diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 9fca40ba4f..fe03c27997 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -blank_issues_enabled: true +blank_issues_enabled: false contact_links: - name: Issue with ABP Commercial url: https://abp.io/support/questions diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml index 5bd0ace63e..db6ca8e1ff 100644 --- a/.github/workflows/auto-pr.yml +++ b/.github/workflows/auto-pr.yml @@ -1,13 +1,13 @@ -name: Merge branch rel-9.3 with rel-9.2 +name: Merge branch dev with rel-9.3 on: push: branches: - - rel-9.2 + - rel-9.3 permissions: contents: read jobs: - merge-rel-9-3-with-rel-9-2: + merge-dev-with-rel-9-3: permissions: contents: write # for peter-evans/create-pull-request to create branch pull-requests: write # for peter-evans/create-pull-request to create a PR @@ -15,17 +15,17 @@ jobs: steps: - uses: actions/checkout@v2 with: - ref: rel-9.3 + ref: dev - name: Reset promotion branch run: | - git fetch origin rel-9.2:rel-9.2 - git reset --hard rel-9.2 + git fetch origin rel-9.3:rel-9.3 + git reset --hard rel-9.3 - name: Create Pull Request uses: peter-evans/create-pull-request@v3 with: - branch: auto-merge/rel-9-2/${{github.run_number}} - title: Merge branch rel-9.3 with rel-9.2 - body: This PR generated automatically to merge rel-9.3 with rel-9.2. Please review the changed files before merging to prevent any errors that may occur. + branch: auto-merge/rel-9-3/${{github.run_number}} + title: Merge branch dev with rel-9.3 + body: This PR generated automatically to merge dev with rel-9.3. Please review the changed files before merging to prevent any errors that may occur. reviewers: maliming draft: true token: ${{ github.token }} @@ -34,5 +34,5 @@ jobs: GH_TOKEN: ${{ secrets.BOT_SECRET }} run: | gh pr ready - gh pr review auto-merge/rel-9-2/${{github.run_number}} --approve - gh pr merge auto-merge/rel-9-2/${{github.run_number}} --merge --auto --delete-branch + gh pr review auto-merge/rel-9-3/${{github.run_number}} --approve + gh pr merge auto-merge/rel-9-3/${{github.run_number}} --merge --auto --delete-branch diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7073e826e3..8ebcc32bfc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -48,7 +48,7 @@ permissions: jobs: build-test: runs-on: ubuntu-22.04 - timeout-minutes: 40 + timeout-minutes: 50 if: ${{ !github.event.pull_request.draft }} steps: - uses: actions/checkout@v2 diff --git a/Directory.Packages.props b/Directory.Packages.props index e74fc60a72..62110b2326 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,10 +18,10 @@ - - - - + + + + @@ -34,6 +34,9 @@ + + + @@ -52,68 +55,68 @@ - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - + + + - + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + @@ -125,11 +128,11 @@ - - - - - + + + + + @@ -138,7 +141,7 @@ - + @@ -160,17 +163,17 @@ - + - + - - - + + + @@ -182,4 +185,4 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index a6199aab9b..fa6632daa8 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The following diagram contains the core components of the **ABP Platform** and s ABP offers a complete architectural model to build modern enterprise software solutions. Here, the fundamental architectural structures offered and first-class supported by ABP: -* [Domain Driven Design](https://abp.io/docs/latest/framework/architecture/domain-driven-design) +* [Domain Driven Design (DDD)](https://abp.io/docs/latest/framework/architecture/domain-driven-design) * [Microservices](https://abp.io/docs/latest/framework/architecture/microservices) * [Modularity](https://abp.io/docs/latest/framework/architecture/modularity/basics) * [Multi-Tenancy](https://abp.io/docs/latest/framework/architecture/multi-tenancy) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 1ea52ff5f5..eebf13731a 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -690,6 +690,37 @@ "Permission:Campaigns": "Campaigns", "Permission:Licenses": "License Settings", "BlockUserPolicy": "User Block Policies", - "Permission:BlockUserPolicy": "User Block Policy" + "Permission:BlockUserPolicy": "User Block Policy", + "ManageImages" : "Manage Image", + "ModuleMainImage": "Module Main Image", + "ModuleImageInfo1": "Accepted file types : JPEG, JPG, PNG, SVG ", + "ModuleImageInfo2": "Max file size : 1 MB ", + "ModuleImageInfo3": "Image Proportion : 1:1 ", + "ModuleImageInfo4": " Download a sample cover image ", + "AreYouSureToDeleteImage": "Are you sure you want to delete this image?", + "CompactPercentage": "Compact Percentage", + "CompactPercentageDescription": "Percentage of cache entries to remove during compaction (1-100)", + "Settings": "Settings", + "MaxSizeOfInMemoryCache": "Max Size Of In Memory Cache", + "MaxSizeOfInMemoryCacheInfo": "Gets or sets the maximum size of the memory cache.", + "SizeOfTriggerAutoCompact": "Size Of Trigger Auto Compact", + "SizeOfTriggerAutoCompactInfo": "Gets or sets the size threshold that triggers auto-compaction. When the cache size exceeds this value, auto-compaction will be performed", + "AutoCompactPercentage": "Auto Compact Percentage", + "AutoCompactPercentageInfo": "Gets or sets the percentage of items to remove when auto-compaction is triggered (1-100)", + "ClearCaches": "This clears all NuGet content cache", + "CacheLatestVersions": "Cache Latest Versions", + "VersionCount": "Version Count", + "VersionCountInfo": "Gets or sets the number of versions to cache", + "IncludeLeptonX": "Include LeptonX", + "IncludeLeptonXInfo": "Gets or sets whether to include LeptonX in the cache", + "IncludePrerelease": "Include Prerelease", + "IncludePrereleaseInfo": "Gets or sets whether to include prerelease versions in the cache", + "CacheVersionCount": "Cache Version Count", + "CacheVersionCountInfo": "Gets or sets the number of versions to cache", + "CacheLatestVersionsInfo": "This caches the latest versions of the NuGet packages", + "NuGetApiKey": "NuGet API key", + "QuestionCount": "Question Count", + "MakeAnnouncement": "Make Announcement", + "MakeAnnouncementInfo": "Check it if you want to make an announcement for this post" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index c56e50af4c..f5fea908de 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -66,7 +66,7 @@ "AuditLogging": "Audit Logging", "Caching": "Caching", "Multitenancy": "Multitenancy", - "DataFiltering": "Data filtering", + "DataFiltering": "Data Filtering", "ConventionOverConfiguration": "Convention Over Configuration", "ConventionOverConfigurationExplanation": "ABP implements common application conventions by default with minimal or zero configuration.", "ConventionOverConfigurationExplanationList1": "Auto registers known services to dependency injection.", @@ -1886,6 +1886,11 @@ "FaqIyzicoPaymentIssuesExplanation5": "Credit/Debit Cards: Visa, MasterCard, American Express, Discover, Diners Club, JCB", "FaqIyzicoPaymentIssuesExplanation6": "Digital Wallets: PayPal, AliPay, WebMoney", "FaqIyzicoPaymentIssuesExplanation7": "Alternatively, you can send the license amount directly via bank wire transfer. For our bank account details, please visit: Bank Account Information (use USD currency).", - "FaqIyzicoPaymentIssuesExplanation8": "ABP website doesn't save or process your credit card. We use payment gateways for this and the entire transaction is handled by payment gateways. We have no authority to interfere with the payment process or fix the payment steps. If you have further questions or need additional support, feel free to contact us at abp.io/contact." + "FaqIyzicoPaymentIssuesExplanation8": "ABP website doesn't save or process your credit card. We use payment gateways for this and the entire transaction is handled by payment gateways. We have no authority to interfere with the payment process or fix the payment steps. If you have further questions or need additional support, feel free to contact us at abp.io/contact.", + "BiographyContainsUrlValidationMessage": "Biography cannot contain URL.", + "CreatePostSEOTitleInfo": "SEO URL is a clean, readable, keyword-rich URL that helps both users and search engines understand what this post is about. Keep it short with 60 characters. SEO titles over 60 characters will be truncated. Use hyphens (-) to separate words (not underscores). Include target keywords near the start. Lowercase only. No stop words unless needed (e.g: \"and\", \"or\", \"the\").", + "SEOTitle": "SEO URL", + "InvalidYouTubeUrl": "The URL you entered is not a valid YouTube video link. Please make sure it points to a specific video and try again.", + "SelectAnOption": "Select an option" } } diff --git a/common.props b/common.props index f02a8f2a28..5a6bddc750 100644 --- a/common.props +++ b/common.props @@ -1,8 +1,8 @@ latest - 9.2.0 - 4.2.0 + 9.3.0-rc.1 + 4.3.0-rc.1 $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ diff --git a/docs/en/Blog-Posts/2022-03-08 v5_2_Preview/POST.md b/docs/en/Blog-Posts/2022-03-08 v5_2_Preview/POST.md index b78e3235a2..b0b44b9e45 100644 --- a/docs/en/Blog-Posts/2022-03-08 v5_2_Preview/POST.md +++ b/docs/en/Blog-Posts/2022-03-08 v5_2_Preview/POST.md @@ -187,7 +187,7 @@ We organized the 3rd live [ABP Community Talks](https://community.abp.io/events) * [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) has also created [an article](https://community.abp.io/posts/using-autofilterer-with-abp-framework-uuqv81jm) to demonstrate how to use his own open source [AutoFilterer](https://github.com/enisn/AutoFilterer) library with the ABP Framework. * [Jonathan Potts](https://github.com/jonathanpotts) has created his first ABP Community article that shows how to use Bootswatch themes with the ABP Framework. [See it here](https://community.abp.io/posts/customizing-the-abp-basic-theme-with-bootswatch-4luoqzr0). -Thanks to all the contributors. It is appreciated if you want to submit your post and share your knowledge with the ABP community: https://community.abp.io/posts/submit +Thanks to all the contributors. It is appreciated if you want to submit your post and share your knowledge with the ABP community: https://community.abp.io/posts/create ## Conclusion diff --git a/docs/en/Blog-Posts/2024-02-16 v8_1_Preview/POST.md b/docs/en/Blog-Posts/2024-02-16 v8_1_Preview/POST.md index 24f55474ad..70cb53c75e 100644 --- a/docs/en/Blog-Posts/2024-02-16 v8_1_Preview/POST.md +++ b/docs/en/Blog-Posts/2024-02-16 v8_1_Preview/POST.md @@ -230,7 +230,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [A Best Practice for Designing Interfaces in .NET C#](https://community.abp.io/posts/a-best-practice-for-designing-interfaces-in-.net-c-9xqc4h8d) * [Invariance, Covariance, and Contravariance in .NET C#](https://community.abp.io/posts/invariance-covariance-and-contravariance-in-.net-c-9blmuhme) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md index 23260950d4..aadaae1c6f 100644 --- a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md +++ b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md @@ -260,7 +260,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [Using FluentValidation with ABP Framework](https://community.abp.io/posts/using-fluentvalidation-with-abp-framework-2cxuwl70) by [Enes Döner](https://community.abp.io/members/Enes) * [Using Blob Storage with ABP](https://community.abp.io/posts/using-blob-storage-with-abp-framework-jygtmhn4) by [Emre Kendirli](https://community.abp.io/members/emrekenderli) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Blog-Posts/2024-07-31 v8_3_Preview/post.md b/docs/en/Blog-Posts/2024-07-31 v8_3_Preview/post.md index 2d8a767568..fc3590b0d5 100644 --- a/docs/en/Blog-Posts/2024-07-31 v8_3_Preview/post.md +++ b/docs/en/Blog-Posts/2024-07-31 v8_3_Preview/post.md @@ -168,7 +168,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [How to use .NET Aspire with ABP framework](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk) by [Berkan Şaşmaz](https://twitter.com/berkansasmazz) * [Exciting New Feature in ABP.IO CMS Kit: Marked Item System](https://abp.io/community/articles/exciting-new-feature-in-abp.io-cms-kit-marked-item-system.-2hvpq0me) by [Suhaib Mousa](https://abp.io/community/members/suhaibmousa032@gmail.com) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Blog-Posts/2024-09-06 v8_3_Release_Stable/POST.md b/docs/en/Blog-Posts/2024-09-06 v8_3_Release_Stable/POST.md index e69fbb86ea..3ac9de075a 100644 --- a/docs/en/Blog-Posts/2024-09-06 v8_3_Release_Stable/POST.md +++ b/docs/en/Blog-Posts/2024-09-06 v8_3_Release_Stable/POST.md @@ -70,7 +70,7 @@ As always, exciting articles have been contributed by the ABP community. I will * [Introducing the Google Cloud Storage BLOB Provider](https://abp.io/community/articles/introducing-the-google-cloud-storage-blob-provider-yrt6azc0) by [Engincan Veske](https://twitter.com/EngincanVeske) * [Switching Between Organization Units](https://abp.io/community/articles/switching-between-organization-units-i5tokpzt) by [Liming Ma](https://github.com/maliming) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## About the Next Version diff --git a/docs/en/Blog-Posts/2024-10-23 v9_0_Preview/POST.md b/docs/en/Blog-Posts/2024-10-23 v9_0_Preview/POST.md index f06648e586..db52eed7d5 100644 --- a/docs/en/Blog-Posts/2024-10-23 v9_0_Preview/POST.md +++ b/docs/en/Blog-Posts/2024-10-23 v9_0_Preview/POST.md @@ -214,7 +214,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [ABP-Powered Web App with Inertia.js, React, and Vite](https://abp.io/community/articles/abppowered-web-app-with-inertia.js-react-and-vite-j7cccvad) by [Anto Subash](https://antosubash.com/) * [Multi-Tenancy Support in Angular Apps with ABP.IO](https://abp.io/community/articles/multitenancy-support-in-angular-apps-with-abp.io-lw9l36c5) by [HeadChannel Team](https://headchannel.co.uk/) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md b/docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md index 26850bc57f..9c96351d96 100644 --- a/docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md +++ b/docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md @@ -78,7 +78,7 @@ In addition to [the articles to highlight .NET 9.0 features written by our team] * [How to create your Own AI Bot on WhatsApp Using an ABP.io Template](https://abp.io/community/articles/how-to-create-your-own-ai-bot-on-whatsapp-using-the-abp-framework-c6jgvt9c) by [Michael Kokula](https://abp.io/community/members/Michal_Kokula) * [ABP Now Supports .NET 9](https://abp.io/community/articles/abp-now-supports-.net-9-zpkznc4f) by [Alper Ebiçoğlu](https://x.com/alperebicoglu) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ### ABP Community Talks 2024.7: What’s New with .NET 9 & ABP 9? diff --git a/docs/en/Blog-Posts/2025-01-21 v9_1_Preview/POST.md b/docs/en/Blog-Posts/2025-01-21 v9_1_Preview/POST.md index bb8bfdf4c7..bbcc69c727 100644 --- a/docs/en/Blog-Posts/2025-01-21 v9_1_Preview/POST.md +++ b/docs/en/Blog-Posts/2025-01-21 v9_1_Preview/POST.md @@ -138,7 +138,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [The new Unit Test structure in ABP application](https://abp.io/community/articles/the-new-unit-test-structure-in-abp-application-4vvvp2oy) by [Liming Ma](https://github.com/maliming) * [How to Use OpenAI API with ABP Framework](https://abp.io/community/articles/how-to-use-openai-api-with-abp-framework-rsfvihla) by [Berkan Şaşmaz](https://github.com/berkansasmaz) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Blog-Posts/2025-03-07 v9_1_Release_Stable/POST.md b/docs/en/Blog-Posts/2025-03-07 v9_1_Release_Stable/POST.md index 96096807f1..2e6764e9b7 100644 --- a/docs/en/Blog-Posts/2025-03-07 v9_1_Release_Stable/POST.md +++ b/docs/en/Blog-Posts/2025-03-07 v9_1_Release_Stable/POST.md @@ -67,7 +67,7 @@ As always, exciting articles have been contributed by the ABP community. I will * [Containerization: Blazor WASM + JWT Web API => Docker](https://abp.io/community/articles/containerization-blazor-wasm-jwt-web-api-docker-i3eirlsf) by [Bart Van Hoey](https://abp.io/community/members/bartvanhoey) * [Configuring Post-Logout Redirect URI in ABP Based Blazor Applications with OpenIddict](https://abp.io/community/articles/configuring-postlogout-redirect-uri-in-abp-based-blazor-applications-with-openiddict-1t84suxg) by [Engincan Veske](https://github.com/EngincanV) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ### ABP Community Talks 2025.2: Real World Problems and Solutions with AI diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md new file mode 100644 index 0000000000..e59e75f44a --- /dev/null +++ b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/POST.md @@ -0,0 +1,195 @@ +# ABP Platform 9.2 RC Has Been Released + +We are happy to release [ABP](https://abp.io) version **9.2 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version. + +Try this version and provide feedback for a more stable version of ABP v9.2! Thanks to you in advance. + +## Get Started with the 9.2 RC + +You can check the [Get Started page](https://abp.io/get-started) to see how to get started with ABP. You can either download [ABP Studio](https://abp.io/get-started#abp-studio-tab) (**recommended**, if you prefer a user-friendly GUI application - desktop application) or use the [ABP CLI](https://abp.io/docs/latest/cli). + +By default, ABP Studio uses stable versions to create solutions. Therefore, if you want to create a solution with a preview version, first you need to create a solution and then switch your solution to the preview version from the ABP Studio UI: + +![studio-switch-to-preview.png](studio-switch-to-preview.png) + +## Migration Guide + +There are a few breaking changes in this version that may affect your application. Please read the migration guide carefully, if you are upgrading from v9.x or earlier: [ABP Version 9.2 Migration Guide](https://abp.io/docs/9.2/release-info/migration-guides/abp-9-2) + +## What's New with ABP v9.2? + +In this section, I will introduce some major features released in this version. +Here is a brief list of titles explained in the next sections: + +* Added `ApplicationName` Property to Isolate Background Jobs & Background Workers +* Docs Module: Added "Alternative Words" to Filter Items +* Introducing the Bunny BLOB Storage Provider +* Upgraded `MongoDB.Driver` to v3.1.0 +* Using Timezone Settings to Display Datetime +* Identity Pro Module: Require Email Verification to Register +* Switching users during OAuth login + +### Added ApplicationName Property to Isolate Background Jobs & Background Workers + +ABP's [Background Jobs Module](https://abp.io/docs/latest/modules/background-jobs) has been enhanced with a new `ApplicationName` property that helps isolate jobs and workers across multiple applications sharing the same database. + +Previously, when different applications used the BackgroundJobs module and shared a database, an application might encounter jobs that didn't belong to it. This would lead to failed processing attempts and marking jobs as `IsAbandoned = true` with a "Undefined background job for the job name" error, preventing these jobs from ever being executed. + +With the new `ApplicationName` property, applications now properly filter jobs at the repository level, ensuring each application only processes job types it recognizes. This prevents the incorrect abandonment of jobs and ensures consistent behavior in multi-application scenarios. + +You can set `ApplicationName` of `AbpBackgroundJobWorkerOptions` to your application name to isolate jobs and workers across multiple applications sharing the same database: + +```csharp +public override void PreConfigureServices(ServiceConfigurationContext context) +{ + PreConfigure(options => + { + options.ApplicationName = context.Services.GetApplicationName()!; + }); +} +``` + +> For more information, please refer to the [Background Jobs Module](https://abp.io/docs/latest/modules/background-jobs) documentation and the [PR](https://github.com/abpframework/abp/pull/22169) that added this feature. + +### Docs Module: Added "Alternative Words" to Filter Items + +[ABP's Docs Module](https://abp.io/docs/9.2/modules/docs) now supports "alternative words" to enhance the search functionality when filtering documentation items. This feature addresses a common user experience issue where users might search using terminology different from what appears in the documentation. + +For example, when a user searches for "Error" in the documentation, they may actually be looking for content related to "Exception Handling." With this new feature, documentation items can now be configured with alternative keywords that are considered during filtering. + +The implementation allows defining optional "keywords" for items in the navigation tree. For example: + +```json +{ + "text": "Exception Handling", + "path": "framework/fundamentals/exception-handling.md", + "keywords": ["Error", "Another Value"] +} +``` + +When users search or filter content, the system now considers both the original text and these alternative keywords, improving discoverability of relevant documentation sections. This enhancement makes the documentation more accessible and user-friendly, especially for newcomers who might not be familiar with the exact terminology used in the ABP documentation. + +### Introducing the Bunny BLOB Storage Provider + +ABP v9.2 RC introduces a new BLOB storage provider for [Bunny Storage](https://bunny.net/storage/), a global edge storage solution. This addition expands ABP's BLOB Storage options beyond the existing providers like Azure, AWS, and others. + +The [Bunny BLOB Storage Provider](https://abp.io/docs/9.2/framework/infrastructure/blob-storing/bunny) allows ABP applications to seamlessly integrate with Bunny's CDN-backed storage service, which offers high-performance content delivery through its global network. + +To use this new provider, you'll need to: + +* Run `abp add-package Volo.Abp.BlobStoring.Bunny` command. +* And then configure the provider in your module's `ConfigureServices` method: + +```csharp +Configure(options => +{ + options.Containers.ConfigureDefault(container => + { + container.UseBunny(bunny => + { + bunny.StorageZoneName = "your-storage-zone"; + bunny.ApiKey = "your-api-key"; + bunny.Region = "your-region"; // de, ny, la, sg, or sy + }); + }); +}); +``` + +This integration provides ABP applications with an efficient and globally distributed storage solution, particularly beneficial for applications requiring fast content delivery across different geographical regions. To use this new provider and make the related configurations, you can refer to the [Bunny Storage Provider](https://abp.io/docs/9.2/framework/infrastructure/blob-storing/bunny) documentation always. + +> This new BLOB Storage provider is contributed by [@suhaib-mousa](https://github.com/suhaib-mousa). Thanks to him for his contribution! +> We are always happy to see the community contributing to the ABP Framework and encouraging them to contribute more. + +### Upgraded `MongoDB.Driver` to `v3.1.0` + +ABP v9.2 RC includes an upgrade to `MongoDB.Driver` version `3.1.0`. This significant version bump from previous releases brings several improvements and new features that benefit ABP applications using MongoDB as their database. + +The upgrade provides: + +* Async/Await Support: Write non-blocking, asynchronous code easily. +* Fluent API: Build queries and updates intuitively with Builders. +* LINQ Support: Use LINQ for querying MongoDB collections. +* and more ... + +> For more information, please refer to the [MongoDB.Driver release notes](https://github.com/mongodb/mongo-csharp-driver/releases/tag/v3.1.0). + +We have prepared a [migration guide](https://abp.io/docs/9.2/release-info/migration-guides/MongoDB-Driver-2-to-3) for this upgrade. Please refer to it to learn more about the changes and how to migrate your application. + +### Using Timezone Settings to Display Datetime + +A significant enhancement in ABP v9.2 is the ability to use timezone settings to display `DateTime` values according to the user's or application's configured timezone. Introduced in `v9.2.0-rc.2`, this feature addresses the common challenge of ensuring users see accurate time information, regardless of their geographical location. + +Previously, `DateTime` values were often shown in the server's timezone or in UTC, which could cause confusion for users in different timezones. With this new feature, ABP applications can now respect the configured timezone and automatically convert and display datetime values accordingly. + +**Before setting the timezone:** + +Consider a scenario where you have a list of books, and the `CreationTime` property is displayed without any timezone consideration. It may appear in the server's default timezone: + +![before.png](before.png) +*(Screenshot of a Books page showing the CreationTime in a default timezone.)* + +**Setting the timezone:** + +To set the timezone, start by configuring the `AbpClockOptions` in your module's `ConfigureServices` method: + +```csharp +Configure(options => +{ + options.Kind = DateTimeKind.Utc; +}); +``` + +> By setting the `Kind` property of `AbpClockOptions` to `DateTimeKind.Utc`, ABP will normalize all datetime values. Times stored in the database and returned to the frontend will be in UTC. Additionally, the `SupportsMultipleTimezone` property of the `IClock` service will be **true**, and you’ll be able to configure the timezone from the UI under the _Settings_ page. + +After setting the `Kind` property, you can run your application and configure the timezone from the UI under the _Settings_ page. For example, set the timezone to "Asia/Tokyo (+09:00)": + +![configure-timezone.png](configure-timezone.png) +*(Screenshot showing the configuration setting for Abp.Timing.TimeZone, set to "Asia/Tokyo (+09:00)".)* + +> ABP provides the `Abp.Timing.TimeZone` setting, which allows you to configure the desired timezone at the application, tenant, or user level and this setting can be configured in the UI under the _Settings_ page, inside of the _Time Zone_ tab. + +**After setting the timezone:** + +Once the timezone is configured, ABP automatically handles the conversion and display of `DateTime` values. The `CreationTime` on the _Books_ page will now be shown in the **"Asia/Tokyo"** timezone. + +![after.png](after.png) +*(Screenshot of the _Books_ page after setting the timezone, showing the `CreationTime` adjusted to the "Asia/Tokyo" timezone.)* + +This feature utilizes the `IClock` service, which provides methods like `ConvertToUserTime` and `ConvertToUtc` to facilitate timezone conversions. By configuring the `Abp.Timing.TimeZone` setting, developers can ensure a consistent and user-friendly experience across applications with a global user base. +> For a more detailed guide on implementing and using this feature, refer to the article: [Developing a Multi-Timezone Application Using the ABP Framework](https://abp.io/community/articles/developing-a-multitimezone-application-using-the-abp-framework-zk7fnrdq). It offers step-by-step instructions and examples for handling multi-timezone scenarios in ABP applications. + +### Identity Pro Module: Require Email Verification to Register + +[ABP Identity Pro module](https://abp.io/docs/9.2/modules/identity-pro) has been enhanced with a new feature that allows administrators to require email verification during the registration process. This security improvement ensures that users must verify their email addresses before their registration is considered complete. Enabling this feature is especially important for applications that want to prevent spam registrations. + +Administrators can enable or disable this feature through the **Identity management -> Identity Verification (tab)** settings page (by checking the `Enforce email verification to register` checkbox): + +![require-email-verification.png](./require-email-verification-for-register.png) + +### Switching users during OAuth login + +If you have an OAuth/Auth Server application using the [ABP Account Pro module](https://abp.io/docs/9.2/modules/account-pro) , you can pass the `prompt=select_account` parameter to force the user to select an account. + +![select-account.png](./select-account.png) + +For more information, please refer to the [Switching users during OAuth login](https://abp.io/docs/9.2/modules/account-pro#switching-users-during-oauth-login) documentation. + +### New ABP Community Articles + +There are exciting articles contributed by the ABP community as always. I will highlight some of them here: + +* [Implementing CQRS with MediatR in ABP](https://abp.io/community/articles/implementing-cqrs-with-mediatr-in-abp-xiqz2iio) by [Engincan Veske](https://github.com/EngincanV) +* [Using Vue Components in a Razor Pages ABP Application](https://abp.io/community/articles/using-vue-components-in-a-razor-pages-abp-application-z3jr07tv) by [Enis Necipoglu](https://github.com/enisn) +* [Using ABP's AWS Blob Storing Provider with DigitalOcean Spaces](https://abp.io/community/articles/using-abps-aws-blob-storing-provider-with-digitalocean-spaces-7hlyb25g) by [Suhaib Mousa](https://abp.io/community/members/suhaib-mousa) +* [Video Post: Using Vue Components in a Razor Pages ABP Application](https://abp.io/community/articles/using-vue-components-in-a-razor-pages-abp-application-z3jr07tv) by [Enis Necipoglu](https://github.com/enisn) +* [Understanding the Embedded Files in ABP Framework](https://abp.io/community/articles/understanding-the-embedded-files-in-abp-framework-nsrp8aa9) by [Liming Ma](https://github.com/maliming) +* [How to Change the CurrentUser in ABP?](https://abp.io/community/articles/how-to-change-the-currentuser-in-abp-i3uu1m7g) by [Engincan Veske](https://github.com/EngincanV) + + +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. + +## Conclusion + +This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://abp.io/docs/9.2/release-info/road-map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v9.2 RC and provide feedback to help us release a more stable version. + +Thanks for being a part of this community! diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/after.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/after.png new file mode 100644 index 0000000000..f9f72302a5 Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/after.png differ diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/before.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/before.png new file mode 100644 index 0000000000..14340f91ee Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/before.png differ diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/configure-timezone.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/configure-timezone.png new file mode 100644 index 0000000000..d383eee6f6 Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/configure-timezone.png differ diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/cover-image.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/cover-image.png new file mode 100644 index 0000000000..dd40555c8e Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/cover-image.png differ diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/require-email-verification-for-register.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/require-email-verification-for-register.png new file mode 100644 index 0000000000..597eaa6118 Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/require-email-verification-for-register.png differ diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/select-account.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/select-account.png new file mode 100644 index 0000000000..39d8c1b421 Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/select-account.png differ diff --git a/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/studio-switch-to-preview.png b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/studio-switch-to-preview.png new file mode 100644 index 0000000000..32f6d01edb Binary files /dev/null and b/docs/en/Blog-Posts/2025-03-27 v9_2_Preview/studio-switch-to-preview.png differ diff --git a/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/POST.md b/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/POST.md new file mode 100644 index 0000000000..1062195bda --- /dev/null +++ b/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/POST.md @@ -0,0 +1,86 @@ +# ABP.IO Platform 9.2 Final Has Been Released! + +We are glad to announce that [ABP](https://abp.io/) 9.2 stable version has been released today. + +## What's New With Version 9.2? + +All the new features were explained in detail in the [9.2 RC Announcement Post](https://abp.io/community/articles/abp-platform-9.2-rc-has-been-released-jpq072nh), so there is no need to review them again. You can check it out for more details. + +## Getting Started with 9.2 + +### Creating New Solutions + +You can check the [Get Started page](https://abp.io/get-started) to see how to get started with ABP. You can either download [ABP Studio](https://abp.io/get-started#abp-studio-tab) (**recommended**, if you prefer a user-friendly GUI application - desktop application) or use the [ABP CLI](https://abp.io/docs/latest/cli) to create new solutions. + +### How to Upgrade an Existing Solution + +You can upgrade your existing solutions with either ABP Studio or ABP CLI. In the following sections, both approaches are explained: + +### Upgrading via ABP Studio + +If you are already using the ABP Studio, you can upgrade it to the latest version. ABP Studio periodically checks for updates in the background, and when a new version of ABP Studio is available, you will be notified through a modal. Then, you can update it by confirming the opened modal. See [the documentation](https://abp.io/docs/latest/studio/installation#upgrading) for more info. + +After upgrading the ABP Studio, then you can open your solution in the application, and simply click the **Upgrade ABP Packages** action button to instantly upgrade your solution: + +![](upgrade-abp-packages.png) + +### Upgrading via ABP CLI + +Alternatively, you can upgrade your existing solution via ABP CLI. First, you need to install the ABP CLI or upgrade it to the latest version. + +If you haven't installed it yet, you can run the following command: + +```bash +dotnet tool install -g Volo.Abp.Studio.Cli +``` + +Or to update the existing CLI, you can run the following command: + +```bash +dotnet tool update -g Volo.Abp.Studio.Cli +``` + +After installing/updating the ABP CLI, you can use the [`update` command](https://abp.io/docs/latest/CLI#update) to update all the ABP related NuGet and NPM packages in your solution as follows: + +```bash +abp update +``` + +You can run this command in the root folder of your solution to update all ABP related packages. + +## Migration Guides + +There are a few breaking changes in this version that may affect your application. Please read the migration guide carefully, if you are upgrading from v9.x: [ABP Version 9.2 Migration Guide](https://abp.io/docs/9.2/release-info/migration-guides/abp-9-2) + +## Community News + +### New ABP Community Articles + +As always, exciting articles have been contributed by the ABP community. I will highlight some of them here: + +* [Liming Ma](https://github.com/maliming) has published 3 new articles: + * [Integrating .NET AI Chat Template with ABP Framework](https://abp.io/community/articles/integrating-.net-ai-chat-template-with-abp-framework-qavb5p2j) + * [Resolving Tenant from Route in ABP Framework](https://abp.io/community/articles/resolving-tenant-from-route-in-abp-framework-ah7oru97) + * [Common Errors in JWT Bearer Authentication](https://abp.io/community/articles/common-errors-in-jwt-bearer-authentication-4u3wrbs5) +* [Engincan Veske](https://engincanveske.substack.com/) has published 3 new articles: + * [Understanding HttpApi.Client Project & Remote Services in an ABP Based Application](https://abp.io/community/articles/http-api-client-and-remote-services-in-abp-based-application-xkknsp6m) + * [Using Elsa 3 with the ABP Framework: A Comprehensive Guide](https://abp.io/community/articles/using-elsa-3-workflow-with-abp-framework-usqk8afg) + * [Implementing Custom Tenant Logo Feature in ABP Framework: A Step-by-Step Guide](https://abp.io/community/articles/implementing-custom-tenant-logo-feature-in-abp-framework-a-stepbystep-guide-sba96ac9) +* [Berkan Şaşmaz](https://berkansasmaz.com/) has published 2 new articles: + * [Understanding the Domain and Application Layers in ABP Framework](https://abp.io/community/articles/understanding-the-domain-and-application-layers-in-abp-1fipc4x4) + * [How Do We Maintain Code Quality and Technical Debt in Our .NET Codebase?](https://abp.io/community/articles/how-do-we-maintain-code-quality-and-technical-debt-in-our-.net-codebase-z7glpya1) +* [Enis Necipoğlu](https://github.com/enisn) has published 2 new articles: + * [White Labeling in ABP Framework](https://abp.io/community/articles/white-labeling-in-abp-framework-5trwmrfm) by [Enis Necipoğlu](https://github.com/enisn) + * [You do it wrong! Customizing ABP Login Page Correctly](https://abp.io/community/articles/you-do-it-wrong-customizing-abp-login-page-correctly-bna7wzt5) +* [Ariful Islam](https://abp.io/community/members/arif) has published 2 new articles: + * [Multi-Workspace Management for ABP Applications](https://abp.io/community/articles/multiworkspace-management-for-abp-applications-eghgty3j) + * [Using Semantic Kernel in the ABP Framework](https://abp.io/community/articles/using-semantic-kernel-in-the-abp-framework-qo5cnuzs) +* [Guide to Add Custom Modules in ABP.IO App](https://abp.io/community/articles/guide-to-add-custom-modules-in-abp.io-app-sttetffa) by [Harsh Gupta](https://abp.io/community/members/harshgupta) +* [Debugging NuGet Packages in ABP.IO: A Complete Guide](https://abp.io/community/articles/debugging-nuget-packages-in-abp.io-a-complete-guide-h13y2033) by [Suhaib Mousa](https://suhaibmousa.com/) +* [Using Microsoft AI Extensions Library and OpenAI to Summarize User Comments](https://abp.io/community/articles/using-microsoft-ai-extensions-library-and-openai-to-summarize-user-comments-gj1lusg7) by [Halil Ibrahim Kalkan](https://twitter.com/hibrahimkalkan) + +Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. + +## About the Next Version + +The next feature version will be 9.3. You can follow the [release planning here](https://github.com/abpframework/abp/milestones). Please [submit an issue](https://github.com/abpframework/abp/issues/new) if you have any problems with this version. diff --git a/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/cover-image.png b/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/cover-image.png new file mode 100644 index 0000000000..dd40555c8e Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/cover-image.png differ diff --git a/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/upgrade-abp-packages.png b/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/upgrade-abp-packages.png new file mode 100644 index 0000000000..ad5e9bd462 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-02 v9_2_Release_Stable/upgrade-abp-packages.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/POST.md b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/POST.md new file mode 100644 index 0000000000..8b37325e7e --- /dev/null +++ b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/POST.md @@ -0,0 +1,97 @@ +# Announcing ABP Studio 1.0 General Availability 🚀 + +It's the moment you've been waiting for! We are thrilled to announce the stable release of ABP Studio v1.0. This milestone marks a significant step forward in our mission to provide a first-class, integrated development environment for ABP developers. Paired with the recently released [ABP v9.2](https://abp.io/community/articles/announcing-abp-9-2-stable-release-061qmtzb), ABP Studio v1.0 brings new features and improvements that will make your development work faster and more efficient. + +For the past several months, our core ABP team has been hard at work, focusing on the features that matter most to you, our community of developers. This release is the peak of that effort, bringing a host of improvements and new capabilities to the forefront. Let's dive in and explore what's new in ABP Studio v1.0. + +## What's New with ABP Studio v1.0? + +ABP Studio v1.0 is all about enhancing your development experience, from project creation to deployment. Here, we'll walk you through some of the latest features we've implemented, along with other key enhancements that make this release truly special. + +### ❤️ Solution Runner with Ready/Health Checks + +ABP Studio's Solution Runner now provides visual health monitoring that makes tracking your applications' status easily. When you start an application, a spinner indicates it's "starting", then in the *Overall* tab, you can see the application's health (✅ for healthy, ⚠️ for unhealthy) that displays real-time health status: + +![Health Checks](health-checks.png) + +With [pre-configured health checks](https://abp.io/docs/9.2/solution-templates/layered-web-application/health-check-configuration) in ABP solution templates including database connectivity tests, you get instant feedback on your applications' health. + +When health check UI is configured, you can access comprehensive health dashboards with a dedicated "Browse Health UI" command or see the last health response from the "Show Latest Health Check Response" command: + +![SaaS Health Check](saas-health-check.png) + +When you restart applications that are open in your browser, ABP Studio automatically refreshes the pages for you. + +### 🎨 Theme Style Selection on Project Creation + +When creating a new solution, you can now choose your theme, theme style, and layout right from the project creation wizard instead of having to configure these settings later. ABP Studio lets you pick from [ABP's officially provided themes including Basic, LeptonX Lite, and LeptonX](https://abp.io/docs/latest/ui-themes). + +![Theme Style Selection LeptonX](theme-style-selection-leptonx.png) + +If you select Basic or LeptonX Lite themes, only the theme will be changed. However, if you select the LeptonX theme, you'll get additional options to fine-tune your setup: + +- **Theme Style Configuration** - Pick from **System, Light, Dim, or Dark** styles to match how you like your development environment +- **Layout Options** - **Sidebar menu** / **Top menu** + +### 📦 "Container" Application Type for Solution Runner + +ABP Studio v1.0 introduces a dedicated "Container" application type that gives you better control over your Docker containers directly from the Solution Runner. Instead of managing all your containers through PowerShell scripts or running them all together, you can now see and control each container individually in the Solution Runner panel. + +![Container Application Type](containers-type.png) + +This new feature replaces the previous _Infrastructure_ folder approach with a cleaner, more intuitive container section. You can now: + +- **Start and stop containers individually** - No more starting all containers at once when you only need specific services +- **Monitor container status** - See which containers are running, stopped, or have issues directly in the UI +- **Manage container dependencies** - Control the order and timing of container startup based on your application needs + +Whether you're working with databases, message brokers, or other containerized services, the new Container application type makes it much easier to manage your development environment. This is especially useful for microservice architectures where you might want to run only specific services during development or testing. + +### ⚙️ Handle Multiple DbContexts When Adding/Removing/Applying Migrations + +When working with ABP solutions that have multiple DbContexts (such as when using the separate tenant database option), ABP Studio now intelligently prompts you to select the appropriate DbContext for migration operations. This enhancement ensures you're always working with the correct database context and helps prevent common mistakes when managing multiple databases. + +![EF Core Migration Context Selection](new-migration-added.gif) + +The context selection dialog appears automatically when you perform any of these Entity Framework operations: + +- **Adding a new migration** - Choose which DbContext the new migration should target +- **Removing an existing migration** - Select the DbContext from which to remove the migration +- **Updating the database** - Specify which database context should be updated + +## Get Started with ABP Studio v1.0 Today! + +ABP Studio v1.0 is built on the solid foundation of the [latest version of ABP Framework, which is v9.2](https://abp.io/community/articles/announcing-abp-9-2-stable-release-061qmtzb). This means that when you create a new project with ABP Studio, you're getting all the latest features, performance improvements, and bug fixes that come with v9.2. This includes updates to dependencies, enhancements to the core framework, and improvements to application modules. + +We are incredibly excited for you to get your hands on ABP Studio v1.0. We believe these new features will make a real difference in your day-to-day development workflow. + +### ⬇️ Download ABP Studio 1.0 + +Ready to get started? You can download the stable v1.0 release right now from the official ABP Studio website: **[https://abp.io/studio](https://abp.io/studio)** + +![ABP Studio 1.0 Download](abp-studio-download.png) + +If you are an existing ABP Studio user, it's even easier. You don't need to download the installer again. Simply launch ABP Studio, and it will prompt you to update to the latest version directly from the UI. + +> Alternatively, you can click to the *Help -> Check for Updates* context menu item to check for updates and install the latest version: +> +> ![ABP Studio 1.0 Check for Updates](abp-studio-check-for-updates.png) + +### 🔮 What's Next? + +ABP Studio v1.0 represents just the beginning of our journey. We're committed to continuously evolving the platform, adding features that directly address real-world development challenges and enhance your workflow. Our goal is to make ABP Studio the go-to development environment for .NET and ABP Framework developers. + +We will keep releasing new versions with exciting features based on our roadmap and your valuable feedback. To give you a sneak peek into what's planned for future releases, you can expect to see: + +- **Environment Variable Management:** A dedicated UI to easily manage environment variables for your solutions. +- **OpenTelemetry Integration:** We'll be integrating OpenTelemetry support directly into the startup templates, making distributed tracing and observability a seamless part of your application from day one. +- **LeptonX Theme Builder**: Allowing users to determine styling, colour palette and easily override their project's theme styles. +- **Monitor dashboards of the tools used in the solution (e.g. Kubernetes, Redis, Grafana, etc...)** +- **Pre-configured .NET Aspire for the Microservice Startup Template** +- **and more...** + +We are incredibly excited about the future of ABP Studio and can't wait to share the next set of features with you. Your comments and suggestions are invaluable to us. If you have any feedback, please drop a comment below. + +Thank you for being part of our community and happy coding! + +**The Volosoft Team** diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/abp-studio-check-for-updates.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/abp-studio-check-for-updates.png new file mode 100644 index 0000000000..bf7f2dc889 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/abp-studio-check-for-updates.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/abp-studio-download.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/abp-studio-download.png new file mode 100644 index 0000000000..453a9ce3f8 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/abp-studio-download.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/containers-type.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/containers-type.png new file mode 100644 index 0000000000..66bfe4a12c Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/containers-type.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/cover-image.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/cover-image.png new file mode 100644 index 0000000000..76b24a8573 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/cover-image.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/health-checks.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/health-checks.png new file mode 100644 index 0000000000..6de5deeacf Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/health-checks.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/new-migration-added.gif b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/new-migration-added.gif new file mode 100644 index 0000000000..b8149e8a41 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/new-migration-added.gif differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/saas-health-check.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/saas-health-check.png new file mode 100644 index 0000000000..547e518751 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/saas-health-check.png differ diff --git a/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/theme-style-selection-leptonx.png b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/theme-style-selection-leptonx.png new file mode 100644 index 0000000000..8f5f143a11 Binary files /dev/null and b/docs/en/Blog-Posts/2025-06-10-Announcing-ABP-Studio-1.0-Stable-Release/theme-style-selection-leptonx.png differ diff --git a/docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/POST.md b/docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/POST.md index 03caff8007..98685933ba 100644 --- a/docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/POST.md +++ b/docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/POST.md @@ -470,6 +470,12 @@ namespace TemplateReplace * I highly recommend you to [check it out](https://commercial.abp.io/modules/Volo.TextTemplateManagement). +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## References * [Text Templating](https://docs.abp.io/en/abp/latest/Text-Templating) diff --git a/docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md b/docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md index 6445d83e85..f946db23b9 100644 --- a/docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md +++ b/docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md @@ -4,6 +4,12 @@ Hi, in this step by step article, we will see how we can integrate the Telerik Blazor Components to our Blazor UI. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Creating the Solution > ABP Framework offers startup templates to get into business faster. @@ -532,6 +538,12 @@ namespace TelerikComponents.Blazor.Pages ![final-result](./final-result.jpg) +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion In this article, I've tried to explain how we can integrate [Telerik Blazor Component](https://www.telerik.com/blazor-ui) to our Blazor UI. ABP Framework designed as modular, so that it can work with any UI library/framework. \ No newline at end of file diff --git a/docs/en/Community-Articles/2021-06-17-Using-Elsa-Workflow-with-ABP-Framework/POST.md b/docs/en/Community-Articles/2021-06-17-Using-Elsa-Workflow-with-ABP-Framework/POST.md index 0ec86d40c4..2f5cde6d2d 100644 --- a/docs/en/Community-Articles/2021-06-17-Using-Elsa-Workflow-with-ABP-Framework/POST.md +++ b/docs/en/Community-Articles/2021-06-17-Using-Elsa-Workflow-with-ABP-Framework/POST.md @@ -1,11 +1,19 @@ # Using Elsa Workflow with ABP Framework +> **UPDATE:** There is a newer version of this article, which covers Elsa 3 with ABP Framework. You can check it at https://abp.io/community/articles/using-elsa-3-workflow-with-abp-framework-usqk8afg + **Elsa Core** is an open-source workflows library that can be used in any kind of .NET Core application. Using such a workflow library can be useful to implement business rules visually or programmatically. ![elsa-overview](./elsa-overview.gif) This article shows how we can use this workflow library within our ABP-based application. We will start with a couple of examples and then we will integrate the **Elsa Dashboard** (you can see it in the above gif) into our application to be able to design our workflows visually. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Source Code You can find the source of the example solution used in this article [here](https://github.com/abpframework/abp-samples/tree/master/ElsaDemo). @@ -453,4 +461,10 @@ namespace ElsaDemo.Web.Menus * Now we can click the "Workflow" menu item, display the Elsa Dashboard and designing workflows. -![elsa-demo-result](./elsa-demo-result.gif) \ No newline at end of file +![elsa-demo-result](./elsa-demo-result.gif) + +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- diff --git a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md index ae688d6981..81c0b6ea34 100644 --- a/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md +++ b/docs/en/Community-Articles/2021-10-31-Many-to-Many-Relationship-with-ABP-and-EF-Core/POST.md @@ -10,6 +10,12 @@ You can see the ER Diagram of our application below. This diagram will be helpfu When we've examined the ER Diagram, we can see the one-to-many relationship between the **Author** and the **Book** tables. Also, the many-to-many relationship (**BookCategory** table) between the **Book** and the **Category** tables. (There can be more than one category on each book and vice-versa in our scenario). +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ### Source Code You can find the source code of the application at https://github.com/EngincanV/ABP-Many-to-Many-Relationship-Demo . @@ -1664,6 +1670,12 @@ namespace BookStore.Web.Pages.Books ![Edit Book Modal](./book-update-modal.png) +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ### Conclusion In this article, I've tried to explain how to create a many-to-many relationship by using the ABP framework. (by following DDD principles) diff --git a/docs/en/Community-Articles/2021-12-13-Integrating-the-Syncfusion-MVC-Components-to-the-ABP-MVC-UI/POST.md b/docs/en/Community-Articles/2021-12-13-Integrating-the-Syncfusion-MVC-Components-to-the-ABP-MVC-UI/POST.md index 4095c62092..2953c552d3 100644 --- a/docs/en/Community-Articles/2021-12-13-Integrating-the-Syncfusion-MVC-Components-to-the-ABP-MVC-UI/POST.md +++ b/docs/en/Community-Articles/2021-12-13-Integrating-the-Syncfusion-MVC-Components-to-the-ABP-MVC-UI/POST.md @@ -4,6 +4,12 @@ In this article we will see how we can integrate the Syncfusion MVC Components into our ABP application. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Source Code You can find the source code of the application at https://github.com/EngincanV/ABP-Syncfusion-Components-Demo. @@ -314,6 +320,12 @@ After injecting the Syncfusion style and script into our application, our config ![](./calendar-component.png) +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ### Conclusion In this article, we've explained how to integrate the **Syncfusion Components** into our applications. After following this article, you can use the Syncfusion components in your application. diff --git a/docs/en/Community-Articles/2022-02-06-How-to-Hide-ABP-Related-Endpoints-on-Swagger-UI/POST.md b/docs/en/Community-Articles/2022-02-06-How-to-Hide-ABP-Related-Endpoints-on-Swagger-UI/POST.md index a6ad7596d4..d4102d8256 100644 --- a/docs/en/Community-Articles/2022-02-06-How-to-Hide-ABP-Related-Endpoints-on-Swagger-UI/POST.md +++ b/docs/en/Community-Articles/2022-02-06-How-to-Hide-ABP-Related-Endpoints-on-Swagger-UI/POST.md @@ -8,6 +8,12 @@ In the issue, there are helpful comments about hiding the ABP related endpoints I thought it would be better to enable/disable showing endpoints on runtime by simply selecting a checkbox on the Setting Management page and in this article I wanted to show you how, so let's dive in. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Source Code You can find the source code of the application at https://github.com/EngincanV/ABP-Hide-Swagger-Endpoint-Demo. @@ -445,6 +451,10 @@ services.AddAbpSwaggerGen( > For more info, please see the [Swagger Integration](https://docs.abp.io/en/abp/latest/API/Swagger-Integration#hide-abp-endpoints-on-swagger-ui) docs. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv --- Thanks for reading. \ No newline at end of file diff --git a/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/post.md b/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/post.md index be89ccb092..e43ba9a529 100644 --- a/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/post.md +++ b/docs/en/Community-Articles/2022-03-09-abpio-platform-52-rc-has-been-published/post.md @@ -186,7 +186,7 @@ We organized the 3rd live [ABP Community Talks](https://community.abp.io/events) * [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) has also created [an article](https://community.abp.io/posts/using-autofilterer-with-abp-framework-uuqv81jm) to demonstrate how to use his own open source [AutoFilterer](https://github.com/enisn/AutoFilterer) library with the ABP Framework. * [Jonathan Potts](https://github.com/jonathanpotts) has created his first ABP Community article that shows how to use Bootswatch themes with the ABP Framework. [See it here](https://community.abp.io/posts/customizing-the-abp-basic-theme-with-bootswatch-4luoqzr0). -Thanks to all the contributors. It is appreciated if you want to submit your post and share your knowledge with the ABP community: https://community.abp.io/posts/submit +Thanks to all the contributors. It is appreciated if you want to submit your post and share your knowledge with the ABP community: https://community.abp.io/posts/create ## Conclusion diff --git a/docs/en/Community-Articles/2022-04-06-Concurrency-Check-in-ABP-Based-Applications/POST.md b/docs/en/Community-Articles/2022-04-06-Concurrency-Check-in-ABP-Based-Applications/POST.md index b16d6bd9f1..cf8c3c122a 100644 --- a/docs/en/Community-Articles/2022-04-06-Concurrency-Check-in-ABP-Based-Applications/POST.md +++ b/docs/en/Community-Articles/2022-04-06-Concurrency-Check-in-ABP-Based-Applications/POST.md @@ -2,6 +2,12 @@ In this article, we'll create a basic application to demonstrate how "Concurrency Check/Control" can be implemented in an ABP project. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Creating the Solution For this article, we will create a simple BookStore application and add CRUD functionality to the pages. Hence we deal with the concurrency situation. @@ -546,3 +552,9 @@ Then we can run the application, navigate to the **/Books** endpoint and see the * After the first user updated the record, the second user tries to update the same record without getting the last state of the record. And therefore `AbpDbConcurrencyException` is thrown because **ConcurrencyStamp** values are different from each other. * The second user should close and re-open the model to get the last state of the record and then they can make changes to the current record. + +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- \ No newline at end of file diff --git a/docs/en/Community-Articles/2022-11-22-gRPC-JSON-Transcoding/POST.md b/docs/en/Community-Articles/2022-11-22-gRPC-JSON-Transcoding/POST.md index 9663ac1f83..e0f1f38aa9 100644 --- a/docs/en/Community-Articles/2022-11-22-gRPC-JSON-Transcoding/POST.md +++ b/docs/en/Community-Articles/2022-11-22-gRPC-JSON-Transcoding/POST.md @@ -4,6 +4,12 @@ In this article, I'll show you one of the new features that came with .NET 7: ** > I've created a community article to highlight some interesting features (briefly) that are now available with the release of .NET 7. You can check it from [here](https://community.abp.io/posts/whats-new-with-.net-7-tlq2g43w). +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## What is gRPC? What are the pros and cons? [gRPC](https://grpc.io/) is a high-performance RPC framework and uses HTTP/2 and Protobuf (protocol buffers). @@ -189,6 +195,12 @@ In this article, I've briefly introduced the JSON Transcoding feature that was s > See the [gRPC JSON transcoding in ASP.NET Core gRPC apps](https://learn.microsoft.com/en-us/aspnet/core/grpc/json-transcoding?view=aspnetcore-7.0) documentation for more information. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## References * https://devblogs.microsoft.com/dotnet/announcing-grpc-json-transcoding-for-dotnet/ diff --git a/docs/en/Community-Articles/2022-18-11-whats-new-with-net7/POST.md b/docs/en/Community-Articles/2022-18-11-whats-new-with-net7/POST.md index fb964fa730..671592d63e 100644 --- a/docs/en/Community-Articles/2022-18-11-whats-new-with-net7/POST.md +++ b/docs/en/Community-Articles/2022-18-11-whats-new-with-net7/POST.md @@ -6,6 +6,12 @@ In this article, I will highlight a few interesting features that are now availa There are many new features coming with this release. We are going to examine new features within 4 sub-sections: ASP.NET Core, C#11, EF 7 and MAUI. Let's start with ASP.NET Core. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## ASP.NET Core We will see the following features in this section: @@ -290,6 +296,12 @@ In this article, I've highlighted some features that were shipped with .NET 7. Thanks for reading the article and I hope you find it helpful. See you in the next one! +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## References * https://devblogs.microsoft.com/dotnet/announcing-dotnet-7/ diff --git a/docs/en/Community-Articles/2023-07-03-Image-Compression-And-Resize/POST.md b/docs/en/Community-Articles/2023-07-03-Image-Compression-And-Resize/POST.md index 9023417b20..1a1aa55f97 100644 --- a/docs/en/Community-Articles/2023-07-03-Image-Compression-And-Resize/POST.md +++ b/docs/en/Community-Articles/2023-07-03-Image-Compression-And-Resize/POST.md @@ -8,6 +8,12 @@ ABP Framework provides services to compress and resize images and implements the > Refer to the documentation for more info: [Image Manipulation](https://docs.abp.io/en/abp/7.3/Image-Manipulation) +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ### Source Code You can find the source code of the application at [https://github.com/abpframework/abp-samples/tree/master/ImageManipulation](https://github.com/abpframework/abp-samples/tree/master/ImageManipulation). Don't hesitate to check the source code, if you are stuck on any point. @@ -281,6 +287,12 @@ The results are impressive for the example above: * The original image was 12 KB and now the compressed & resized image has been reduced to 8 KB. * The original image was 225x225 and now resized as 200x200. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion In this article, I have shown you how to compress and/or resize images with ABP Framework's Image Manipulation System by just defining some attributes to the top of the controller actions. diff --git a/docs/en/Community-Articles/2023-08-12-ABP-Commercial-GDPR-Module-Overview/POST.md b/docs/en/Community-Articles/2023-08-12-ABP-Commercial-GDPR-Module-Overview/POST.md index 38cfab67e9..3d62f38886 100644 --- a/docs/en/Community-Articles/2023-08-12-ABP-Commercial-GDPR-Module-Overview/POST.md +++ b/docs/en/Community-Articles/2023-08-12-ABP-Commercial-GDPR-Module-Overview/POST.md @@ -2,6 +2,12 @@ In this article, I will highlight ABP Commercial's [GDPR Module](https://commercial.abp.io/modules/Volo.Gdpr) and show you how to provide personal data to the GDPR Module that is collected by your application and make it aligned with personal data download results. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## GDPR Module [GDPR Module](https://docs.abp.io/en/commercial/latest/modules/gdpr) allows users to download and delete the data collected by the application. It's used for Personal Data Management obligating by the GDPR regulation and provides the following features: @@ -143,6 +149,12 @@ Then, when we clicked the download button, a zip file will be downloaded. We can {"City":"Istanbul","Postcode":"..."} ``` +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion In this article, I've explained the GDPR Module's data collection system and given you a brief overview of the module. GDPR Module allows you to request to download personal data, delete/anonymize your own personal data and delete your account permanently. It's pre-installed in the Application and Application(single layer) Pro Startup templates, but you can easily configure it to your existing application. diff --git a/docs/en/Community-Articles/2023-10-30-NET-8-ASP-NET-Core-Metrics/POST.md b/docs/en/Community-Articles/2023-10-30-NET-8-ASP-NET-Core-Metrics/POST.md index 9142a36be9..9586b51cf5 100644 --- a/docs/en/Community-Articles/2023-10-30-NET-8-ASP-NET-Core-Metrics/POST.md +++ b/docs/en/Community-Articles/2023-10-30-NET-8-ASP-NET-Core-Metrics/POST.md @@ -2,6 +2,12 @@ In this article, I'll show you the new built-in metrics of .NET 8, which are basically numerical measurements reported over time in your application and can be used to monitor the health of your application and generate reports according to those numerical values. We will see what the metrics are, why to use them, and how to use them in detail. So, let's dive in. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## What are Metrics? Metrics are numerical measurements reported over time. These measurements are crucial for monitoring the health of an application and generating alerts when necessary. In the context of a web service, various metrics can be tracked, such as: @@ -185,6 +191,12 @@ If you want to build a dashboard, you can see [this documentation from Microsoft Also, you can check [this video](https://www.youtube.com/watch?v=A2pKhNQoQUU) if you want to see it in action. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion In this article, I've shown you the new built-in metrics of .NET8, described what metrics are, which pre-built metrics are provided by ASP.NET Core, how to use & view these pre-built metrics and finally, I have shown you how to create custom metrics and view them in a dashboard. If you want to learn more about the **Metrics System of .NET**, you can check out the references that I have shared below. diff --git a/docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md b/docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md index 3ed34680c1..c247f1e3e9 100644 --- a/docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md +++ b/docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md @@ -4,6 +4,12 @@ A new .NET version was released on November 14, 2023 and ABP 8.0 RC.1 shipped ba Despite all the related dependency upgrades and changes made on the ABP Framework and ABP Commercial sides, we still need to make some changes. Let's see the required actions that need to be taken in the following sections. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Installing the .NET 8.0 SDK To get started with ASP.NET Core in .NET 8.0, you need to install the .NET 8 SDK. You can install it at [https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0). @@ -99,3 +105,9 @@ After that, you need to check the migration guide documents, listed below: That's it! These were all the related steps that need to be taken to upgrade your application to .NET 8 and ABP 8.0. Now, you can enjoy the .NET 8 & ABP 8.0 and benefit from the performance improvements and new features. Happy Coding 🤗 + +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- \ No newline at end of file diff --git a/docs/en/Community-Articles/2024-01-18-ABP-Now-Supports-Keyed-Services/POST.md b/docs/en/Community-Articles/2024-01-18-ABP-Now-Supports-Keyed-Services/POST.md index d100838b1a..aeefc03c0c 100644 --- a/docs/en/Community-Articles/2024-01-18-ABP-Now-Supports-Keyed-Services/POST.md +++ b/docs/en/Community-Articles/2024-01-18-ABP-Now-Supports-Keyed-Services/POST.md @@ -2,6 +2,12 @@ In this post, I describe the new **"keyed service"** support for the dependency injection container, which came with .NET 8.0. Then, I'll show you an example of usage within the ABP Framework. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## What Are Keyed Services? ASP.NET Core ships with a built-in dependency injection container, which is a pretty basic DI container that supports minimal features a dependency injection container is supposed to have. For that reason, most of the .NET users use third-party containers like [Autofac](https://autofac.org/), or Ninject. @@ -203,6 +209,12 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie Please refer to the [Dependency Injection document](https://abp.io/docs/latest/framework/fundamentals/dependency-injection#exposekeyedservice-attribute) for further info. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Summary In this post, I described the new **"keyed service"** support added to the built-in dependency injection container that was released in .NET 8, and wanted to announce it's being supported from v8.0.2 for ABP Framework. It's a really good addition to the built-in dependency injection container and can be pretty useful for certain use-cases. diff --git a/docs/en/Community-Articles/2024-02-19-abpio-platform-81-rc-has-been-published/post.md b/docs/en/Community-Articles/2024-02-19-abpio-platform-81-rc-has-been-published/post.md index 569e566af7..fbe2c2cbad 100644 --- a/docs/en/Community-Articles/2024-02-19-abpio-platform-81-rc-has-been-published/post.md +++ b/docs/en/Community-Articles/2024-02-19-abpio-platform-81-rc-has-been-published/post.md @@ -228,7 +228,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [A Best Practice for Designing Interfaces in .NET C#](https://community.abp.io/posts/a-best-practice-for-designing-interfaces-in-.net-c-9xqc4h8d) * [Invariance, Covariance, and Contravariance in .NET C#](https://community.abp.io/posts/invariance-covariance-and-contravariance-in-.net-c-9blmuhme) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Community-Articles/2024-04-19-Performing-Case-Insensitive-Search-In-Postgresql/POST.md b/docs/en/Community-Articles/2024-04-19-Performing-Case-Insensitive-Search-In-Postgresql/POST.md index e4f763f279..5eb4a5bd98 100644 --- a/docs/en/Community-Articles/2024-04-19-Performing-Case-Insensitive-Search-In-Postgresql/POST.md +++ b/docs/en/Community-Articles/2024-04-19-Performing-Case-Insensitive-Search-In-Postgresql/POST.md @@ -120,6 +120,12 @@ After these configurations, you should create a migration and apply it to your d However, this solution comes with some problems, for example, by using non-deterministic collations, it's not yet possible to use pattern-matching operators such as `LIKE` on columns. This is a huge problem because it makes it hard to use LINQ. For example, you can't use the `.EndsWith` or `.StartsWith` methods, because they are [translated to `LIKE` command on the SQL level](https://www.npgsql.org/efcore/mapping/translations.html). +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion In PostgreSQL, you can perform case-insensitive searches by using the `citext` data type or by utilizing collation settings. Nevertheless, if you have an ABP-based PostgreSQL application or a plain .NET application with PostgreSQL as the database option, to make a decision to pick one of these options, you can follow the following points: diff --git a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md index e6417b70ce..deb162bcba 100644 --- a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md +++ b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md @@ -4,6 +4,12 @@ In this article, first I will briefly explain what sentiment analysis is and the We will use ML.NET Framework, which is an open-source machine learning framework created by the dotnet team and also we will create a layered ABP Solution by using the application template and finally we will use CMS Kit's Comment Feature and extend its behavior by adding spam detection while creating or updating a comment, at that point we will make sentiment analysis. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Sentiment Analysis [Sentiment Analysis (or opinion mining)](https://en.wikipedia.org/wiki/Sentiment_analysis) refers to determining the emotion from the given input. The primary goal of sentiment analysis is to identify, extract, and categorize (positive, negative, or neutral) the sentiments expressed in textual data. @@ -333,6 +339,12 @@ Then, finally, we can run the application to see the final results: Once the model is trained and evaluated, we can save the trained model and use it directly for further use. In this way, you don’t have to retrain the model every time when you want to make predictions. It’s essential to save the trained model for future use and a must for the production-ready code. I created a separate article dedicated to that topic, and if you are interested, you can read it from [here](https://engincanv.github.io/machine-learning/sentiment-analysis/best-practises/2024/05/16/reusing-and-optimizing-machine-learning-models-in-dotnet.html). +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion In this article, I briefly explain what sentiment analysis is, created a sample ABP-based application, integrated the CMS Kit Module and finally, applied sentiment analysis to make spam checks whenever a new comment has been submitted or updated. You can get the source code of the demo from [https://github.com/EngincanV/SentimentAnalysisDemo](https://github.com/EngincanV/SentimentAnalysisDemo) diff --git a/docs/en/Community-Articles/2024-05-24-abpio-platform-82-rc-has-been-published/post.md b/docs/en/Community-Articles/2024-05-24-abpio-platform-82-rc-has-been-published/post.md index 6574012f24..c3eadb6419 100644 --- a/docs/en/Community-Articles/2024-05-24-abpio-platform-82-rc-has-been-published/post.md +++ b/docs/en/Community-Articles/2024-05-24-abpio-platform-82-rc-has-been-published/post.md @@ -259,7 +259,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [Using FluentValidation with ABP Framework](https://community.abp.io/posts/using-fluentvalidation-with-abp-framework-2cxuwl70) by [Enes Döner](https://community.abp.io/members/Enes) * [Using Blob Storage with ABP](https://community.abp.io/posts/using-blob-storage-with-abp-framework-jygtmhn4) by [Emre Kendirli](https://community.abp.io/members/emrekenderli) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Community-Articles/2024-08-01-abpio-platform-83-rc-has-been-published/post.md b/docs/en/Community-Articles/2024-08-01-abpio-platform-83-rc-has-been-published/post.md index 05c18fde03..4ddd247a63 100644 --- a/docs/en/Community-Articles/2024-08-01-abpio-platform-83-rc-has-been-published/post.md +++ b/docs/en/Community-Articles/2024-08-01-abpio-platform-83-rc-has-been-published/post.md @@ -165,7 +165,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [How to use .NET Aspire with ABP framework](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk) by [Berkan Şaşmaz](https://twitter.com/berkansasmazz) * [Exciting New Feature in ABP.IO CMS Kit: Marked Item System](https://abp.io/community/articles/exciting-new-feature-in-abp.io-cms-kit-marked-item-system.-2hvpq0me) by [Suhaib Mousa](https://abp.io/community/members/suhaibmousa032@gmail.com) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Community-Articles/2024-09-12-abpio-platform-83-final-has-been-released/post.md b/docs/en/Community-Articles/2024-09-12-abpio-platform-83-final-has-been-released/post.md index 55f7b80294..de27f8cdbd 100644 --- a/docs/en/Community-Articles/2024-09-12-abpio-platform-83-final-has-been-released/post.md +++ b/docs/en/Community-Articles/2024-09-12-abpio-platform-83-final-has-been-released/post.md @@ -70,7 +70,7 @@ As always, exciting articles have been contributed by the ABP community. I will * [Introducing the Google Cloud Storage BLOB Provider](https://abp.io/community/articles/introducing-the-google-cloud-storage-blob-provider-yrt6azc0) by [Engincan Veske](https://twitter.com/EngincanVeske) * [Switching Between Organization Units](https://abp.io/community/articles/switching-between-organization-units-i5tokpzt) by [Liming Ma](https://github.com/maliming) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## About the Next Version diff --git a/docs/en/Community-Articles/2024-10-23-abpio-platform-90-rc-has-been-published/post.md b/docs/en/Community-Articles/2024-10-23-abpio-platform-90-rc-has-been-published/post.md index 9e22660332..a7dfa896bd 100644 --- a/docs/en/Community-Articles/2024-10-23-abpio-platform-90-rc-has-been-published/post.md +++ b/docs/en/Community-Articles/2024-10-23-abpio-platform-90-rc-has-been-published/post.md @@ -210,7 +210,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [ABP-Powered Web App with Inertia.js, React, and Vite](https://abp.io/community/articles/abppowered-web-app-with-inertia.js-react-and-vite-j7cccvad) by [Anto Subash](https://antosubash.com/) * [Multi-Tenancy Support in Angular Apps with ABP.IO](https://abp.io/community/articles/multitenancy-support-in-angular-apps-with-abp.io-lw9l36c5) by [HeadChannel Team](https://headchannel.co.uk/) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md b/docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md index 3cd4bdc706..a9b869a822 100644 --- a/docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md +++ b/docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md @@ -6,6 +6,12 @@ It offers a flexible caching solution that combines the best aspects of local an In this article, we’ll explore **HybridCache** in .NET 9 and how it integrates with ABP Framework using `AbpHybridCache`. This new feature offers a robust solution for applications that need to scale while maintaining efficient caching strategies. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## What is HybridCache? **HybridCache** is designed to merge different caching layers, commonly including an in-memory cache (for high-speed access) and a distributed cache (for scalability across multiple instances). This hybrid approach allows for: @@ -109,6 +115,12 @@ As you can see from the figure, it only set the cache item to the **LocalCache** **Note:** If you configure distributed caching options, `HybridCache` service uses the distributed cache and sets the **BackendCache**. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion The **HybridCache** library in .NET 9 provides a powerful tool for applications needing both high-speed caching and consistency in distributed environments. diff --git a/docs/en/Community-Articles/2024-11-21-abpio-platform-90-has-been-released-based-on-net-90/post.md b/docs/en/Community-Articles/2024-11-21-abpio-platform-90-has-been-released-based-on-net-90/post.md index 30ff978de6..931379eac0 100644 --- a/docs/en/Community-Articles/2024-11-21-abpio-platform-90-has-been-released-based-on-net-90/post.md +++ b/docs/en/Community-Articles/2024-11-21-abpio-platform-90-has-been-released-based-on-net-90/post.md @@ -80,7 +80,7 @@ In addition to [the articles to highlight .NET 9.0 features written by our team] * [How to create your Own AI Bot on WhatsApp Using an ABP.io Template](https://abp.io/community/articles/how-to-create-your-own-ai-bot-on-whatsapp-using-the-abp-framework-c6jgvt9c) by [Michael Kokula](https://abp.io/community/members/Michal_Kokula) * [ABP Now Supports .NET 9](https://abp.io/community/articles/abp-now-supports-.net-9-zpkznc4f) by [Alper Ebiçoğlu](https://x.com/alperebicoglu) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Community-Articles/2025-01-21-abp-platform-91-rc-has-been-released/post.md b/docs/en/Community-Articles/2025-01-21-abp-platform-91-rc-has-been-released/post.md index 2c3a98ac49..615457a7ff 100644 --- a/docs/en/Community-Articles/2025-01-21-abp-platform-91-rc-has-been-released/post.md +++ b/docs/en/Community-Articles/2025-01-21-abp-platform-91-rc-has-been-released/post.md @@ -136,7 +136,7 @@ There are exciting articles contributed by the ABP community as always. I will h * [The new Unit Test structure in ABP application](https://abp.io/community/articles/the-new-unit-test-structure-in-abp-application-4vvvp2oy) by [Liming Ma](https://github.com/maliming) * [How to Use OpenAI API with ABP Framework](https://abp.io/community/articles/how-to-use-openai-api-with-abp-framework-rsfvihla) by [Berkan Şaşmaz](https://github.com/berkansasmaz) -Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community. +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/create) to the ABP Community. ## Conclusion diff --git a/docs/en/Community-Articles/2025-02-04-OpenIddict-Custom-Logic/POST.md b/docs/en/Community-Articles/2025-02-04-OpenIddict-Custom-Logic/POST.md index f5602650ae..e8b8c9a1b3 100644 --- a/docs/en/Community-Articles/2025-02-04-OpenIddict-Custom-Logic/POST.md +++ b/docs/en/Community-Articles/2025-02-04-OpenIddict-Custom-Logic/POST.md @@ -6,6 +6,12 @@ OpenIddict provides an event-driven model ([event models](https://documentation. In this article, we will explore OpenIddict event models, their key use cases, and how to implement them effectively. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Understanding OpenIddict Event Model OpenIddict events are primarily used within the OpenIddict server component. These events provide hooks into the OpenID Connect flow, allowing developers to modify behavior at different stages of authentication & authorization processes. @@ -101,6 +107,12 @@ That's it! After these steps, your `SignOutEventHandler.HandleAsync()` method sh Each event provides access to the relevant context, allowing you to access and modify the authentication flow's behavior. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion ABP Framework integrates OpenIddict as its authentication and authorization module. OpenIddict provides an event-driven model that allows developers to customize authentication and authorization processes within their ABP applications. It's pre-installed & pre-configured in the ABP's startup templates. diff --git a/docs/en/Community-Articles/2025-03-11-Developing-A-Multi-Timezone-Application-Using-The-ABP-Framework/post.md b/docs/en/Community-Articles/2025-03-11-Developing-A-Multi-Timezone-Application-Using-The-ABP-Framework/post.md index bfde4d5318..09d7f917bb 100644 --- a/docs/en/Community-Articles/2025-03-11-Developing-A-Multi-Timezone-Application-Using-The-ABP-Framework/post.md +++ b/docs/en/Community-Articles/2025-03-11-Developing-A-Multi-Timezone-Application-Using-The-ABP-Framework/post.md @@ -6,6 +6,8 @@ All these scenarios require us to handle timezone conversions correctly in our a In this article, we'll show you step by step how to handle multi-timezone in the ABP framework. +> The content mentioned in this article will be available after the ABP 9.2 version + ## Timezone Settings The ABP framework provides a setting called `Abp.Timing.TimeZone` for setting and getting the timezone of users, tenants, or applications. The default value is empty, which means the application will use the server's time zone. Check out the [Timing documentation](https://abp.io/docs/latest/framework/infrastructure/timing) for more information. diff --git a/docs/en/Community-Articles/2025-03-18-Using-Vue-Components/post.md b/docs/en/Community-Articles/2025-03-18-Using-Vue-Components/post.md index bc0b390b03..09998169e6 100644 --- a/docs/en/Community-Articles/2025-03-18-Using-Vue-Components/post.md +++ b/docs/en/Community-Articles/2025-03-18-Using-Vue-Components/post.md @@ -75,7 +75,7 @@ Let's create a simple Vue component to display the TODO list. ```html
- +
``` diff --git a/docs/en/Community-Articles/2025-03-23-Understanding-the-Embedded-Files-in-ABP-Framework/post.md b/docs/en/Community-Articles/2025-03-23-Understanding-the-Embedded-Files-in-ABP-Framework/post.md index 5664fd8091..ccbf1a285c 100644 --- a/docs/en/Community-Articles/2025-03-23-Understanding-the-Embedded-Files-in-ABP-Framework/post.md +++ b/docs/en/Community-Articles/2025-03-23-Understanding-the-Embedded-Files-in-ABP-Framework/post.md @@ -119,7 +119,7 @@ For example, if your filename is `zh.hans.json`, ABP will generate the following [File] [/MyModule/Volo/Abp/MyModule/Localization/zh/hans.json] ``` -Microsoft provides the `Microsoft.Extensions.FileProviders.Manifest` library to solve this problem. +Microsoft provides the `Microsoft.Extensions.FileProviders.Embedded` library to solve this problem. We need to add this package dependency and set `true` in our project: @@ -136,7 +136,7 @@ We need to add this package dependency and set `t - + diff --git a/docs/en/Community-Articles/2025-03-24-How-to-Change-the-CurrentUser-in-ABP/POST.md b/docs/en/Community-Articles/2025-03-24-How-to-Change-the-CurrentUser-in-ABP/POST.md index b74aecdbe4..4213ad0e48 100644 --- a/docs/en/Community-Articles/2025-03-24-How-to-Change-the-CurrentUser-in-ABP/POST.md +++ b/docs/en/Community-Articles/2025-03-24-How-to-Change-the-CurrentUser-in-ABP/POST.md @@ -4,6 +4,12 @@ In this article, we'll explore the [`CurrentUser` service](https://abp.io/docs/latest/framework/infrastructure/current-user), its use cases, and how to change it when necessary. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Understanding the ICurrentUser Service The `ICurrentUser` interface is the primary service in ABP Framework for obtaining information about the logged-in user. It provides some key properties, such as `Id`, `UserName`, `TenantId`, `Roles` (roleNames), and more... @@ -108,6 +114,12 @@ Here's what the code does step by step: This pattern is particularly useful in background jobs, event handlers, or any scenario where you need to perform operations under a specific user's context, regardless of the actual authenticated user. +--- +> 🛠 Liked this post? I now share all my content on Substack — real-world .NET, AI, and scalable software design. +> 👉 Subscribe here → engincanveske.substack.com +> 🎥 Also, check out my YouTube channel for hands-on demos and deep dives: https://www.youtube.com/@engincanv +--- + ## Conclusion The `CurrentUser` service in ABP Framework provides a simple way to access information about the authenticated user. While it works automatically in most scenarios, there are cases where you need to explicitly change the current user identity, particularly in background processing scenarios. diff --git a/docs/en/Community-Articles/2025-03-27-Announcing-the-ABP-Contributor-Program/post.md b/docs/en/Community-Articles/2025-03-27-Announcing-the-ABP-Contributor-Program/post.md new file mode 100644 index 0000000000..7767a6673b --- /dev/null +++ b/docs/en/Community-Articles/2025-03-27-Announcing-the-ABP-Contributor-Program/post.md @@ -0,0 +1,38 @@ +We are excited to introduce the ABP Contributor Program, which is an amazing opportunity for community enthusiasts to contribute to the ABP ecosystem while getting valuable benefits\! + +**Create, Contribute and Be Part of Something Bigger** + +This is your opportunity to not only share your knowledge but also to grow alongside a passionate community of developers and creators. When you create and contribute to the ABP ecosystem, you’re not just building content, you’re also helping shape the future of ABP. + +## **Why Become an ABP Contributor?** + +By sharing your knowledge, creating valuable content, and engaging with the ABP Community, you’ll enjoy a range of benefits, including: + +* Free ABP Personal License – If you meet all the requirements, you’ll receive an ABP Personal License at no cost + +* Community Badge & Title – Stand out in the ABP Community with a special contributor badge and label next to your name. + +* Exclusive Discord Role – Get a unique Contributor role on the ABP Community Discord server. + +* Increased Visibility – Your contributions will be recognized by hundreds of thousands of developers worldwide. + + Completely Free – No fees, just log in, contribute, and start collecting benefits\! + +## **How to Apply?** + +If you’re passionate about ABP and think you meet the required criteria, follow these simple steps: + +Create content related to ABP: blog posts, tutorials, videos, or documentation. You can publish it on the ABP Community website or any external platform (just make sure to submit it to the ABP Community site). + +Apply by email: Send your application to marketing@volosoft.com, and the ABP Team will review your eligibility. + +Periodic Assessments: The team reviews submissions every three months to determine and renew contributor status. Keep contributing to continue enjoying the perks\! + +## **Join Us & Grow\!** + +This is your chance to give back to the community, grow your presence, and get rewarded for your contributions. Whether you love writing documentation, sharing tutorials, or building open-source projects, your efforts matter. + +Apply today and be part of something impactful\! + + +[image1]: images/img_1.png \ No newline at end of file diff --git a/docs/en/Community-Articles/2025-04-20-IDX10204/POST.md b/docs/en/Community-Articles/2025-04-20-IDX10204/POST.md new file mode 100644 index 0000000000..5de0650d11 --- /dev/null +++ b/docs/en/Community-Articles/2025-04-20-IDX10204/POST.md @@ -0,0 +1,170 @@ +# Common Errors in JWT Bearer Authentication + +When implementing JWT Bearer authentication in an ABP(tiered) application, you might occasionally encounter errors starting with `IDX`. These errors are related to JWT Bearer Token validation and this article will help you understand and resolve them. + +## Enable JWT Bearer authentication + +Your API project usually contains the following code, which enables JWT Bearer authentication and makes it as the default authentication scheme. + +We simply configure the JWT's `Authority` and `Audience` properties, and it will work fine. + +```csharp +context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = "https://localhost:44301/"; //configuration["AuthServer:Authority"]; + options.Audience = "MyProjectName"; + }); +``` + +> `AddJwtBearer` and `AddAbpJwtBearer` will do the same thing, but `AddAbpJwtBearer` is recommended. + +## JWT authentication process + +Let's take a look at how the above code works. + +A JWT Token usually consists of three parts: `Header`, `Payload`, and `Signature`. + +- `Header`: Contains the type and signing algorithm of the token +- `Payload`: Contains the claims of the token, including `sub`, `aud`, `exp`, `iat`, `iss`, `jti`, `preferred_username`, `given_name`, `role`, `email`, etc. +- `Signature`: The cryptographic signature of the token used to verify its authenticity + +Here is an example of a JWT Token issued by `AuthServer(OpenIddict)`: + +The `Header` part: + +![JWT Header](header.png) + +The `Payload` part: + +![JWT Payload](payload.png) + +### TokenValidationParameters + +In the `JwtBearerOptions`, there is a `TokenValidationParameters` property, which is used to validate the JWT Token. + +The default implementation for JWT Token validation is `JsonWebTokenHandler`, which comes from the [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/) package. + +We didn't set the `TokenValidationParameters` property in the code above, so the default values below will be used: + +```csharp +//... +TokenValidationParameters.ValidateAudience = true +TokenValidationParameters.ValidAudience = "MyProjectName" +TokenValidationParameters.ValidAudiences = null + +TokenValidationParameters.ValidateIssuer = true +TokenValidationParameters.ValidIssuer = null +TokenValidationParameters.ValidIssuers = null +//... +``` + +### JWT Bearer Token Validation Process + +During JWT Bearer authentication, API website will get the token from the HTTP request and validate it. + +The `JsonWebTokenHandler` will get the `OpenID Connect` metadata from the `AuthServer`, it will be used in the validation process, the current metadata request address is: https://localhost:44301/.well-known/openid-configuration , it is a fixed address calculated from the `Authority` property. + +First, the token's Signature is verified using the public key obtained from `OpenID Connect` metadata(https://localhost:44301/.well-known/jwks). + +Then, the payload is validated. The payload is a JSON object containing essential information such as the `token type`, `expiration time`, `issuer`, and `audience` etc. + +Most of the validation problems we may encounter are payload validation failures, for example: + +#### Lifetime + +If the token in your request has expired, the validation will fail. You will see the exception information like `IDX10230` in the log. + +#### Audience + +The `ValidAudience` of `TokenValidationParameters` is `MyProjectName`, the `aud` in the payload of the token is also `MyProjectName`, if the token does not contain `aud` or the `aud` does not match, the validation will fail. You may see the exception information like `IDX10206`, `IDX10277` or `IDX10208`. + +> If the `ValidateAudience` of `TokenValidationParameters` is `false`, then the `aud` will not be validated. + +#### Issuer + +The default value of `TokenValidationParameters.ValidateIssuer` is `true`, it requires the token's payload to contain the `issuer` field, and it must match one of `TokenValidationParameters.ValidIssuer` or `TokenValidationParameters.ValidIssuers`. + +> The default value of `ValidIssuer` or `ValidIssuers` is `null`, it will use the `issuer` from the `OpenID Connect` metadata as the default value. + +1. If the token's payload does not contain the `issuer` field, you may see the error `IDX10211`. +2. If the API website cannot get the `OpenID Connect` metadata from AuthServer website, the validation will fail. You may see the error `IDX10204`, the full exception message is: `IDX10204: Unable to validate issuer. validationParameters.ValidIssuer is null or whitespace AND validationParameters.ValidIssuers is null or empty.` +3. If the `issuer` does not match, the validation will fail. You may see the error `IDX10205` in the log. + +> If the `ValidateIssuer` of `TokenValidationParameters` is `false`, then the `issuer` will not be validated. + +> Please note that `OpenIddict` will use the current HTTP request information as the value of `issuer`. If the AuthServer website is deployed behind a reverse proxy or similar deployment configurations, the `issuer` in the token may not be the value you expect. In this case, please specify it manually. + +```csharp +PreConfigure(serverBuilder => +{ + serverBuilder.SetIssuer("https://localhost:44301/"); +}); +``` + +## Troubleshooting + +To troubleshoot any `IDX` errors during JWT authentication, you can enable detailed logging by configuring the `identitymodel` logs as follows: + +```csharp +using System.Diagnostics.Tracing; +using Microsoft.IdentityModel.Logging; + +public class Program +{ + public async static Task Main(string[] args) + { + IdentityModelEventSource.ShowPII = true; + IdentityModelEventSource.Logger.LogLevel = EventLevel.Verbose; + var wilsonTextLogger = newTextWriterEventListener("Logs/identitymodel.txt"); + wilsonTextLogger.EnableEvents(IdentityModelEventSource.Logger, EventLevel.Verbose); + + //... + } +} +``` + +Additionally, you can enable `OpenIddict`'s `Verbose` logs for more detailed debugging information: + +```csharp +var loggerConfiguration = new LoggerConfiguration() + .MinimumLevel.Debug() + .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) + .MinimumLevel.Override("OpenIddict", LogEventLevel.Verbose) + .Enrich.FromLogContext() + .WriteTo.Async(c => c.File("Logs/logs.txt")) +``` + +## Summary + +For JWT authentication, you need to pay attention to the following key points: + +1. Ensure your API website can communicate with the AuthServer properly +2. Verify that the `aud` claim in your token matches the expected audience +3. Confirm that the `issuer` claim in your token is valid and matches the configuration + +You can customize the `JwtBearerOptions`'s `TokenValidationParameters` to modify the validation rules to meet your actual needs. + +For example, if your `issuer` needs to support multiple subdomains, you can use the [Owl.TokenWildcardIssuerValidator](https://github.com/maliming/Owl.TokenWildcardIssuerValidator) library to customize the validation. + +```csharp +services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = "https://abp.io"; + options.Audience = "abp_io"; + + options.TokenValidationParameters.IssuerValidator = TokenWildcardIssuerValidator.IssuerValidator; + options.TokenValidationParameters.ValidIssuers = new[] + { + "https://{0}.abp.io" + }; + }); +``` + +## References + +- [Configure JWT bearer authentication in ASP.NET Core]([https://learn.microsoft.com/en-us/aspnet/core/security/authentication/jwt-auth?view=aspnetcore-8.0](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/configure-jwt-bearer-authentication)) +- [OpenIddict](https://github.com/openiddict/openiddict-core) +- [IdentityModel](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) +- [Owl.TokenWildcardIssuerValidator](https://github.com/maliming/Owl.TokenWildcardIssuerValidator) diff --git a/docs/en/Community-Articles/2025-04-20-IDX10204/header.png b/docs/en/Community-Articles/2025-04-20-IDX10204/header.png new file mode 100644 index 0000000000..13109a4515 Binary files /dev/null and b/docs/en/Community-Articles/2025-04-20-IDX10204/header.png differ diff --git a/docs/en/Community-Articles/2025-04-20-IDX10204/payload.png b/docs/en/Community-Articles/2025-04-20-IDX10204/payload.png new file mode 100644 index 0000000000..04b927bbb2 Binary files /dev/null and b/docs/en/Community-Articles/2025-04-20-IDX10204/payload.png differ diff --git a/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/POST.md b/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/POST.md new file mode 100644 index 0000000000..f79fa21ce8 --- /dev/null +++ b/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/POST.md @@ -0,0 +1,262 @@ +# Using Microsoft AI Extensions Library and OpenAI to Summarize User Comments + +Either you are building an e-commerce application or a simple blog, **user comments** (about your products or blog posts) **can grow rapidly**, making it harder for users to get the gist of discussions at a glance. AI is a pretty good tool to solve the problem. By using AI, you can **summarize all the user comments** and show a single paragraph to your users, so they can easily understand the overall thought of users about the product or the blog post. + +In this tutorial, we’ll walk through a real-life implementation of using AI to summarize multiple user comments in an application. I will implement the solution based on ABP's **[CMS Kit](https://abp.io/docs/latest/modules/cms-kit)** library, as it already features a **[commenting system](https://abp.io/docs/latest/modules/cms-kit/comments)** and a [demo application](https://cms-kit-demo.abpdemo.com/) that displays user comments on **[gallery images](https://cms-kit-demo.abpdemo.com/image-gallery)** (it has not a comment summary feature yet, we will implement it in this tutorial). + +## A Screenshot + +Here, an example screenshot from the application with the comment summary feature: + +![comment-example](comment-example.png) + +## Cloning the Repository + +If you want to follow the development, you can clone the [CMS Kit Demo repository](https://github.com/abpframework/cms-kit-demo) to your computer and make it running by following the instructions on the [README file](https://github.com/abpframework/cms-kit-demo?tab=readme-ov-file#cms-kit-demo). + +I suggest to you to play a little with [the application](https://cms-kit-demo.abpdemo.com/) (create a new user for yourself, add some comments to the images in the gallery), so you understand how it works. + +## Preparing the Solution for AI + +I will use [Microsoft AI Extensions Library](https://learn.microsoft.com/en-us/dotnet/ai/ai-extensions) to use the AI features. It is an abstraction library that can work with multiple AI models and tools. I will use an OpenAI model in the demo. + +The first step is to add the [Microsoft.Extensions.AI.OpenAI](http://nuget.org/packages/Microsoft.Extensions.AI.OpenAI) NuGet package to the project: + +````bash +dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease +```` + +>The Microsoft AI Extensions Library was in preview at the time when I wrote this article. If it has a stable release now, you can remove the `--prerelease` parameter for the preceding command. + +We will store the OpenAI key and model name in user secrets. So, locate the root path of the CMS Kit project (`src\CmsKitDemo` folder) and execute the following commands in order in a command-line terminal: + +````bash +dotnet user-secrets init +dotnet user-secrets set OpenAIKey +dotnet user-secrets set ModelName +```` + +For this example, you need to have an [OpenAI API Key](https://platform.openai.com/). That's all. Now, we are ready to use the AI. + +## Implementing the AI Summarization + +Let's start from the most important point of this article: Comment summarization. I will create a class named `AiCommentSummarizer` to implement the summarization work. Here, the full content of that class: + +````csharp +using System.Text; +using Microsoft.Extensions.AI; +using OpenAI; +using Volo.Abp.DependencyInjection; + +namespace CmsKitDemo.Utils; + +public class AiCommentSummarizer : ITransientDependency +{ + private readonly IConfiguration _configuration; + + public AiCommentSummarizer(IConfiguration configuration) + { + _configuration = configuration; + } + + public async Task SummarizeAsync(string[] commentTexts) + { + // Get the model and key from the configuration + var aiModel = _configuration["ModelName"]; + var apiKey = _configuration["OpenAIKey"]; + + if (aiModel.IsNullOrEmpty() || apiKey.IsNullOrEmpty()) + { + return ""; + } + + // Create the IChatClient + var client = new OpenAIClient(apiKey) + .GetChatClient(aiModel) + .AsIChatClient(); + + // Create a prompt (input for AI) + var promptBuilder = new StringBuilder(); + + promptBuilder.AppendLine( + @"There are comments from different users of our website about an image. +We want to summarize the comments into a single comment. +Return a single comment with a maximum of 512 characters. Comments are separated by a newline character and given below." + ); + promptBuilder.AppendLine(); + + foreach (var commentText in commentTexts) + { + promptBuilder.AppendLine("User comment:"); + promptBuilder.AppendLine(commentText); + promptBuilder.AppendLine(); + } + + // Submit the prompt and get the response + var response = await client.GetResponseAsync( + promptBuilder.ToString(), + new ChatOptions { MaxOutputTokens = 1024 } + ); + + return response.Text; + } +} +```` + +That class is pretty simple and already decorated with comments: + +* First, we are getting the API Key and an OpenAI model name from user secrets. I used `gpt-4.1` as the model name, but you can use another available model. +* Then we are obtaining an `IChatClient` reference for OpenAI. `IChatClient` interface is an abstraction that is provided by the [Microsoft AI Extensions Library](https://learn.microsoft.com/en-us/dotnet/ai/ai-extensions) library, so we can implement rest of the code independently from OpenAI. +* Then we continue by building a proper prompt (input) for the AI operation. +* And finally we are using the AI to generate a response (the summary). + +At this point, all the AI-related work has already been done. The rest of this article explains how to integrate that summarization feature with the [CMS Kit Demo application](https://cms-kit-demo.abpdemo.com/). + +## Adding a CommentsSummary Property to the GalleryImage Entity + +The `GalleryImage` entity is used to represent an image on [the image gallery](https://cms-kit-demo.abpdemo.com/image-gallery). I add a `CommentsSummary` property to that entity: + +````csharp +public class GalleryImage : CreationAuditedAggregateRoot +{ + public string Description { get; set; } + + public Guid CoverImageMediaId { get; set; } + + public string CommentsSummary { get; set; } // The new property is here + + //... +} +```` + +Since the CMS Kit Demo application uses Entity Framework Core, I need to add a new database schema migration and update the database: + +````bash +dotnet ef migrations add Added_Summary_To_GalleryImage +dotnet ef database update +```` + +## Updating the Summary + +Great, we have a `GalleryImage.CommentsSummary` property now. But, how will it be updated when a users adds or removes a comment for an image? To implement that; + +* We will listen all the change events for user comments (when a user adds, removes or updates a comment). +* Whenever a comment is changed, we will find the related gallery image, retrieve all the user comments for this image, use the `AiCommentSummarizer` class to summarize all the comments. +* Finally, we wil set the `GalleryImage.CommentsSummary` property with the generated summary text. + +Here, the implementation: + +````csharp +using CmsKitDemo.Entities; +using CmsKitDemo.Utils; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.EventBus; +using Volo.CmsKit.Comments; + +namespace CmsKitDemo.EventHandlers; + +public class GalleryImageCommentListener : + ILocalEventHandler>, + ITransientDependency +{ + private readonly IRepository _galleryImageRepository; + private readonly IRepository _commentRepository; + private readonly AiCommentSummarizer _aiCommentSummarizer; + + public GalleryImageCommentListener( + IRepository galleryImageRepository, + IRepository commentRepository, + AiCommentSummarizer aiCommentSummarizer) + { + _galleryImageRepository = galleryImageRepository; + _commentRepository = commentRepository; + _aiCommentSummarizer = aiCommentSummarizer; + } + + public async Task HandleEventAsync(EntityChangedEventData eventData) + { + var comment = eventData.Entity; + + //Here, we only interest in comments related to image gallery items + if (comment.EntityType != CmsKitDemoConsts.ImageGalleryEntityType) + { + return; + } + + if (!Guid.TryParse(comment.EntityId, out var galleryImageId)) + { + return; + } + + // Get the related image from database + var galleryImage = await _galleryImageRepository.FindAsync(galleryImageId); + if (galleryImage == null) + { + return; + } + + // Get all the comments related to the image + var queryable = await _commentRepository.GetQueryableAsync(); + var allCommentTexts = await queryable + .Where(c => c.EntityType == CmsKitDemoConsts.ImageGalleryEntityType && + c.EntityId == comment.EntityId) + .Select(c => c.Text) + .ToArrayAsync(); + + // Update the summary of comments related to the image + if (allCommentTexts.Length <= 0) + { + galleryImage.CommentsSummary = ""; + } + else + { + galleryImage.CommentsSummary = + await _aiCommentSummarizer.SummarizeAsync(allCommentTexts); + } + + // Update the image in database + await _galleryImageRepository.UpdateAsync(galleryImage); + } +} +```` + +Let's explain that class: + +* `GalleryImageCommentListener` implements the `ILocalEventHandler>` interface. In this way, it can handle an event whenever a `Comment` [entity](https://abp.io/docs/latest/framework/architecture/domain-driven-design/entities) is changed (created, updated or deleted). We are using ABP's [local event bus](https://abp.io/docs/latest/framework/infrastructure/event-bus/local) and its [pre-defined events](https://abp.io/docs/latest/framework/infrastructure/event-bus/local#pre-built-events). +* `HandleEventAsync` is called by the ABP Framework whenever a new `Comment` is created, or an existing `Comment` is deleted or updated. +* ABP's `Comment` entity is reusable and it can be associated with any kind of objects (blog posts, images, etc). So, first we are checking if this comment is related to an image gallery item. +* Then we are getting the related `GalleryImage` entity from the database. +* And getting all comments (including the new one) from the database for this image. +* Finally, using the `AiCommentSummarizer` class to generate the summary and set the `CommentsSummary` property. + +## Show the Summary Card on the UI + +Everything is ready on the backend. Now, we can show the summary text on the user interface. To do, that, I added `CommentsSummary` property also to the `GalleryImageDto` class and used it on the `/Pages/Gallery/Detail.cshtml` view: + +````csharp +@if (!Model.Image.CommentsSummary.IsNullOrEmpty()) +{ +
+
+
Summary of the User Comments
+

@Model.Image.CommentsSummary

+
+
+} +```` + +That section renders the following card on the user interface: + +![summary-card](summary-card.png) + +## Conclusion + +In this article, I demonstrated how to use [Microsoft AI Extensions Library](https://learn.microsoft.com/en-us/dotnet/ai/ai-extensions) to work with OpenAI for summarization of multiple user comments. I reused the [ABP's CMS Kit Demo application](https://github.com/abpframework/cms-kit-demo) to show it in a more real world example. + +## Source Code + +* [Source code of the CMS Kit Demo application](https://github.com/abpframework/cms-kit-demo) +* [All the changes made for this article (as a pull request)](https://github.com/abpframework/cms-kit-demo/pull/18) \ No newline at end of file diff --git a/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/comment-example.png b/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/comment-example.png new file mode 100644 index 0000000000..4ac33b60f9 Binary files /dev/null and b/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/comment-example.png differ diff --git a/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/summary-card.png b/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/summary-card.png new file mode 100644 index 0000000000..9a36f3cd35 Binary files /dev/null and b/docs/en/Community-Articles/2025-04-25-AI-Comment-Summarization/summary-card.png differ diff --git a/docs/en/Community-Articles/2025-05-11-AI-Chat/POST.md b/docs/en/Community-Articles/2025-05-11-AI-Chat/POST.md new file mode 100644 index 0000000000..d6d2a5b6dc --- /dev/null +++ b/docs/en/Community-Articles/2025-05-11-AI-Chat/POST.md @@ -0,0 +1,134 @@ +# Integrating .NET AI Chat Template with ABP Framework + +This article demonstrates how to integrate the [.NET AI Chat Template](https://devblogs.microsoft.com/dotnet/announcing-dotnet-ai-template-preview2/) into an ABP Framework application, enabling powerful AI chat capabilities in your ABP-based solution. + +![cover](cover.png) + +## Step 1: Create a New ABP Project + +First, let's create a new [single-layer Blazor Server project](https://abp.io/docs/latest/solution-templates/single-layer-web-application/overview) named `AbpAiChat` using ABP Studio, You can also use the following ABP CLI command to create the project: + +```bash +abp new AbpAiChat -t app-nolayers --ui-framework blazor-server --use-open-source-template +``` + +## Step 2: Integrate AI Chat Template + +The integration process involves copying and adapting the .NET AI Chat Template code into our ABP project. The template code is already included in our sample project, so you don't need to install it separately. + +### 2.1 Project Structure Changes + +1. Copy Blazor components to the `Components` folder +2. Copy AI service classes to the `Services` folder +3. Add required entities(`IngestedDocument`, `IngestedRecord`) to the `AbpAiChatDbContext` and add new migration +4. Copy frontend resources to the `wwwroot` folder +5. Adjust some styles to capatible with the ABP theme + +### 2.2 Required NuGet Packages + +Add the following packages to `AbpAiChat.csproj`: + +```xml + + + + + + +``` + +### 2.3 Configure AI Services + +Add the following configuration to `AbpAiChatModule.cs`: + +```csharp +private void ConfigureAi(ServiceConfigurationContext context) +{ + var credential = new ApiKeyCredential(context.Services.GetConfiguration()["GitHubToken"] ?? throw new InvalidOperationException("Missing configuration: GitHubToken. See the README for details.")); + var openAiOptions = new OpenAIClientOptions() + { + Endpoint = new Uri("https://models.inference.ai.azure.com") + }; + + var ghModelsClient = new OpenAIClient(credential, openAiOptions); + var chatClient = ghModelsClient.GetChatClient("gpt-4o-mini").AsIChatClient(); + var embeddingGenerator = ghModelsClient.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator(); + + var vectorStore = new JsonVectorStore(Path.Combine(AppContext.BaseDirectory, "vector-store")); + + context.Services.AddSingleton(vectorStore); + context.Services.AddScoped(); + context.Services.AddSingleton(); + context.Services.AddChatClient(chatClient).UseFunctionInvocation().UseLogging(); + context.Services.AddEmbeddingGenerator(embeddingGenerator); + + context.Services.Configure(options => + { + options.ContentTypeMaps.Add(".mjs", "application/javascript"); + }); +} +``` + +The `ConfigureAi` method is called in the `ConfigureServices` method of `AbpAiChatModule`. It sets up the AI services, including the OpenAI client, chat client, embedding generator, and vector store. + +### 2.4 Configure GitHub Token + +Add your GitHub Personal Access Token to `appsettings.json`: + +```json +{ + "GitHubToken": "your-github-token" +} +``` + +You can obtain your token from [GitHub Personal Access Tokens](https://github.com/settings/personal-access-tokens). + +## Step 3: Add Custom AI Functionality + +Let's add a custom AI function to retrieve the current user's information. Update the `Chat.razor` component: + +```csharp +chatOptions.Tools = +[ + AIFunctionFactory.Create(SearchAsync), + AIFunctionFactory.Create(GetWeather), + AIFunctionFactory.Create(GetCurrentUserInfo) +]; + +[Description("Get current user information")] +private Task GetCurrentUserInfo() +{ + return Task.FromResult(CurrentUser.IsAuthenticated ? + $"UserId: {CurrentUser.Id}, Name: {CurrentUser.UserName}, Email: {CurrentUser.Email}, Roles: {string.Join(", ", CurrentUser.Roles)}" : + "No user information available."); +} +``` + +## Step 4: Add Navigation + +Add a `Chat` menu item in `AbpAiChatMenuContributor` to navigate to the AI Chat component. + +## Running the Application + +After completing the integration, you can run the application and access the AI chat functionality. The chat interface allows you to: + +- Get weather information +- Ask questions about PDF content +- Retrieve current user information +- And more! + +![AI Chat Interface](ai-chat.png) + +## Conclusion + +This integration demonstrates how to leverage the power of AI in your ABP Framework applications. The .NET AI Chat Template provides a solid foundation for building intelligent chat interfaces, and ABP Framework makes it more powerful. + +## References + +- [ABP Single Layer Solution](https://abp.io/docs/latest/solution-templates/single-layer-web-application/overview) +- [.NET AI Template Documentation](https://devblogs.microsoft.com/dotnet/announcing-dotnet-ai-template-preview1/) +- [GitHub Personal Access Tokens Guide](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) + +## Source Code + +- [AbpAiChat Source Code](https://github.com/abpframework/abp-samples/tree/master/AIChat) diff --git a/docs/en/Community-Articles/2025-05-11-AI-Chat/ai-chat.png b/docs/en/Community-Articles/2025-05-11-AI-Chat/ai-chat.png new file mode 100644 index 0000000000..8388e2ca9e Binary files /dev/null and b/docs/en/Community-Articles/2025-05-11-AI-Chat/ai-chat.png differ diff --git a/docs/en/Community-Articles/2025-05-11-AI-Chat/cover.png b/docs/en/Community-Articles/2025-05-11-AI-Chat/cover.png new file mode 100644 index 0000000000..5dce208fd6 Binary files /dev/null and b/docs/en/Community-Articles/2025-05-11-AI-Chat/cover.png differ diff --git a/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/POST.md b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/POST.md new file mode 100644 index 0000000000..6007e5371f --- /dev/null +++ b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/POST.md @@ -0,0 +1,268 @@ +# Resolving Tenant from Route in ABP Framework + +The ABP Framework provides multi-tenancy support with various ways to resolve tenant information, including: Cookie, Header, Domain, Route, and more. + +This article will demonstrate how to resolve tenant information from the route. + +## Tenant Information in Routes + +In the ABP Framework, tenant information in routes is handled by the `RouteTenantResolveContributor`. + +Let's say your application is hosted at `https://abp.io` and you have a tenant named `acme`. You can add the `{__tenant}` variable to your controller or page routes like this: + +```csharp +[Route("{__tenant}/[Controller]")] +public class MyController : MyProjectNameController +{ + [HttpGet] + public IActionResult Get() + { + return Ok("Hello My Page"); + } +} +``` + +```cshtml +@page "{__tenant?}/mypage" +@model MyPageModel + + + +

My Page

+ + +``` + +When you access `https://abp.io/acme/my` or `https://abp.io/acme/mypage`, ABP will automatically resolve the tenant information from the route. + +## Adding __tenant to Global Routes + +While we've shown how to add `{__tenant}` to individual controllers or pages, you might want to add it globally to your entire application. Here's how to implement this: + +```cs +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace MyCompanyName; + +public class AddTenantRouteToPages : IPageRouteModelConvention, IApplicationModelConvention +{ + public void Apply(PageRouteModel model) + { + var selectorCount = model.Selectors.Count; + var selectorModels = new List(); + for (var i = 0; i < selectorCount; i++) + { + var selector = model.Selectors[i]; + selectorModels.Add(new SelectorModel + { + AttributeRouteModel = new AttributeRouteModel + { + Template = AttributeRouteModel.CombineTemplates("{__tenant:regex(^[a-zA-Z0-9]+$)}", selector.AttributeRouteModel!.Template!.RemovePreFix("/")) + } + }); + } + foreach (var selectorModel in selectorModels) + { + model.Selectors.Add(selectorModel); + } + } +} + +public class AddTenantRouteToControllers :IApplicationModelConvention +{ + public void Apply(ApplicationModel application) + { + var controllers = application.Controllers; + foreach (var controller in controllers) + { + var selector = controller.Selectors.FirstOrDefault(); + if (selector == null || selector.AttributeRouteModel == null) + { + controller.Selectors.Add(new SelectorModel + { + AttributeRouteModel = new AttributeRouteModel + { + Template = AttributeRouteModel.CombineTemplates("{__tenant:regex(^[[a-zA-Z0-9]]+$)}", controller.ControllerName) + } + }); + controller.Selectors.Add(new SelectorModel + { + AttributeRouteModel = new AttributeRouteModel + { + Template = controller.ControllerName + } + }); + } + else + { + var template = selector.AttributeRouteModel?.Template; + template = template.IsNullOrWhiteSpace() ? "{__tenant:regex(^[[a-zA-Z0-9]]+$)}" : AttributeRouteModel.CombineTemplates("{__tenant:regex(^[[a-zA-Z0-9]]+$)}", template.RemovePreFix("/")); + controller.Selectors.Add(new SelectorModel + { + AttributeRouteModel = new AttributeRouteModel + { + Template = template + } + }); + } + } + } +} +``` + +Register the services: + +```cs +public override void ConfigureServices(ServiceConfigurationContext context) +{ + //... + + PostConfigure(options => + { + options.Conventions.Add(new AddTenantRouteToPages()); + }); + + PostConfigure(options => + { + options.Conventions.Add(new AddTenantRouteToControllers()); + }); + + // Configure cookie path to prevent authentication cookie loss + context.Services.ConfigureApplicationCookie(x => + { + x.Cookie.Path = "/"; + }); + //... +} +``` + +After implementing this, you'll notice that all controllers in your Swagger UI will have the `{__tenant}` route added: + +![Swagger UI](./swagger-ui.png) + +## Handling Navigation Links + +To ensure navigation links automatically include tenant information, we need to add middleware that dynamically adds the tenant to the PathBase: + +```cs +public override void OnApplicationInitialization(ApplicationInitializationContext context) +{ + //... + app.Use(async (httpContext, next) => + { + var tenantMatch = Regex.Match(httpContext.Request.Path, "^/([^/.]+)(?:/.*)?$"); + if (tenantMatch.Groups.Count > 1 && !string.IsNullOrEmpty(tenantMatch.Groups[1].Value)) + { + var tenantName = tenantMatch.Groups[1].Value; + if (!tenantName.IsNullOrWhiteSpace()) + { + var tenantStore = httpContext.RequestServices.GetRequiredService(); + var tenantNormalizer = httpContext.RequestServices.GetRequiredService(); + var tenantInfo = await tenantStore.FindAsync(tenantNormalizer.NormalizeName(tenantName)!); + if (tenantInfo != null) + { + if (httpContext.Request.Path.StartsWithSegments(new PathString(tenantName.EnsureStartsWith('/')), out var matchedPath, out var remainingPath)) + { + var originalPath = httpContext.Request.Path; + var originalPathBase = httpContext.Request.PathBase; + httpContext.Request.Path = remainingPath; + httpContext.Request.PathBase = originalPathBase.Add(matchedPath); + try + { + await next(httpContext); + } + finally + { + httpContext.Request.Path = originalPath; + httpContext.Request.PathBase = originalPathBase; + } + return; + } + } + } + } + + await next(httpContext); + }); + app.UseRouting(); + app.MapAbpStaticAssets(); + //... +} +``` + +![ui](ui.png) + +After setting the PathBase, we need to add a custom tenant resolver to extract tenant information from the `PathBase`: + +```cs +public class MyRouteTenantResolveContributor : RouteTenantResolveContributor +{ + public const string ContributorName = "MyRoute"; + + public override string Name => ContributorName; + + protected override Task GetTenantIdOrNameFromHttpContextOrNullAsync(ITenantResolveContext context, HttpContext httpContext) + { + var tenantId = httpContext.GetRouteValue(context.GetAbpAspNetCoreMultiTenancyOptions().TenantKey) ?? httpContext.Request.PathBase.ToString(); + var tenantIdStr = tenantId?.ToString()?.RemovePreFix("/"); + return Task.FromResult(!tenantIdStr.IsNullOrWhiteSpace() ? Convert.ToString(tenantIdStr) : null); + } +} +``` + +Register the MyRouteTenantResolveContributor with the ABP Framework: + +```cs +public override void ConfigureServices(ServiceConfigurationContext context) +{ + //... + Configure(options => + { + options.TenantResolvers.Add(new MyRouteTenantResolveContributor()); + }); + //... +} +``` + +### Modifying abp.appPath + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + //... + context.Services.AddOptions().Configure((options, rootServiceProvider) => + { + var currentTenant = rootServiceProvider.GetRequiredService(); + if (!currentTenant.Name.IsNullOrWhiteSpace()) + { + options.BaseUrl = currentTenant.Name.EnsureStartsWith('/').EnsureEndsWith('/'); + } + }); + + context.Services.RemoveAll(x => x.ServiceType == typeof(IOptions)); + context.Services.Add(ServiceDescriptor.Scoped(typeof(IOptions<>), typeof(OptionsManager<>))); + //... +} +``` + +Browser console output: + +```cs +> https://localhost:44303/acme/ +> abp.appPath +> '/acme/' +``` + +## Summary + +By following these steps, you can implement tenant resolution from routes in the ABP Framework and handle navigation links appropriately. This approach provides a clean and maintainable way to manage multi-tenancy in your application. + + +## References + +- [ABP Multi-Tenancy](https://docs.abp.io/en/abp/latest/Multi-Tenancy) +- [Routing in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing) +- [HTML base tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) diff --git a/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/cover.png b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/cover.png new file mode 100644 index 0000000000..ebd7978ac8 Binary files /dev/null and b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/cover.png differ diff --git a/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/swagger-ui.png b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/swagger-ui.png new file mode 100644 index 0000000000..72da9bd571 Binary files /dev/null and b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/swagger-ui.png differ diff --git a/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/ui.png b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/ui.png new file mode 100644 index 0000000000..3ae3f6650c Binary files /dev/null and b/docs/en/Community-Articles/2025-05-19-RouteTenantResolveContributor/ui.png differ diff --git a/docs/en/Community-Articles/2025-06-10-bootcamp/post.md b/docs/en/Community-Articles/2025-06-10-bootcamp/post.md new file mode 100644 index 0000000000..98192235fa --- /dev/null +++ b/docs/en/Community-Articles/2025-06-10-bootcamp/post.md @@ -0,0 +1,38 @@ +You Asked, We Delivered: Introducing Our New Training Bootcamp\! + +Over the past months we’ve heard from countless freelancers, individuals and small teams asking for a focused, high-impact training without the overwhelming commitment or high costs of traditional bootcamps. So here we are\! + +We're excited to introduce **ABP Bootcamp: Mastering Infrastructure & Features**, a full training experience designed to help developers level up fast with practical knowledge they can apply immediately. + +This live, instructor-led program delivers four days of in-depth, real-world training on ABP’s infrastructure and core features. + +**Bootcamp Details** + +Dates: July 1,2,3,4 2025 +Time: 17:00-19:00 (UTC) each day +Format: Live, online sessions +Price: $399 (discounted $799) +Seats: Limited to a small group + +### **What You’ll Learn** + +By the end of this bootcamp, you’ll have: + +\-A solid understanding of ABP’s infrastructure, systems, and design patterns +\-Practical experience with features like dependency injection, configuration, logging, and localization +\-The ability to implement email templating, event bus, caching, and custom settings in real applications +\-Knowledge of best practices for building scalable, maintainable, and high-performance solutions with ABP + +### **Who It’s For** + +This bootcamp is ideal for: + +\-Developers and freelancers using ABP in their daily work +\-Teams looking to speed up onboarding and improve development efficiency +\-Anyone who wants practical ABP knowledge without committing to long-format training programs + +### **Reserve Your Spot** + +Seats are limited to keep the experience interactive and personalized. With the current 50% discount, this is the most accessible way to gain hands-on ABP experience with expert guidance. + +**Registration is now open. Secure your place today and master the infrastructure that powers ABP. Register here: [https://docs.google.com/forms/d/e/1FAIpQLSckMZChdqIJIuWiEvg\_KsSDmrxagRdc5WBYceAemHLrmT1oiA/viewform](https://docs.google.com/forms/d/e/1FAIpQLSckMZChdqIJIuWiEvg_KsSDmrxagRdc5WBYceAemHLrmT1oiA/viewform)** diff --git a/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg new file mode 100644 index 0000000000..63d1fc9ab6 Binary files /dev/null and b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/mongo-db.jpg differ diff --git a/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md new file mode 100644 index 0000000000..ddae9a3704 --- /dev/null +++ b/docs/en/Community-Articles/2025-06-12-fix-mongodb-guid-abp-v9.2.0-upgrade/post.md @@ -0,0 +1,93 @@ +# Solving MongoDB GUID Issues After an ABP Framework Upgrade + +So, you've just upgraded your ABP Framework application to a newer version (like v9.2.0+) and suddenly, your application can't read data from its MongoDB database. You're seeing strange deserialization errors, especially related to `Guid` types. What's going on? + +You've likely run into a classic compatibility issue with the MongoDB .NET driver. + +### The Problem: Legacy vs. Standard GUIDs + +Here's the short version: + +* **Old MongoDB Drivers** (used in older ABP versions) stored `Guid` values in a format called `CSharpLegacy`. +* **New MongoDB Drivers** (v3.0+), now default to a universal `Standard` format. + +When your newly upgraded app tries to read old data, the new driver expects the `Standard` format but finds `CSharpLegacy`. The byte orders don't match, and... boom. Deserialization fails. + +The ABP Framework team has an excellent official guide covering this topic in detail. We highly recommend reading their **[MongoDB Driver 2 to 3 Migration Guide](https://abp.io/docs/latest/release-info/migration-guides/MongoDB-Driver-2-to-3)** for a full understanding. + +Our tip below serves as a fast, application-level fix if you need to get your system back online quickly without performing a full data migration. + +### The Quick Fix: Tell the Driver to Use the Old Format + +Instead of changing your data, you can simply tell the new driver to continue using the old `CSharpLegacy` format for all `Guid` and `Guid?` properties. This provides immediate backward compatibility without touching your database. + +It’s a simple, two-step process. + +#### Step 1: Create a Custom Convention + +First, create this class in your `.MongoDb` project. It tells the serializer how to handle `Guid` types. + +```csharp +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.Serializers; +using System; + +public class LegacyGuidConvention : ConventionBase, IMemberMapConvention +{ + public void Apply(BsonMemberMap memberMap) + { + if (memberMap.MemberType == typeof(Guid)) + { + memberMap.SetSerializer(new GuidSerializer(GuidRepresentation.CSharpLegacy)); + } + else if (memberMap.MemberType == typeof(Guid?)) + { + var guidSerializer = new GuidSerializer(GuidRepresentation.CSharpLegacy); + var nullableGuidSerializer = new NullableSerializer(guidSerializer); + memberMap.SetSerializer(nullableGuidSerializer); + } + } +} +``` + +#### Step 2: Register the Convention at Startup + +Now, register this convention in your `YourProjectMongoDbModule.cs` file. Add this code to the top of the `ConfigureServices` method. This ensures your rule is applied globally as soon as the application starts. + +```csharp +using Volo.Abp.Modularity; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; + +public class YourProjectMongoDbModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + // Fix Start + var conventionPack = new ConventionPack { new LegacyGuidConvention() }; + ConventionRegistry.Register( + "LegacyGuidConvention", + conventionPack, + t => true); // Apply to all types + // Fix End + + // ... Your existing ConfigureServices code + } +} +``` + +### An Alternative to Full Data Migration + +It's important to note that the method described here is an **application-level fix**. It's a fantastic alternative to performing a full data migration, which involves writing scripts to convert every legacy GUID in your database. + +If you are interested in the more permanent, data-centric approach, the ABP.IO community has a detailed guide on [**Migrating MongoDB GUIDs from Legacy to Standard Format**](https://abp.io/community/articles/migrating-mongodb-guids-from-legacy-to-standard-format-mongodb-v2-to-v3-dqwybdtw). + +Our quick fix is ideal for getting a system back online fast or when a database migration is too complex. The full migration is better for long-term standards compliance. Choose the path that best fits your project's needs! + +### That's It! + +Restart your application, and the errors should be gone. Your app can now correctly read its old `Guid` data, and it will continue to write new data in the same legacy format, ensuring consistency. + +This approach is a lifesaver for existing projects, saving you from a risky and time-consuming data migration. For brand-new projects, you might consider starting with the `Standard` representation, but for everything else, this is a clean and effective fix. Happy coding! diff --git a/docs/en/Community-Articles/2025-06-13-modular-docker-container-management/modular-docker-container-management.md b/docs/en/Community-Articles/2025-06-13-modular-docker-container-management/modular-docker-container-management.md new file mode 100644 index 0000000000..3f6e061c14 --- /dev/null +++ b/docs/en/Community-Articles/2025-06-13-modular-docker-container-management/modular-docker-container-management.md @@ -0,0 +1,113 @@ +# 🚀 New in ABP Studio: Modular Docker Container Management + +We're excited to announce a new improvement to Docker integration in **ABP Studio**! +With the latest update, you can now manage Docker containers **individually**, add or remove them dynamically, and launch them **either separately or collectively** — all within the Studio. + +![solution-runner-containers](solution-runner-containers.png) + +------ + +## 🔄 What Has Changed? + +In previous versions, Docker dependencies were handled using a **single `docker-compose.override.yml` file**, which was **automatically generated** when creating a new solution if it is needed. + +By default, this file included common development dependencies like PostgreSQL, Redis, RabbitMQ, etc., and was executed through a predefined script named `docker-dependencies` in the Solution Runner. + +While this approach worked well for simple setups, it had some limitations: + +- All services were bundled into a **single compose file**. +- Adding or removing services required modifying this central file. +- It wasn't possible to **start or stop individual containers independently**. + +------ + +## ✅ What's New? + +With the latest ABP Studio update: + +- Each Docker container can now be defined in its **own `docker-compose` file**. +- Compose files can be **added or removed** from the Studio UI. +- Containers can be: + - **Started or stopped individually**. + - **Started/stopped in bulk**. +- The **Solution Runner** recognizes Docker containers and can run them alongside application projects. + +------ + +## ⚠️ Important Notes Before You Start + +### Required: Use `container_name` for Docker Service Matching + +When working with the new modular Docker system in ABP Studio, each service **must define a `container_name`**. +This name is used by ABP Studio to **identify and map** Docker containers to their corresponding service entries in the Studio UI. + +#### Why is this mandatory? + +- ABP Studio relies on `container_name` to: + - Detect whether the service is stopped or continue running. + - Perform **start**, **stop**, and **status check** operations reliably. + - Match Studio UI entries with actual running Docker containers. +- Without a `container_name`, container discovery may fail and **service management features might not work as expected**. + +#### Example: + +``` +services: + redis: + container_name: redis + image: redis:7 + ports: + - "6379:6379" + networks: + - my-network +``` + +> If you do **not** define `container_name`, ABP Studio will be unable to track or control the service properly. + +------ + +## 📥 Migrating from the Old System + +If you're using the old method with a centralized compose file: + +Before: + +``` +docker-compose -f docker-compose.override.yml up -d +``` + +Now: + +1. Create separate `docker-compose` files for each service + (e.g., `docker-compose.postgres.yml`, `docker-compose.redis.yml`). +2. Go to the **Solution Runner tab in ABP Studio**. +3. Use the **“Add Docker Service”** option in Studio to register each file. +4. Optionally remove or archive the old monolithic compose file. + +> If your original `docker-compose.override.yml` contains multiple services, you can split it into individual files — Docker Compose and ABP Studio both support modular composition. + +------ + +## ⚙️ Advanced: Shared Network + +If your containers need to communicate over a shared network, you can define an external network in each compose file like this: + +``` +networks: + my-network: + external: true +``` + +ABP Studio automatically creates the network if they do no exist. But if you like you can create the network once using: + +``` +docker network create my-network +``` + +------ + +## 📚 Additional Resources + +- Docker Compose Documentation +- ABP Studio Documentation (link to updated docs when ready) +- [Report Issues on GitHub](https://github.com/abpframework/abp/issues) \ No newline at end of file diff --git a/docs/en/Community-Articles/2025-06-13-modular-docker-container-management/solution-runner-containers.png b/docs/en/Community-Articles/2025-06-13-modular-docker-container-management/solution-runner-containers.png new file mode 100644 index 0000000000..ef6de78c1f Binary files /dev/null and b/docs/en/Community-Articles/2025-06-13-modular-docker-container-management/solution-runner-containers.png differ diff --git a/docs/en/cli/differences-between-old-and-new-cli.md b/docs/en/cli/differences-between-old-and-new-cli.md index 095d4fc316..ee4e06a543 100644 --- a/docs/en/cli/differences-between-old-and-new-cli.md +++ b/docs/en/cli/differences-between-old-and-new-cli.md @@ -16,8 +16,6 @@ This change allows you to create your application with the new templating system > If you installed [ABP Studio](../studio/index.md) recently, then you may skip this section because ABP Studio automatically uninstalls the old CLI and replaces it with the new CLI. Therefore, you don't need to manually switch to the new ABP CLI. -> 🛈 The new ABP CLI is in the beta version for now. If you have any issues, you can always use the old ABP CLI by following the instructions in the _Using the old ABP CLI_ section below. - ABP CLI has two variations, which are `Volo.Abp.Studio.Cli` (new) and `Volo.Abp.Cli` (old). If you are using ABP earlier than v8.2+, then you are probably using the old ABP CLI and can easily switch to the new CLI by simply uninstalling the old one and installing the new CLI by executing the commands below: ```bash diff --git a/docs/en/cli/index.md b/docs/en/cli/index.md index 1e5f7a1711..60d4e3ff0b 100644 --- a/docs/en/cli/index.md +++ b/docs/en/cli/index.md @@ -889,6 +889,7 @@ Some features of the CLI requires to be logged in to ABP Platform. The login com ```bash abp login # Opens a default browser to log in to ABP Platform via abp.io abp login --device # Use device login flow +abp login username -p ****** --password # Use user password login ``` A new login with an already active session overwrites the previous session. diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 2ede960b12..4b5e2908a6 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -83,47 +83,59 @@ { "text": "Overview", "path": "tutorials/book-store", - "isIndex": true + "isIndex": true, + "isInSeries": true }, { "text": "1: Creating the Server Side", - "path": "tutorials/book-store/part-01.md" + "path": "tutorials/book-store/part-01.md", + "isInSeries": true + }, { "text": "2: The Book List Page", - "path": "tutorials/book-store/part-02.md" + "path": "tutorials/book-store/part-02.md", + "isInSeries": true }, { "text": "3: Creating, Updating and Deleting Books", - "path": "tutorials/book-store/part-03.md" + "path": "tutorials/book-store/part-03.md", + "isInSeries": true }, { "text": "4: Integration Tests", - "path": "tutorials/book-store/part-04.md" + "path": "tutorials/book-store/part-04.md", + "isInSeries": true }, { "text": "5: Authorization", - "path": "tutorials/book-store/part-05.md" + "path": "tutorials/book-store/part-05.md", + "isInSeries": true }, { "text": "6: Authors: Domain Layer", - "path": "tutorials/book-store/part-06.md" + "path": "tutorials/book-store/part-06.md", + "isInSeries": true }, { "text": "7: Authors: Database Integration", - "path": "tutorials/book-store/part-07.md" + "path": "tutorials/book-store/part-07.md", + "isInSeries": true }, { "text": "8: Authors: Application Layer", - "path": "tutorials/book-store/part-08.md" + "path": "tutorials/book-store/part-08.md", + "isInSeries": true }, { "text": "9: Authors: User Interface", - "path": "tutorials/book-store/part-09.md" + "path": "tutorials/book-store/part-09.md", + "isInSeries": true }, { "text": "10: Book to Author Relation", - "path": "tutorials/book-store/part-10.md" + "path": "tutorials/book-store/part-10.md", + "isInSeries": true } ] }, @@ -135,27 +147,33 @@ { "text": "Overview", "path": "tutorials/book-store-with-abp-suite", - "isIndex": true + "isIndex": true, + "isInSeries": true }, { "text": "1: Creating the Solution", - "path": "tutorials/book-store-with-abp-suite/part-01.md" + "path": "tutorials/book-store-with-abp-suite/part-01.md", + "isInSeries": true }, { "text": "2: Creating the Books", - "path": "tutorials/book-store-with-abp-suite/part-02.md" + "path": "tutorials/book-store-with-abp-suite/part-02.md", + "isInSeries": true }, { "text": "3: Creating the Authors", - "path": "tutorials/book-store-with-abp-suite/part-03.md" + "path": "tutorials/book-store-with-abp-suite/part-03.md", + "isInSeries": true }, { "text": "4: Book to Author Relation", - "path": "tutorials/book-store-with-abp-suite/part-04.md" + "path": "tutorials/book-store-with-abp-suite/part-04.md", + "isInSeries": true }, { "text": "5: Customizing the Generated Code", - "path": "tutorials/book-store-with-abp-suite/part-05.md" + "path": "tutorials/book-store-with-abp-suite/part-05.md", + "isInSeries": true } ] }, @@ -614,7 +632,7 @@ "path": "framework/infrastructure/blob-storing/google.md" }, { - "text": "Bunny Provider", + "text": "Bunny.Net Provider", "path": "framework/infrastructure/blob-storing/bunny.md" }, { @@ -2070,19 +2088,23 @@ "items": [ { "text": "Deploy to Azure Web App Service", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md", + "isInSeries": true }, { "text": "Creating an Azure Web App Service Environment", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md", + "isInSeries": true }, { "text": "Customizing the Configuration of Your ABP Application", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md", + "isInSeries": true }, { "text": "Deploying Application With GitHub Actions", - "path": "solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md" + "path": "solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md", + "isInSeries": true } ] }, diff --git a/docs/en/framework/api-development/static-csharp-clients.md b/docs/en/framework/api-development/static-csharp-clients.md index c8eaea4231..b3cf80fcfc 100644 --- a/docs/en/framework/api-development/static-csharp-clients.md +++ b/docs/en/framework/api-development/static-csharp-clients.md @@ -47,7 +47,7 @@ Implement this class in your service application. You can use [auto API controll First, add [Volo.Abp.Http.Client](https://www.nuget.org/packages/Volo.Abp.Http.Client) nuget package to your client project: ```` -Install-Package Volo.Abp.Http.Client +dotnet add package Volo.Abp.Http.Client ```` Then add `AbpHttpClientModule` dependency to your module: diff --git a/docs/en/framework/api-development/swagger.md b/docs/en/framework/api-development/swagger.md index 1699e4d0d2..fb27bcf27b 100644 --- a/docs/en/framework/api-development/swagger.md +++ b/docs/en/framework/api-development/swagger.md @@ -29,7 +29,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Swashbuckle](https://www.nuget.org/packages/Volo.Abp.Swashbuckle) NuGet package to your `Web` or `HttpApi.Host` project: - `Install-Package Volo.Abp.Swashbuckle` + `dotnet add package Volo.Abp.Swashbuckle` 2. Add the `AbpSwashbuckleModule` to the dependency list of your module: diff --git a/docs/en/framework/fundamentals/fluent-validation.md b/docs/en/framework/fundamentals/fluent-validation.md index d3af69bae9..207cddcbd3 100644 --- a/docs/en/framework/fundamentals/fluent-validation.md +++ b/docs/en/framework/fundamentals/fluent-validation.md @@ -21,7 +21,7 @@ If you want to manually install; 1. Add the [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet package to your project: ```` - Install-Package Volo.Abp.FluentValidation + dotnet add package Volo.Abp.FluentValidation ```` 2. Add the `AbpFluentValidationModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/background-jobs/hangfire.md b/docs/en/framework/infrastructure/background-jobs/hangfire.md index 293f03494c..f5991ee19b 100644 --- a/docs/en/framework/infrastructure/background-jobs/hangfire.md +++ b/docs/en/framework/infrastructure/background-jobs/hangfire.md @@ -25,7 +25,7 @@ If you want to manually install; 1. Add the [Volo.Abp.BackgroundJobs.HangFire](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.HangFire) NuGet package to your project: ```` - Install-Package Volo.Abp.BackgroundJobs.HangFire + dotnet add package Volo.Abp.BackgroundJobs.HangFire ```` 2. Add the `AbpBackgroundJobsHangfireModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/background-jobs/index.md b/docs/en/framework/infrastructure/background-jobs/index.md index 5aa58a7d3e..af0c33de21 100644 --- a/docs/en/framework/infrastructure/background-jobs/index.md +++ b/docs/en/framework/infrastructure/background-jobs/index.md @@ -134,6 +134,25 @@ namespace MyProject } ``` +##### Custom Job Name + +You can configure `GetBackgroundJobName` delegate of the `AbpBackgroundJobOptions` to change the default job name. + +```csharp +Configure(options => +{ + options.GetBackgroundJobName = (jobType) => + { + if (jobTyep == typeof(EmailSendingArgs)) + { + return "emails"; + } + + return BackgroundJobNameAttribute.GetName(jobType); + }; +}); +``` + ### Queue a Job Item Now, you can queue an email sending job using the `IBackgroundJobManager` service: diff --git a/docs/en/framework/infrastructure/background-jobs/quartz.md b/docs/en/framework/infrastructure/background-jobs/quartz.md index 93cf5d53bf..1b18fd36ae 100644 --- a/docs/en/framework/infrastructure/background-jobs/quartz.md +++ b/docs/en/framework/infrastructure/background-jobs/quartz.md @@ -25,7 +25,7 @@ If you want to manually install; 1. Add the [Volo.Abp.BackgroundJobs.Quartz](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.Quartz) NuGet package to your project: ```` - Install-Package Volo.Abp.BackgroundJobs.Quartz + dotnet add package Volo.Abp.BackgroundJobs.Quartz ```` 2. Add the `AbpBackgroundJobsQuartzModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/background-workers/hangfire.md b/docs/en/framework/infrastructure/background-workers/hangfire.md index 4612e15b06..7fec8be273 100644 --- a/docs/en/framework/infrastructure/background-workers/hangfire.md +++ b/docs/en/framework/infrastructure/background-workers/hangfire.md @@ -23,7 +23,7 @@ If you want to manually install; 1. Add the [Volo.Abp.BackgroundWorkers.Hangfire](https://www.nuget.org/packages/Volo.Abp.BackgroundWorkers.Hangfire) NuGet package to your project: ```` - Install-Package Volo.Abp.BackgroundWorkers.Hangfire + dotnet add package Volo.Abp.BackgroundWorkers.Hangfire ```` 2. Add the `AbpBackgroundWorkersHangfireModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/background-workers/index.md b/docs/en/framework/infrastructure/background-workers/index.md index 884ea60c25..6ab88a9e53 100644 --- a/docs/en/framework/infrastructure/background-workers/index.md +++ b/docs/en/framework/infrastructure/background-workers/index.md @@ -41,6 +41,8 @@ Start your worker in the `StartAsync` (which is called when the application begi Assume that we want to make a user passive, if the user has not logged in to the application in last 30 days. `AsyncPeriodicBackgroundWorkerBase` class simplifies to create periodic workers, so we will use it for the example below: +> You can use `CronExpression` property to set the cron expression for the background worker if you will use the [Hangfire Background Worker Manager](./hangfire.md) or [Quartz Background Worker Manager](./quartz.md). + ````csharp public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase { @@ -52,6 +54,7 @@ public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase serviceScopeFactory) { Timer.Period = 600000; //10 minutes + //CronExpression = "0 0/10 * * * ?"; //Run every 10 minutes, Only for Quartz or Hangfire integration. } protected async override Task DoWorkAsync( diff --git a/docs/en/framework/infrastructure/background-workers/quartz.md b/docs/en/framework/infrastructure/background-workers/quartz.md index 663fe22a7f..909371adb0 100644 --- a/docs/en/framework/infrastructure/background-workers/quartz.md +++ b/docs/en/framework/infrastructure/background-workers/quartz.md @@ -21,7 +21,7 @@ If you want to manually install; 1. Add the [Volo.Abp.BackgroundWorkers.Quartz](https://www.nuget.org/packages/Volo.Abp.BackgroundWorkers.Quartz) NuGet package to your project: ```` - Install-Package Volo.Abp.BackgroundWorkers.Quartz + dotnet add package Volo.Abp.BackgroundWorkers.Quartz ```` 2. Add the `AbpBackgroundWorkersQuartzModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/image-manipulation.md b/docs/en/framework/infrastructure/image-manipulation.md index 7ab8dc562e..a1ee6e1584 100644 --- a/docs/en/framework/infrastructure/image-manipulation.md +++ b/docs/en/framework/infrastructure/image-manipulation.md @@ -22,7 +22,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Imaging.Abstractions](https://www.nuget.org/packages/Volo.Abp.Imaging.Abstractions) NuGet package to your project: ``` -Install-Package Volo.Abp.Imaging.Abstractions +dotnet add package Volo.Abp.Imaging.Abstractions ``` 2. Add the `AbpImagingAbstractionsModule` to the dependency list of your module: @@ -240,7 +240,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Imaging.MagickNet](https://www.nuget.org/packages/Volo.Abp.Imaging.MagickNet) NuGet package to your project: ``` -Install-Package Volo.Abp.Imaging.MagickNet +dotnet add package Volo.Abp.Imaging.MagickNet ``` 2. Add `AbpImagingMagickNetModule` to your [module](../architecture/modularity/basics.md)'s dependency list: @@ -284,7 +284,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Imaging.ImageSharp](https://www.nuget.org/packages/Volo.Abp.Imaging.ImageSharp) NuGet package to your project: ``` -Install-Package Volo.Abp.Imaging.ImageSharp +dotnet add package Volo.Abp.Imaging.ImageSharp ``` 2. Add `AbpImagingImageSharpModule` to your [module](../architecture/modularity/basics.md)'s dependency list: @@ -350,7 +350,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Imaging.AspNetCore](https://www.nuget.org/packages/Volo.Abp.Imaging.AspNetCore) NuGet package to your project: ``` -Install-Package Volo.Abp.Imaging.AspNetCore +dotnet add package Volo.Abp.Imaging.AspNetCore ``` 2. Add `AbpImagingAspNetCoreModule` to your [module](../architecture/modularity/basics.md)'s dependency list: diff --git a/docs/en/framework/infrastructure/sms-sending.md b/docs/en/framework/infrastructure/sms-sending.md index e6bc9135e5..ef2a86445f 100644 --- a/docs/en/framework/infrastructure/sms-sending.md +++ b/docs/en/framework/infrastructure/sms-sending.md @@ -26,7 +26,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Sms](https://www.nuget.org/packages/Volo.Abp.Sms) NuGet package to your project: ``` -Install-Package Volo.Abp.Sms +dotnet add package Volo.Abp.Sms ``` 2. Add the `AbpSmsModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/string-encryption.md b/docs/en/framework/infrastructure/string-encryption.md index 5f47e246ef..bb398425f6 100644 --- a/docs/en/framework/infrastructure/string-encryption.md +++ b/docs/en/framework/infrastructure/string-encryption.md @@ -22,7 +22,7 @@ If you want to manually install; 1. Add the [Volo.Abp.Security](https://www.nuget.org/packages/Volo.Abp.Security) NuGet package to your project: - `Install-Package Volo.Abp.Security` + `dotnet add package Volo.Abp.Security` 2. Add the `AbpSecurityModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/text-templating/razor.md b/docs/en/framework/infrastructure/text-templating/razor.md index 1d17d4337e..77db5467aa 100644 --- a/docs/en/framework/infrastructure/text-templating/razor.md +++ b/docs/en/framework/infrastructure/text-templating/razor.md @@ -25,7 +25,7 @@ If you want to manually install; 1. Add the [Volo.Abp.TextTemplating.Razor](https://www.nuget.org/packages/Volo.Abp.TextTemplating.Razor) NuGet package to your project: ```` -Install-Package Volo.Abp.TextTemplating.Razor +dotnet add package Volo.Abp.TextTemplating.Razor ```` 2. Add the `AbpTextTemplatingRazorModule` to the dependency list of your module: diff --git a/docs/en/framework/infrastructure/text-templating/scriban.md b/docs/en/framework/infrastructure/text-templating/scriban.md index bd54914411..99d160ce85 100644 --- a/docs/en/framework/infrastructure/text-templating/scriban.md +++ b/docs/en/framework/infrastructure/text-templating/scriban.md @@ -19,7 +19,7 @@ If you want to manually install; 1. Add the [Volo.Abp.TextTemplating.Scriban](https://www.nuget.org/packages/Volo.Abp.TextTemplating.Scriban) NuGet package to your project: ```` -Install-Package Volo.Abp.TextTemplating.Scriban +dotnet add package Volo.Abp.TextTemplating.Scriban ```` 2. Add the `AbpTextTemplatingScribanModule` to the dependency list of your module: diff --git a/docs/en/framework/real-time/signalr.md b/docs/en/framework/real-time/signalr.md index d6cbbfbada..2d2710c77d 100644 --- a/docs/en/framework/real-time/signalr.md +++ b/docs/en/framework/real-time/signalr.md @@ -27,7 +27,7 @@ If you want to manually install; 1. Add the [Volo.Abp.AspNetCore.SignalR](https://www.nuget.org/packages/Volo.Abp.AspNetCore.SignalR) NuGet package to your project: ``` - Install-Package Volo.Abp.AspNetCore.SignalR + dotnet add package Volo.Abp.AspNetCore.SignalR ``` Or use the Visual Studio NuGet package management UI to install it. diff --git a/docs/en/get-started/empty-aspnet-core-application.md b/docs/en/get-started/empty-aspnet-core-application.md index b0457db71b..95861719ce 100644 --- a/docs/en/get-started/empty-aspnet-core-application.md +++ b/docs/en/get-started/empty-aspnet-core-application.md @@ -104,7 +104,7 @@ Replacing ASP.NET Core's DI system by Autofac and integrating to ABP is pretty e 1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package ```` -Install-Package Volo.Abp.Autofac +dotnet add package Volo.Abp.Autofac ```` 2. Add the ``AbpAutofacModule`` Dependency diff --git a/docs/en/get-started/layered-web-application.md b/docs/en/get-started/layered-web-application.md index 8d4e540292..3f1fce475b 100644 --- a/docs/en/get-started/layered-web-application.md +++ b/docs/en/get-started/layered-web-application.md @@ -25,8 +25,6 @@ First things first! Let's setup your development environment before creating the ## Creating a New Solution -> This document uses [ABP Studio](../studio/index.md) to create new ABP solutions. **ABP Studio** is in the beta version now. If you have any issues, you can use the [ABP CLI](../cli/index.md) to create new solutions. You can also use the [getting started page](https://abp.io/get-started) to easily build ABP CLI commands for new project creations. - > ABP startup solution templates have many options for your specific needs. If you don't understand an option that probably means you don't need it. We selected common defaults for you, so you can leave these options as they are. Assuming that you have [installed and logged in](../studio/installation.md) to the application, you should see the following screen when you open ABP Studio: diff --git a/docs/en/get-started/microservice.md b/docs/en/get-started/microservice.md index cca7d3c02e..47c1a2a44e 100644 --- a/docs/en/get-started/microservice.md +++ b/docs/en/get-started/microservice.md @@ -21,8 +21,6 @@ First things first! Let's setup your development environment before creating the ## Creating a New Solution -> 🛈 This document uses [ABP Studio](../studio/index.md) to create new ABP solutions. **ABP Studio** is in the beta version now. If you have any issues, you can use the [ABP CLI](../cli/index.md) to create new solutions. You can also use the [getting started page](https://abp.io/get-started) to easily build ABP CLI commands for new project creations. - > ABP startup solution templates have many options for your specific needs. If you don't understand an option that probably means you don't need it. We selected common defaults for you, so you can leave these options as they are. Assuming that you have [installed and logged in](../studio/installation.md) to the application, you should see the following screen when you open ABP Studio: diff --git a/docs/en/images/samples-cms-kit.png b/docs/en/images/samples-cms-kit.png new file mode 100644 index 0000000000..0c4e3e5877 Binary files /dev/null and b/docs/en/images/samples-cms-kit.png differ diff --git a/docs/en/images/samples-easycrm.png b/docs/en/images/samples-easycrm.png new file mode 100644 index 0000000000..72924ae3e7 Binary files /dev/null and b/docs/en/images/samples-easycrm.png differ diff --git a/docs/en/images/samples-eshoponabp.png b/docs/en/images/samples-eshoponabp.png new file mode 100644 index 0000000000..f8e22fff7d Binary files /dev/null and b/docs/en/images/samples-eshoponabp.png differ diff --git a/docs/en/images/samples-eventhub.png b/docs/en/images/samples-eventhub.png new file mode 100644 index 0000000000..548412d62c Binary files /dev/null and b/docs/en/images/samples-eventhub.png differ diff --git a/docs/en/modules/audit-logging-pro.md b/docs/en/modules/audit-logging-pro.md index ef609e5422..cb32ff52fe 100644 --- a/docs/en/modules/audit-logging-pro.md +++ b/docs/en/modules/audit-logging-pro.md @@ -9,6 +9,8 @@ This module implements the Audit Logging system of an application; * See all changes of entities and filter entity change logs. * View details of an entity change. * View all changes of an entity. +* Export audit logs and entity changes to Excel. +* Receive email notifications for completed or failed exports. * This module also defines reusable "Average Execution Duration Per Day" and "Error Rate" widgets. * Periodic clean up of audit logs. @@ -56,6 +58,10 @@ You can view details of an audit log by clicking the magnifier icon on each audi * **Actions:** This tab shows list of actions (controller actions and application service method calls with their parameters) executed during a web request. * **Changes:** This tab shows changed entities during the web request. +##### Export to Excel + +You can export audit logs to Excel by clicking the "Export to Excel" button in the toolbar. If the result set is small (less than a configurable threshold), the file will be generated and downloaded immediately. For larger result sets, the export will be processed as a background job and you'll receive an email with a download link once the export is completed. + #### Entity Changes Entity changes tab is used to list, view and filter entity change logs. @@ -80,6 +86,10 @@ You can view details of all changes of an entity by clicking the "Full Change Hi ![audit-logging-module-full-entity-change-details-modal](../images/audit-logging-module-full-entity-change-details-modal.png) +##### Export to Excel + +You can export entity changes to Excel by clicking the "Export to Excel" button in the toolbar. Similar to audit logs export, for large datasets the export will be processed as a background job and you'll receive an email notification once completed. + #### Audit Log Settings The *Audit Log* settings tab is used to configure audit log settings. You can enable or disable the clean up service system wide. This way, you can shut down the clean up service for all tenants and host. If the system wide clean up service is enabled, you can configure the global *Expired Item Deletion Period* for all tenants and host. @@ -121,11 +131,32 @@ To see `AbpAuditingOptions` properties, please see its [documentation](../framew Configure(options => { options.Period = (int)TimeSpan.FromSeconds(30).TotalMilliseconds; + options.CronExpression = "0 23 * * *"; // This Cron expression only works if Hangfire or Quartz is used for background workers. }); ``` The *Period* doesn't mean the *Expired Item Deletion Period*. It's the period of the worker to run clean up service system wide. The default value is 1 day. +### AuditLogExcelFileOptions + +`AuditLogExcelFileOptions` can be configured in the UI layer, within the `ConfigureServices` method of your [module](../framework/architecture/modularity/basics.md). Example: + +```csharp +Configure(options => +{ + options.FileRetentionHours = 24; // How long to keep files before cleanup (default: 24 hours) + options.DownloadBaseUrl = "https://yourdomain.com"; // Base URL for download links in emails + options.ExcelFileCleanupOptions.Period = (int)TimeSpan.FromHours(24).TotalMilliseconds; // Interval of the cleanup worker (default: 24 hours) + options.ExcelFileCleanupOptions.CronExpression = "0 23 * * *"; // This Cron expression only works if Hangfire or Quartz is used for background workers. +}); +``` + +> Note: The `FileRetentionHours` value determines when files become eligible for deletion, but actual deletion depends on when the cleanup worker runs. If the worker hasn't run after the retention period expires, files will remain accessible. Therefore, `FileRetentionHours` represents the minimum intended retention time, but the actual retention time might be longer depending on the worker's execution schedule. + +These settings control where Excel export files are stored, how long they are kept before automatic cleanup, and what base URL is used in email download links. + +> You must use a valid [BLOB Storage Provider](https://abp.io/docs/latest/framework/infrastructure/blob-storing#blob-storage-providers) to use this feature. + ## Internals ### Domain layer @@ -156,6 +187,15 @@ Following custom repositories are defined for this module: * `AuditLogsAppService` (implements `IAuditLogsAppService`): Implements the use cases of the audit logs management UI. +#### Email Templates + +The module provides email templates for notifications: + +* `AuditLogExportCompleted`: Sent when an audit log export is successfully completed, including a download link. +* `AuditLogExportFailed`: Sent when an audit log export fails, including error details. +* `EntityChangeExportCompleted`: Sent when an entity change export is successfully completed, including a download link. +* `EntityChangeExportFailed`: Sent when an entity change export fails, including error details. + ### Database providers #### Common diff --git a/docs/en/modules/docs.md b/docs/en/modules/docs.md index 69de3362a6..b564980ba3 100644 --- a/docs/en/modules/docs.md +++ b/docs/en/modules/docs.md @@ -73,25 +73,25 @@ Or you can also manually install nuget package to each project: * Install [Volo.Docs.Domain](https://www.nuget.org/packages/Volo.Docs.Domain/) nuget package to `Acme.MyProject.Domain` project. ```bash - Install-Package Volo.Docs.Domain + dotnet add package Volo.Docs.Domain ``` * Install [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) nuget package to `Acme.MyProject.EntityFrameworkCore` project. ```bash - Install-Package Volo.Docs.EntityFrameworkCore + dotnet add package Volo.Docs.EntityFrameworkCore ``` * Install [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) nuget package to `Acme.MyProject.Application` project. ```bash - Install-Package Volo.Docs.Application + dotnet add package Volo.Docs.Application ``` * Install [Volo.Docs.Web](https://www.nuget.org/packages/Volo.Docs.Domain/) nuget package to `Acme.MyProject.Web` project. ```bash - Install-Package Volo.Docs.Web + dotnet add package Volo.Docs.Web ``` ##### 3.2.1- Adding Module Dependencies diff --git a/docs/en/modules/virtual-file-explorer.md b/docs/en/modules/virtual-file-explorer.md index 21bccfd999..3157198c30 100644 --- a/docs/en/modules/virtual-file-explorer.md +++ b/docs/en/modules/virtual-file-explorer.md @@ -24,7 +24,7 @@ Or you can also manually install nuget package to `Acme.MyProject.Web` project: * Install [Volo.Abp.VirtualFileExplorer.Web](https://www.nuget.org/packages/Volo.Abp.VirtualFileExplorer.Web/) nuget package to `Acme.MyProject.Web` project. - `Install-Package Volo.Abp.VirtualFileExplorer.Web` + `dotnet add package Volo.Abp.VirtualFileExplorer.Web` ##### 2.1- Adding Module Dependencies diff --git a/docs/en/release-info/migration-guides/abp-9-3.md b/docs/en/release-info/migration-guides/abp-9-3.md new file mode 100644 index 0000000000..3d085eba7d --- /dev/null +++ b/docs/en/release-info/migration-guides/abp-9-3.md @@ -0,0 +1,46 @@ +# ABP Version 9.3 Migration Guide + +This document is a guide for upgrading ABP v9.2 solutions to ABP v9.3. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. + +## Updated `RabbitMQ.Client` to `7.x` + +In this version, we updated `RabbitMQ.Client` to `7.1.2`. [This is a major version update](https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/main/v7-MIGRATION.md) that brings significant improvements to the library: + +1. Full async/await support throughout the entire public API and internals +2. Improved performance and resource utilization +3. Better error handling and connection management + +With this update, you should update your method calls to use the new async/await support (in the RabbitMQ related provider packages). There are some method signature changes and new API calls, aligned with the new API. You can see the internal changes we made in [#22510](https://github.com/abpframework/abp/pull/22510) and make the relevant changes in your code. + +## Docs Module: Export as PDF + +In this version, we have introduced a new feature to the [Docs Module](../../modules/docs.md) that allows you to export the documentation as a PDF file. (Administrators generate PDF files from the back-office side, and then "Download PDF" button appears on the document system, allowing users to download the compiled documentation as a PDF file.) + +While implementing this feature, we have made changes in some services of the Docs Module. Typically, you don't need to make any changes in your code unless you have overridden or used internal services of the Docs Module. + +For example, the `ProjectAdminAppService` constructor has been changed to accept a new parameter: + +```diff +public class ProjectAdminAppService : ApplicationService, IProjectAdminAppService +{ + public ProjectAdminAppService( + IProjectRepository projectRepository, + IDocumentRepository documentRepository, + IDocumentFullSearch elasticSearchService, + IGuidGenerator guidGenerator, ++ IProjectPdfFileStore projectPdfFileStore) +} +``` + +You can see the all internal changes we made in [#22430](https://github.com/abpframework/abp/pull/22430) and [#22922](https://github.com/abpframework/abp/pull/22922) and make the relevant changes in your code if needed. + +## Angular UI: Migrating NPM Packages to Standalone Structure + +In this version, we've updated our Angular packages to support the new standalone components architecture. This is a non-breaking change - your existing module-based applications will continue to work without any modifications. However, if you wish to migrate to the standalone approach, [we've provided the necessary updates in our packages](https://github.com/abpframework/abp/pull/22829). + +The main changes include: +- Updated routing configurations to support both module-based and standalone approaches +- Added support for standalone components in ABP Suite code generation +- Updated schematics to support both module-based and standalone templates + +For detailed migration steps and best practices, please refer to our upcoming documentation and/or blog post. The migration is optional, and you can continue using the module-based approach if you prefer. \ No newline at end of file diff --git a/docs/en/release-info/migration-guides/index.md b/docs/en/release-info/migration-guides/index.md index 4a8eaaf467..e09c41c952 100644 --- a/docs/en/release-info/migration-guides/index.md +++ b/docs/en/release-info/migration-guides/index.md @@ -2,6 +2,7 @@ The following documents explain how to migrate your existing ABP applications. We write migration documents only if you need to take an action while upgrading your solution. Otherwise, you can easily upgrade your solution using the [abp update command](../upgrading.md). +- [9.2 to 9.3](abp-9-3.md) - [9.x to 9.2](abp-9-2.md) - [9.0 to 9.1](abp-9-1.md) - [8.x to 9.0](abp-9-0.md) diff --git a/docs/en/release-info/release-notes.md b/docs/en/release-info/release-notes.md index ce35f8b87c..685b1dcb72 100644 --- a/docs/en/release-info/release-notes.md +++ b/docs/en/release-info/release-notes.md @@ -7,6 +7,15 @@ Also see the following notes about ABP releases: * [ABP Studio release notes](../studio/release-notes.md) * [Change logs for ABP pro packages](https://abp.io/pro-releases) +## 9.3 (2025-06-17) + +This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/articles/announcing-abp-9-3-release-candidate-4dqgiryf)** for the v9.3 release. + +* Cron Expression Support for Background Workers +* Docs Module: PDF Export +* Angular UI: Standalone Package Structure +* Upgraded to `Blazorise` **v1.7.7** +* Audit Logging Module: Excel Export ## 9.2 (2025-06-02) diff --git a/docs/en/release-info/road-map.md b/docs/en/release-info/road-map.md index d2ae30999f..7a9ae2161a 100644 --- a/docs/en/release-info/road-map.md +++ b/docs/en/release-info/road-map.md @@ -4,11 +4,12 @@ This document provides a road map, release schedule, and planned features for th ## Next Versions -### v9.3 +### v10.0 -The next version will be 9.3 and planned to release the stable 9.3 version in July 2025. We will be mostly working on the following topics: +The next version will be 10.0 and planned to release the stable 10.0 version in December 2025. We will be mostly working on the following topics: * Framework + * Upgrading to .NET 10 * Upgrading 3rd-party dependencies * Enhancements in the core points @@ -16,7 +17,6 @@ The next version will be 9.3 and planned to release the stable 9.3 version in Ju * Define navigation properties without target string property dependency * Improvements one-to-many scenarios * File Upload Modal enhancements - * Master/Detail DataGrid Toggle Detail Row Enhancements for Blazor UI * ABP Studio diff --git a/docs/en/samples/index.md b/docs/en/samples/index.md index 39f6f02636..7110dd42f6 100644 --- a/docs/en/samples/index.md +++ b/docs/en/samples/index.md @@ -9,6 +9,8 @@ A reference application built with ABP. It implements the Domain Driven Design w * [Live demo](https://www.openeventhub.com/) * [Source code](https://github.com/abpframework/eventhub) +![samples-event-hub](../images/samples-eventhub.png) + ## eShopOnAbp > ⚠️ **Important Notice** @@ -18,6 +20,8 @@ Reference microservice solution built with ABP and .NET. * [Source code](https://github.com/abpframework/eShopOnAbp) +![eshoponabp](../images/samples-eshoponabp.png) + ## CMS Kit Demo A minimal example website built with the [CMS Kit module](../modules/cms-kit/index.md). @@ -25,6 +29,8 @@ A minimal example website built with the [CMS Kit module](../modules/cms-kit/ind * [Live demo](https://cms-kit-demo.abpdemo.com/) * [Source code](https://github.com/abpframework/cms-kit-demo) +![samples-cms-kit](../images/samples-cms-kit.png) + ## Easy CRM A middle-size CRM application built with ABP. @@ -32,6 +38,8 @@ A middle-size CRM application built with ABP. * [Live demo](http://easycrm.abp.io/) * [Click here](easy-crm.md) to see the details and download the source code. +![samples-easy-crm](../images/samples-easycrm.png) + ## Book Store A simple CRUD application to show basic principles of developing an application with ABP. The same sample was implemented with different technologies and different modules: diff --git a/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md b/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md index a280420ec3..4f77f3040d 100644 --- a/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md +++ b/docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md @@ -316,6 +316,34 @@ See: - https://learn.microsoft.com/en-us/aspnet/web-api/overview/testing-and-debugging/troubleshooting-http-405-errors-after-publishing-web-api-applications#resolve-http-405-errors - https://learn.microsoft.com/en-us/troubleshoot/developer/webapps/iis/site-behavior-performance/http-error-405-website#resolution-for-cause-3 +## Publish the Application(s) as IIS sub-application + +If your MVC application is a sub-application, you need to set the `BaseUrl` property of `AbpThemingOptions` to the sub-application’s path. The `BaseUrl` is used to configure the `base` element in the `head` section of the layout page. + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + Configure(options => + { + options.BaseUrl = "/myapp/"; + }); +} +``` + +```html + + + + ... + + + ... + + +``` + +For Blazor applications, you can to set the `base` tag in the `App.razor` file instead of configure `AbpThemingOptions`. + ## How to get stdout-log If your application is running on IIS and getting errors like `502.5, 500.3x`, you can enable stdout logs to see the error details. diff --git a/docs/en/studio/installation.md b/docs/en/studio/installation.md index fb657fba47..8da2fa79d7 100644 --- a/docs/en/studio/installation.md +++ b/docs/en/studio/installation.md @@ -4,26 +4,27 @@ This document explains how to install the ABP Studio tool. ## Pre-requirements -Before you begin the installation process for ABP Studio, ensure that your system meets the following pre-requirements: +ABP Studio automatically instals most of the required dependencies. When you first launch the application, it will check for and install the following components if missed: -### Node -Make sure [Node.js](https://nodejs.org/en) is installed on your system. If you have not installed Node.js, you can download the `v22+` version from the official [Node.js website](https://nodejs.org/en/download/prebuilt-installer). +* .NET SDK +* Node.js +* ABP CLI +* mkcert (for HTTPS development) +* WireGuard (for Kubernetes operations) -### Docker -ABP Studio needs [Docker](https://www.docker.com/) for [Kubernetes](https://kubernetes.io/) operations. Install Docker by following the guidelines on the official [Docker website](https://docs.docker.com/get-docker/). +However, the followings should be manually installed: -### WireGuard (Optional) +### Docker (Required for Kubernetes Operations) -ABP Studio needs [WireGuard](https://www.wireguard.com/) for Kubernetes operations. You can find the installation instructions for your specific operating system below: +ABP Studio needs [Docker](https://www.docker.com/) for Docker and [Kubernetes](https://kubernetes.io/) operations. Install Docker by following the guidelines on the official [Docker website](https://docs.docker.com/get-docker/). -**For Windows:** -Installation instructions for your Windows operating system are on the official [WireGuard website](https://www.wireguard.com/install/#windows-7-81-10-11-2008r2-2012r2-2016-2019-2022). +### Package Manager Prerequisites -**For macOS:** -Installation instructions for your macOS operating system are on the official [WireGuard website](https://www.wireguard.com/install/#macos-homebrew-and-macports-basic-cli-homebrew-userspace-go-homebrew-tools-macports-userspace-go-macports-tools). +* **Windows:** The automatic installation process uses `winget`. If not already installed, ABP Studio will attempt to install it. +* **macOS:** The automatic installation process uses `brew`. If not already installed, you'll need to install it manually from [brew.sh](https://brew.sh/). ## Installation -Now you have met the pre-requirements, follow the steps below to install ABP Studio: +Follow these steps to install ABP Studio: 1. **Download ABP Studio:** Visit [abp.io](https://abp.io/studio) to download the latest version of ABP Studio. @@ -31,8 +32,10 @@ Now you have met the pre-requirements, follow the steps below to install ABP Stu 2. **Run the Installer:** Execute the installer and follow the on-screen instructions to install ABP Studio on your computer. +3. **First Launch:** When you first launch ABP Studio, it will automatically check for and install required dependencies. This process may take several minutes, and you'll see progress indicators for each component being installed. + ## Login -After you install ABP Studio, you can log in to access all the features. To log in, follow the below steps: +After installation is complete, you can log in to access all features: 1. **Launch ABP Studio:** Open ABP Studio on your desktop. diff --git a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorCachedApplicationConfigurationClient.cs index a48901f6dd..e4a2f8a3cc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiBlazorCachedApplicationConfigurationClient.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.JSInterop; +using Volo.Abp.AspNetCore.Components.Web.Security; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; using Volo.Abp.AspNetCore.Mvc.Client; @@ -23,6 +24,8 @@ namespace Volo.Abp.AspNetCore.Components.MauiBlazor protected ICurrentTimezoneProvider CurrentTimezoneProvider { get; } + protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; } + protected IJSRuntime JSRuntime { get; } protected IClock Clock { get; } @@ -34,6 +37,7 @@ namespace Volo.Abp.AspNetCore.Components.MauiBlazor ICurrentTimezoneProvider currentTimezoneProvider, AuthenticationStateProvider authenticationStateProvider, AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy, + ApplicationConfigurationChangedService applicationConfigurationChangedService, IJSRuntime jsRuntime, IClock clock) { @@ -42,6 +46,7 @@ namespace Volo.Abp.AspNetCore.Components.MauiBlazor CurrentTenantAccessor = currentTenantAccessor; CurrentTimezoneProvider = currentTimezoneProvider; ApplicationLocalizationClientProxy = applicationLocalizationClientProxy; + ApplicationConfigurationChangedService = applicationConfigurationChangedService; JSRuntime = jsRuntime; Clock = clock; @@ -81,6 +86,8 @@ namespace Volo.Abp.AspNetCore.Components.MauiBlazor await JSRuntime.InvokeAsync("abp.clock.setBrowserTimeZoneToCookie"); } + + ApplicationConfigurationChangedService.NotifyChanged(); } public virtual Task GetAsync() diff --git a/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiCurrentApplicationConfigurationCacheResetService.cs b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiCurrentApplicationConfigurationCacheResetService.cs new file mode 100644 index 0000000000..ad2f6ba983 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo/Abp/AspNetCore/Components/MauiBlazor/MauiCurrentApplicationConfigurationCacheResetService.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Components.Web.Configuration; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Components.MauiBlazor; + +[Dependency(ReplaceServices = true)] +public class MauiCurrentApplicationConfigurationCacheResetService : + ICurrentApplicationConfigurationCacheResetService, + ITransientDependency +{ + private readonly MauiBlazorCachedApplicationConfigurationClient _mauiBlazorCachedApplicationConfigurationClient; + + public MauiCurrentApplicationConfigurationCacheResetService(MauiBlazorCachedApplicationConfigurationClient mauiBlazorCachedApplicationConfigurationClient) + { + _mauiBlazorCachedApplicationConfigurationClient = mauiBlazorCachedApplicationConfigurationClient; + } + + public async Task ResetAsync() + { + await _mauiBlazorCachedApplicationConfigurationClient.InitializeAsync(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs index 62cae94413..af1538bbde 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelper.cs @@ -47,11 +47,13 @@ public class AbpInputTagHelper : AbpTagHelper } if (isCheckBox) { - output.Attributes.AddClass("custom-checkbox"); - output.Attributes.AddClass("custom-control"); + if (!TagHelper.UseSwitchCheckBox) + { + output.Attributes.AddClass("custom-checkbox"); + output.Attributes.AddClass("custom-control"); + } + else + { + output.Attributes.AddClass("form-switch"); + } + output.Attributes.AddClass("form-check"); } } @@ -266,7 +274,7 @@ public class AbpInputTagHelperService : AbpTagHelperService } protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) - { + { if (IsOutputHidden(inputTag) || TagHelper.SuppressLabel) { return string.Empty; @@ -395,7 +403,7 @@ public class AbpInputTagHelperService : AbpTagHelperService } innerOutput.Content.AppendHtml($" "); } - + innerOutput.Content.AppendHtml(GetRequiredSymbol(context, output)); return innerOutput.Render(_encoder); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js index e11a8f4d99..f8c9543e0d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js @@ -55,7 +55,7 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f function _createContainer() { _removeContainer(); - _$modalContainer = $('
'); + _$modalContainer = $('
'); var existsModals = $('[id^="Abp_Modal_"]'); if (existsModals.length) { existsModals.last().after(_$modalContainer) @@ -104,6 +104,7 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f } } + var focusElement = null; if (!options.focusElement) { //focuses first element if it's a typeable input. var $firstVisibleInput = _$modal.find('input:not([type=hidden]):first'); @@ -120,11 +121,18 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f } $firstVisibleInput.focus(); + focusElement = $firstVisibleInput; } else if (typeof options.focusElement === 'function') { - var focusElement = options.focusElement(); + focusElement = options.focusElement(); focusElement.focus(); } else if (typeof options.focusElement === 'string') { - $(options.focusElement).focus(); + focusElement = $(options.focusElement); + focusElement.focus(); + } + + if (focusElement && $(focusElement).is('input')) { + var value = focusElement.val(); + focusElement[0].setSelectionRange(value.length, value.length); } }); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/AbpThemingOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/AbpThemingOptions.cs index 1197ad6e53..bf999be982 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/AbpThemingOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Theming/AbpThemingOptions.cs @@ -6,6 +6,12 @@ public class AbpThemingOptions public string? DefaultThemeName { get; set; } + /// + /// If set, the base element will be added to the head element of the page. + /// eg: + /// + public string? BaseUrl { get; set; } + public AbpThemingOptions() { Themes = new ThemeDictionary(); diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs index d042bb6026..b9142b5aed 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs @@ -115,7 +115,7 @@ public static class AbpApplicationBuilderExtensions return app.UseMiddleware(); } - [Obsolete("Replace with AbpClaimsTransformation")] + [Obsolete("Use the TransformAbpClaims extension method from IServiceCollection instead.")] public static IApplicationBuilder UseAbpClaimsMap(this IApplicationBuilder app) { return app.UseMiddleware(); diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs index 2104edab0a..70fad0d19e 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs @@ -11,7 +11,7 @@ using Volo.Abp.Security.Claims; namespace Volo.Abp.AspNetCore.Security.Claims; -[Obsolete("Replace with AbpClaimsTransformation")] +[Obsolete("Use the TransformAbpClaims extension method from IServiceCollection instead.")] public class AbpClaimsMapMiddleware : AbpMiddlewareBase, ITransientDependency { public async override Task InvokeAsync(HttpContext context, RequestDelegate next) diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs index 3357d8f95c..e834b3d00d 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs @@ -38,7 +38,7 @@ public static class AbpRegistrationBuilderExtensions } registrationBuilder = registrationBuilder.EnablePropertyInjection(moduleContainer, implementationType); - registrationBuilder = registrationBuilder.InvokeRegistrationActions(registrationActionList, serviceType, implementationType); + registrationBuilder = registrationBuilder.InvokeRegistrationActions(registrationActionList, serviceType, implementationType, serviceDescriptor.ServiceKey); return registrationBuilder; } @@ -69,10 +69,11 @@ public static class AbpRegistrationBuilderExtensions this IRegistrationBuilder registrationBuilder, ServiceRegistrationActionList registrationActionList, Type serviceType, - Type implementationType) + Type implementationType, + object? serviceKey = null) where TActivatorData : ReflectionActivatorData { - var serviceRegistredArgs = new OnServiceRegistredContext(serviceType, implementationType); + var serviceRegistredArgs = new OnServiceRegistredContext(serviceType, implementationType, serviceKey); foreach (var registrationAction in registrationActionList) { diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs index 6b3aaa52b8..1a6cb6a9e9 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobOptions.cs @@ -14,10 +14,17 @@ public class AbpBackgroundJobOptions /// public bool IsJobExecutionEnabled { get; set; } = true; + /// + /// The delegate to get the name of a background job. + /// Default: . + /// + public Func GetBackgroundJobName { get; set; } + public AbpBackgroundJobOptions() { _jobConfigurationsByArgsType = new Dictionary(); _jobConfigurationsByName = new Dictionary(); + GetBackgroundJobName = BackgroundJobNameAttribute.GetName; } public BackgroundJobConfiguration GetJob() @@ -61,7 +68,7 @@ public class AbpBackgroundJobOptions public void AddJob(Type jobType) { - AddJob(new BackgroundJobConfiguration(jobType)); + AddJob(new BackgroundJobConfiguration(jobType, GetBackgroundJobName(BackgroundJobArgsHelper.GetJobArgsType(jobType)))); } public void AddJob(BackgroundJobConfiguration jobConfiguration) diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobConfiguration.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobConfiguration.cs index d9f08da2e7..c17ccdc443 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobConfiguration.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobConfiguration.cs @@ -10,10 +10,10 @@ public class BackgroundJobConfiguration public string JobName { get; } - public BackgroundJobConfiguration(Type jobType) + public BackgroundJobConfiguration(Type jobType, string jobName) { JobType = jobType; ArgsType = BackgroundJobArgsHelper.GetJobArgsType(jobType); - JobName = BackgroundJobNameAttribute.GetName(ArgsType); + JobName = jobName; } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs index ee747e4611..345a69703f 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs @@ -25,13 +25,8 @@ public class AbpBackgroundJobsHangfireModule : AbpModule if (!options.IsJobExecutionEnabled) { var hangfireOptions = context.ServiceProvider.GetRequiredService>().Value; - hangfireOptions.BackgroundJobServerFactory = CreateOnlyEnqueueJobServer; + context.ServiceProvider.GetRequiredService(); + hangfireOptions.BackgroundJobServerFactory = _ => null; } } - - private BackgroundJobServer? CreateOnlyEnqueueJobServer(IServiceProvider serviceProvider) - { - serviceProvider.GetRequiredService(); - return null; - } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs index 1dbe4a6dcc..bdc28c7ca0 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -120,46 +121,44 @@ public class JobQueue : IJobQueue ChannelAccessor?.Dispose(); } - protected virtual Task EnsureInitializedAsync() + protected virtual async Task EnsureInitializedAsync() { if (ChannelAccessor != null && ChannelAccessor.Channel.IsOpen) { - return Task.CompletedTask; + return; } - ChannelAccessor = ChannelPool.Acquire( + ChannelAccessor = await ChannelPool.AcquireAsync( ChannelPrefix + QueueConfiguration.QueueName, QueueConfiguration.ConnectionName ); - var result = QueueConfiguration.Declare(ChannelAccessor.Channel); + var result = await QueueConfiguration.DeclareAsync(ChannelAccessor.Channel); Logger.LogDebug($"RabbitMQ Queue '{QueueConfiguration.QueueName}' has {result.MessageCount} messages and {result.ConsumerCount} consumers."); // Declare delayed queue - QueueConfiguration.DeclareDelayed(ChannelAccessor.Channel); + await QueueConfiguration.DeclareDelayedAsync(ChannelAccessor.Channel); if (AbpBackgroundJobOptions.IsJobExecutionEnabled) { if (QueueConfiguration.PrefetchCount.HasValue) { - ChannelAccessor.Channel.BasicQos(0, QueueConfiguration.PrefetchCount.Value, false); + await ChannelAccessor.Channel.BasicQosAsync(0, QueueConfiguration.PrefetchCount.Value, false); } - + Consumer = new AsyncEventingBasicConsumer(ChannelAccessor.Channel); - Consumer.Received += MessageReceived; - + Consumer.ReceivedAsync += MessageReceived; + //TODO: What BasicConsume returns? - ChannelAccessor.Channel.BasicConsume( + await ChannelAccessor.Channel.BasicConsumeAsync( queue: QueueConfiguration.QueueName, autoAck: false, consumer: Consumer ); } - - return Task.CompletedTask; } - protected virtual Task PublishAsync( + protected virtual async Task PublishAsync( TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) @@ -167,29 +166,27 @@ public class JobQueue : IJobQueue //TODO: How to handle priority var routingKey = QueueConfiguration.QueueName; - var basicProperties = CreateBasicPropertiesToPublish(); + var basicProperties = new BasicProperties + { + Persistent = true + }; if (delay.HasValue) { routingKey = QueueConfiguration.DelayedQueueName; - basicProperties.Expiration = delay.Value.TotalMilliseconds.ToString(); + basicProperties.Expiration = delay.Value.TotalMilliseconds.ToString(CultureInfo.InvariantCulture); } - ChannelAccessor!.Channel.BasicPublish( - exchange: "", - routingKey: routingKey, - basicProperties: basicProperties, - body: Serializer.Serialize(args!) - ); - - return Task.CompletedTask; - } - - protected virtual IBasicProperties CreateBasicPropertiesToPublish() - { - var properties = ChannelAccessor!.Channel.CreateBasicProperties(); - properties.Persistent = true; - return properties; + if (ChannelAccessor != null) + { + await ChannelAccessor.Channel.BasicPublishAsync( + exchange: "", + routingKey: routingKey, + mandatory: false, + basicProperties: basicProperties, + body: Serializer.Serialize(args!) + ); + } } protected virtual async Task MessageReceived(object sender, BasicDeliverEventArgs ea) @@ -205,17 +202,17 @@ public class JobQueue : IJobQueue try { await JobExecuter.ExecuteAsync(context); - ChannelAccessor!.Channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); + await ChannelAccessor!.Channel.BasicAckAsync(deliveryTag: ea.DeliveryTag, multiple: false); } catch (BackgroundJobExecutionException) { //TODO: Reject like that? - ChannelAccessor!.Channel.BasicReject(deliveryTag: ea.DeliveryTag, requeue: true); + await ChannelAccessor!.Channel.BasicRejectAsync(deliveryTag: ea.DeliveryTag, requeue: true); } catch (Exception) { //TODO: Reject like that? - ChannelAccessor!.Channel.BasicReject(deliveryTag: ea.DeliveryTag, requeue: false); + await ChannelAccessor!.Channel.BasicRejectAsync(deliveryTag: ea.DeliveryTag, requeue: false); } } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs index 9425cd0604..c6418f52f7 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using RabbitMQ.Client; using Volo.Abp.RabbitMQ; @@ -34,15 +35,15 @@ public class JobQueueConfiguration : QueueDeclareConfiguration DelayedQueueName = delayedQueueName; } - public virtual QueueDeclareOk DeclareDelayed(IModel channel) + public virtual async Task DeclareDelayedAsync(IChannel channel) { - var delayedArguments = new Dictionary(Arguments) + var delayedArguments = new Dictionary(Arguments) { ["x-dead-letter-routing-key"] = QueueName, ["x-dead-letter-exchange"] = string.Empty }; - return channel.QueueDeclare( + return await channel.QueueDeclareAsync( queue: DelayedQueueName, durable: Durable, exclusive: Exclusive, diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs index 68851c5043..586b66b5d1 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/DefaultBackgroundJobManager.cs @@ -18,6 +18,7 @@ public class DefaultBackgroundJobManager : IBackgroundJobManager, ITransientDepe protected IBackgroundJobSerializer Serializer { get; } protected IGuidGenerator GuidGenerator { get; } protected IBackgroundJobStore Store { get; } + protected IOptions BackgroundJobOptions { get; } protected IOptions BackgroundJobWorkerOptions { get; } public DefaultBackgroundJobManager( @@ -25,18 +26,20 @@ public class DefaultBackgroundJobManager : IBackgroundJobManager, ITransientDepe IBackgroundJobSerializer serializer, IBackgroundJobStore store, IGuidGenerator guidGenerator, + IOptions backgroundJobOptions, IOptions backgroundJobWorkerOptions) { Clock = clock; Serializer = serializer; GuidGenerator = guidGenerator; + BackgroundJobOptions = backgroundJobOptions; BackgroundJobWorkerOptions = backgroundJobWorkerOptions; Store = store; } public virtual async Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) { - var jobName = BackgroundJobNameAttribute.GetName(); + var jobName = BackgroundJobOptions.Value.GetBackgroundJobName(typeof(TArgs)); var jobId = await EnqueueAsync(jobName, args!, priority, delay); return jobId.ToString(); } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs index 2577181143..433ac699d2 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs @@ -1,5 +1,4 @@ -using System; -using Hangfire; +using Hangfire; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Hangfire; @@ -23,17 +22,12 @@ public class AbpBackgroundWorkersHangfireModule : AbpModule if (!options.IsEnabled) { var hangfireOptions = context.ServiceProvider.GetRequiredService>().Value; - hangfireOptions.BackgroundJobServerFactory = CreateOnlyEnqueueJobServer; + context.ServiceProvider.GetRequiredService(); + hangfireOptions.BackgroundJobServerFactory = _ => null; } context.ServiceProvider .GetRequiredService() .Initialize(); } - - private BackgroundJobServer? CreateOnlyEnqueueJobServer(IServiceProvider serviceProvider) - { - serviceProvider.GetRequiredService(); - return null; - } } diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs index 1ed3561cac..fe9a8ad983 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -1,14 +1,15 @@ using System; +using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Hangfire; +using Hangfire.Common; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; using Volo.Abp.Hangfire; -using Volo.Abp.Threading; namespace Volo.Abp.BackgroundWorkers.Hangfire; @@ -55,40 +56,40 @@ public class HangfireBackgroundWorkerManager : BackgroundWorkerManager, ISinglet } case AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase: { - var timer = worker.GetType().GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); - var period = worker is AsyncPeriodicBackgroundWorkerBase ? ((AbpAsyncTimer?)timer)?.Period : ((AbpTimer?)timer)?.Period; + int? period = null; + string? CronExpression = null; - if (period == null) + if (worker is AsyncPeriodicBackgroundWorkerBase asyncPeriodicBackgroundWorkerBase) { - return; + period = asyncPeriodicBackgroundWorkerBase.Period; + CronExpression = asyncPeriodicBackgroundWorkerBase.CronExpression; } - - var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); - var workerAdapter = (Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker)!; - - if (workerAdapter.RecurringJobId.IsNullOrWhiteSpace()) + else if (worker is PeriodicBackgroundWorkerBase periodicBackgroundWorkerBase) { - RecurringJob.AddOrUpdate( - () => workerAdapter.DoWorkAsync(cancellationToken), - GetCron(period.Value), - workerAdapter.TimeZone , - workerAdapter.Queue.IsNullOrWhiteSpace() ? defaultQueue : defaultQueuePrefix + workerAdapter.Queue); + period = periodicBackgroundWorkerBase.Period; + CronExpression = periodicBackgroundWorkerBase.CronExpression; } - else - { - RecurringJob.AddOrUpdate( - workerAdapter.RecurringJobId, - workerAdapter.Queue.IsNullOrWhiteSpace() ? defaultQueue : defaultQueuePrefix + workerAdapter.Queue, - () => workerAdapter.DoWorkAsync(cancellationToken), - GetCron(period.Value), - new RecurringJobOptions - { - TimeZone = workerAdapter.TimeZone - }); + if (period == null && CronExpression.IsNullOrWhiteSpace()) + { + return; } + var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker)); + var workerAdapter = (Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker)!; + + Expression> methodCall = () => workerAdapter.DoWorkAsync(cancellationToken); + var recurringJobId = !workerAdapter.RecurringJobId.IsNullOrWhiteSpace() ? workerAdapter.RecurringJobId : GetRecurringJobId(worker, methodCall); + RecurringJob.AddOrUpdate( + recurringJobId, + workerAdapter.Queue.IsNullOrWhiteSpace() ? defaultQueue : defaultQueuePrefix + workerAdapter.Queue, + methodCall, + CronExpression ?? GetCron(period!.Value), + new RecurringJobOptions + { + TimeZone = workerAdapter.TimeZone + }); break; } default: @@ -97,6 +98,24 @@ public class HangfireBackgroundWorkerManager : BackgroundWorkerManager, ISinglet } } + private readonly static MethodInfo? GetRecurringJobIdMethodInfo = typeof(RecurringJob).GetMethod("GetRecurringJobId", BindingFlags.NonPublic | BindingFlags.Static); + protected virtual string? GetRecurringJobId(IBackgroundWorker worker, Expression> methodCall) + { + string? recurringJobId = null; + if (GetRecurringJobIdMethodInfo != null) + { + var job = Job.FromExpression(methodCall); + recurringJobId = (string)GetRecurringJobIdMethodInfo.Invoke(null, [job])!; + } + + if (recurringJobId.IsNullOrWhiteSpace()) + { + recurringJobId = $"HangfirePeriodicBackgroundWorkerAdapter<{worker.GetType().Name}>.DoWorkAsync"; + } + + return recurringJobId; + } + protected virtual string GetCron(int period) { var time = TimeSpan.FromMilliseconds(period); @@ -120,8 +139,7 @@ public class HangfireBackgroundWorkerManager : BackgroundWorkerManager, ISinglet } else { - throw new AbpException( - $"Cannot convert period: {period} to cron expression, use HangfireBackgroundWorkerBase to define worker"); + throw new AbpException($"Cannot convert period: {period} to cron expression, use HangfireBackgroundWorkerBase to define worker"); } return cron; diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs index 522ef7a807..2967b1a508 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs @@ -3,8 +3,6 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Quartz; -using Volo.Abp.DynamicProxy; -using Volo.Abp.Threading; namespace Volo.Abp.BackgroundWorkers.Quartz; @@ -25,28 +23,23 @@ public class QuartzPeriodicBackgroundWorkerAdapter : QuartzBackgroundWo } - public void BuildWorker(IBackgroundWorker worker) + public virtual void BuildWorker(IBackgroundWorker worker) { - int? period; - var workerType = ProxyHelper.GetUnProxiedType(worker); + int? period = null; + string? CronExpression = null; - if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase) + if (worker is AsyncPeriodicBackgroundWorkerBase asyncPeriodicBackgroundWorkerBase) { - if (typeof(TWorker) != workerType) - { - throw new ArgumentException($"{nameof(worker)} type is different from the generic type"); - } - - var timer = workerType.GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); - - period = worker is AsyncPeriodicBackgroundWorkerBase ? ((AbpAsyncTimer?)timer)?.Period : ((AbpTimer?)timer)?.Period; + period = asyncPeriodicBackgroundWorkerBase.Period; + CronExpression = asyncPeriodicBackgroundWorkerBase.CronExpression; } - else + else if (worker is PeriodicBackgroundWorkerBase periodicBackgroundWorkerBase) { - return; + period = periodicBackgroundWorkerBase.Period; + CronExpression = periodicBackgroundWorkerBase.CronExpression; } - if (period == null) + if (period == null && CronExpression.IsNullOrWhiteSpace()) { return; } @@ -55,10 +48,21 @@ public class QuartzPeriodicBackgroundWorkerAdapter : QuartzBackgroundWo .Create>() .WithIdentity(BackgroundWorkerNameAttribute.GetName()) .Build(); - Trigger = TriggerBuilder.Create() - .WithIdentity(BackgroundWorkerNameAttribute.GetName()) - .WithSimpleSchedule(builder => builder.WithInterval(TimeSpan.FromMilliseconds(period.Value)).RepeatForever()) - .Build(); + + var triggerBuilder = TriggerBuilder.Create() + .ForJob(JobDetail) + .WithIdentity(BackgroundWorkerNameAttribute.GetName()); + + if (!CronExpression.IsNullOrWhiteSpace()) + { + triggerBuilder.WithCronSchedule(CronExpression); + } + else + { + triggerBuilder.WithSimpleSchedule(builder => builder.WithInterval(TimeSpan.FromMilliseconds(period!.Value)).RepeatForever()); + } + + Trigger = triggerBuilder.Build(); } public async override Task Execute(IJobExecutionContext context) diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs index 37911feae5..781d3535ba 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs @@ -13,6 +13,11 @@ public abstract class AsyncPeriodicBackgroundWorkerBase : BackgroundWorkerBase protected IServiceScopeFactory ServiceScopeFactory { get; } protected AbpAsyncTimer Timer { get; } protected CancellationToken StartCancellationToken { get; set; } + public int Period => Timer.Period; + /// + /// CronExpression has high priority over Period. + /// + public string? CronExpression { get; protected set; } protected AsyncPeriodicBackgroundWorkerBase( AbpAsyncTimer timer, diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs index 9d78d9237d..c7f9af7016 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs @@ -15,6 +15,11 @@ public abstract class PeriodicBackgroundWorkerBase : BackgroundWorkerBase { protected IServiceScopeFactory ServiceScopeFactory { get; } protected AbpTimer Timer { get; } + public int Period => Timer.Period; + /// + /// CronExpression has high priority over Period. + /// + public string? CronExpression { get; protected set; } protected PeriodicBackgroundWorkerBase( AbpTimer timer, @@ -25,13 +30,13 @@ public abstract class PeriodicBackgroundWorkerBase : BackgroundWorkerBase Timer.Elapsed += Timer_Elapsed; } - public override async Task StartAsync(CancellationToken cancellationToken = default) + public async override Task StartAsync(CancellationToken cancellationToken = default) { await base.StartAsync(cancellationToken); Timer.Start(cancellationToken); } - public override async Task StopAsync(CancellationToken cancellationToken = default) + public async override Task StopAsync(CancellationToken cancellationToken = default) { Timer.Stop(cancellationToken); await base.StopAsync(cancellationToken); diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index 6c4fcf07f9..a2c7193437 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -357,10 +357,10 @@ public abstract class AbpCrudPageBase< } } - protected virtual Task CloseCreateModalAsync() + protected virtual async Task CloseCreateModalAsync() { + await InvokeAsync(CreateModal!.Hide); NewEntity = new TCreateViewModel(); - return InvokeAsync(CreateModal!.Hide); } protected virtual Task ClosingCreateModal(ModalClosingEventArgs eventArgs) @@ -474,11 +474,11 @@ public abstract class AbpCrudPageBase< protected virtual async Task OnCreatedEntityAsync() { - NewEntity = new TCreateViewModel(); await GetEntitiesAsync(); await InvokeAsync(CreateModal!.Hide); await Notify.Success(GetCreateMessage()); + NewEntity = new TCreateViewModel(); } protected virtual string GetCreateMessage() diff --git a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs index 2773b88bed..fa4994e2f9 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/BlazoriseUiObjectExtensionPropertyInfoExtensions.cs @@ -233,19 +233,17 @@ public static class BlazoriseUiObjectExtensionPropertyInfoExtensions switch (dataTypeAttribute.DataType) { case DataType.Password: - return typeof(TextExtensionProperty<,>); - case DataType.Date: - return typeof(DateTimeExtensionProperty<,>); - case DataType.Time: - return typeof(TimeExtensionProperty<,>); case DataType.EmailAddress: - return typeof(TextExtensionProperty<,>); case DataType.Url: - return typeof(TextExtensionProperty<,>); case DataType.PhoneNumber: return typeof(TextExtensionProperty<,>); + case DataType.Date: case DataType.DateTime: return typeof(DateTimeExtensionProperty<,>); + case DataType.Time: + return typeof(TimeExtensionProperty<,>); + case DataType.MultilineText: + return typeof(TextAreaExtensionProperty<,>); } } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextAreaExtensionProperty.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextAreaExtensionProperty.razor new file mode 100644 index 0000000000..6acf7ba69d --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextAreaExtensionProperty.razor @@ -0,0 +1,19 @@ +@typeparam TEntity +@typeparam TResourceType +@using Volo.Abp.BlazoriseUI +@using Volo.Abp.Localization +@inherits ExtensionPropertyComponentBase + +@if (PropertyInfo != null && Entity != null) +{ + + + @PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory) + + + + + + + +} diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextAreaExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextAreaExtensionProperty.razor.cs new file mode 100644 index 0000000000..853d1e7372 --- /dev/null +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/TextAreaExtensionProperty.razor.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Data; + +namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; +public partial class TextAreaExtensionProperty + where TEntity : IHasExtraProperties +{ + protected string? Value { + get { + return PropertyInfo.GetTextInputValueOrNull(Entity.GetProperty(PropertyInfo.Name)); + } + set { + Entity.SetProperty(PropertyInfo.Name, value, validate: false); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs index 1c04fdb755..d20c8d1214 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs @@ -86,7 +86,7 @@ public class AliyunBlobProvider : BlobProviderBase, ITransientDependency return null; } var result = ossClient.GetObject(containerName, blobName); - return await TryCopyToMemoryStreamAsync(result.Content, args.CancellationToken); + return result.ResponseStream; } protected virtual string GetContainerName(BlobProviderArgs args) diff --git a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs index 00a82a0f3e..7c520da471 100644 --- a/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProvider.cs @@ -103,7 +103,7 @@ public class AwsBlobProvider : BlobProviderBase, ITransientDependency Key = blobName }); - return await TryCopyToMemoryStreamAsync(response.ResponseStream, args.CancellationToken); + return response.ResponseStream; } } diff --git a/framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProvider.cs index 5d45e749ea..bea55c624d 100644 --- a/framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProvider.cs @@ -66,8 +66,7 @@ public class AzureBlobProvider : BlobProviderBase, ITransientDependency } var blobClient = GetBlobClient(args, blobName); - var download = await blobClient.DownloadAsync(); - return await TryCopyToMemoryStreamAsync(download.Value.Content, args.CancellationToken); + return await blobClient.OpenReadAsync(cancellationToken: args.CancellationToken); } protected virtual BlobClient GetBlobClient(BlobProviderArgs args, string blobName) diff --git a/framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobProvider.cs index a221441749..2a410005db 100644 --- a/framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.FileSystem/Volo/Abp/BlobStoring/FileSystem/FileSystemBlobProvider.cs @@ -70,13 +70,7 @@ public class FileSystemBlobProvider : BlobProviderBase, ITransientDependency return await Policy.Handle() .WaitAndRetryAsync(2, retryCount => TimeSpan.FromSeconds(retryCount)) - .ExecuteAsync(async () => - { - using (var fileStream = File.OpenRead(filePath)) - { - return await TryCopyToMemoryStreamAsync(fileStream, args.CancellationToken); - } - }); + .ExecuteAsync(() => Task.FromResult(File.OpenRead(filePath))); } protected virtual Task ExistsAsync(string filePath) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj index 48d756465f..547f9f0aff 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj +++ b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj @@ -16,23 +16,26 @@ - +
+ + + + -
diff --git a/framework/src/Volo.Abp.Cli/Volo.Abp.Cli.csproj b/framework/src/Volo.Abp.Cli/Volo.Abp.Cli.csproj index 92753dc30d..e714fcd0b3 100644 --- a/framework/src/Volo.Abp.Cli/Volo.Abp.Cli.csproj +++ b/framework/src/Volo.Abp.Cli/Volo.Abp.Cli.csproj @@ -15,7 +15,6 @@ - diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs index be365df686..be906c9e74 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Logging; namespace Microsoft.Extensions.DependencyInjection; @@ -7,6 +8,7 @@ public static class ServiceCollectionLoggingExtensions { public static ILogger GetInitLogger(this IServiceCollection services) { - return services.GetSingletonInstance().Create(); + var loggerFactory = services.GetSingletonInstanceOrNull(); + return loggerFactory == null ? NullLogger.Instance : loggerFactory.Create(); } } diff --git a/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj b/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj index b1605bddd2..caa6b6be94 100644 --- a/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj +++ b/framework/src/Volo.Abp.Core/Volo.Abp.Core.csproj @@ -16,7 +16,6 @@ - @@ -26,10 +25,7 @@ - - - @@ -40,6 +36,10 @@ + + + + all runtime; build; native; contentfiles; analyzers diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ConventionalRegistrarBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ConventionalRegistrarBase.cs index 6d1c345840..d9fae16e16 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ConventionalRegistrarBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ConventionalRegistrarBase.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Volo.Abp.Reflection; namespace Volo.Abp.DependencyInjection; @@ -11,14 +12,30 @@ public abstract class ConventionalRegistrarBase : IConventionalRegistrar { public virtual void AddAssembly(IServiceCollection services, Assembly assembly) { - var types = AssemblyHelper - .GetAllTypes(assembly) - .Where( - type => type != null && - type.IsClass && - !type.IsAbstract && - !type.IsGenericType - ).ToArray(); + var logger = services.GetInitLogger(); + var types = Array.Empty(); + + try + { + types = AssemblyHelper + .GetAllTypes(assembly) + .Where( + type => type != null && + type.IsClass && + !type.IsAbstract && + !type.IsGenericType + ).ToArray(); + } + catch (ReflectionTypeLoadException e) + { + types = e.Types.Select(x => x!).ToArray(); + logger.LogException(e); + } + catch (Exception e) + { + //TODO: Trigger a global event? + logger.LogException(e); + } AddTypes(services, types); } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceRegistredContext.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceRegistredContext.cs index 86dad068b6..a1c50c0c64 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceRegistredContext.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IOnServiceRegistredContext.cs @@ -9,4 +9,6 @@ public interface IOnServiceRegistredContext ITypeList Interceptors { get; } Type ImplementationType { get; } + + object? ServiceKey { get; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceRegistredContext.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceRegistredContext.cs index a843b136f6..8491c94e91 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceRegistredContext.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/OnServiceRegistredContext.cs @@ -13,10 +13,13 @@ public class OnServiceRegistredContext : IOnServiceRegistredContext public virtual Type ImplementationType { get; } - public OnServiceRegistredContext(Type serviceType, [NotNull] Type implementationType) + public virtual object? ServiceKey { get; } + + public OnServiceRegistredContext(Type serviceType, [NotNull] Type implementationType, object? serviceKey = null) { ServiceType = Check.NotNull(serviceType, nameof(serviceType)); ImplementationType = Check.NotNull(implementationType, nameof(implementationType)); + ServiceKey = serviceKey; Interceptors = new TypeList(); } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs index 3f638defe8..be28f569ea 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs @@ -23,7 +23,6 @@ internal static class InternalServiceCollectionExtensions { var moduleLoader = new ModuleLoader(); var assemblyFinder = new AssemblyFinder(abpApplication); - var typeFinder = new TypeFinder(assemblyFinder); if (!services.IsAdded()) { @@ -36,8 +35,9 @@ internal static class InternalServiceCollectionExtensions services.TryAddSingleton(moduleLoader); services.TryAddSingleton(assemblyFinder); - services.TryAddSingleton(typeFinder); services.TryAddSingleton(new DefaultInitLoggerFactory()); + var typeFinder = new TypeFinder(services.GetInitLogger(), assemblyFinder); + services.TryAddSingleton(typeFinder); services.AddAssemblyOf(); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyHelper.cs index 8e71f011fe..040159dcc8 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyHelper.cs @@ -25,13 +25,6 @@ internal static class AssemblyHelper public static IReadOnlyList GetAllTypes(Assembly assembly) { - try - { - return assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - return ex.Types!; - } + return assembly.GetTypes(); } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs index c7350cde18..c4b52604d6 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs @@ -1,19 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading; +using Microsoft.Extensions.Logging; namespace Volo.Abp.Reflection; public class TypeFinder : ITypeFinder { + private readonly ILogger _logger; + private readonly IAssemblyFinder _assemblyFinder; private readonly Lazy> _types; - public TypeFinder(IAssemblyFinder assemblyFinder) + public TypeFinder(ILogger logger, IAssemblyFinder assemblyFinder) { _assemblyFinder = assemblyFinder; + _logger = logger; _types = new Lazy>(FindAll, LazyThreadSafetyMode.ExecutionAndPublication); } @@ -37,9 +42,15 @@ public class TypeFinder : ITypeFinder allTypes.AddRange(typesInThisAssembly.Where(type => type != null)); } - catch + catch (ReflectionTypeLoadException e) + { + allTypes = e.Types.Select(x => x!).ToList(); + _logger.LogException(e); + } + catch (Exception e) { //TODO: Trigger a global event? + _logger.LogException(e); } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs index 2115d00200..e84778ae50 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; @@ -12,7 +14,7 @@ public static class RepositoryAsyncExtensions { #region Contains - public static async Task ContainsAsync( + public async static Task ContainsAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] T item, CancellationToken cancellationToken = default) @@ -26,7 +28,7 @@ public static class RepositoryAsyncExtensions #region Any/All - public static async Task AnyAsync( + public async static Task AnyAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -35,7 +37,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AnyAsync(queryable, cancellationToken); } - public static async Task AnyAsync( + public async static Task AnyAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -45,7 +47,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AnyAsync(queryable, predicate, cancellationToken); } - public static async Task AllAsync( + public async static Task AllAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -59,7 +61,7 @@ public static class RepositoryAsyncExtensions #region Count/LongCount - public static async Task CountAsync( + public async static Task CountAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -68,7 +70,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.CountAsync(queryable, cancellationToken); } - public static async Task CountAsync( + public async static Task CountAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -78,7 +80,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.CountAsync(queryable, predicate, cancellationToken); } - public static async Task LongCountAsync( + public async static Task LongCountAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -87,7 +89,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.LongCountAsync(queryable, cancellationToken); } - public static async Task LongCountAsync( + public async static Task LongCountAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -101,41 +103,41 @@ public static class RepositoryAsyncExtensions #region First/FirstOrDefault - public static async Task FirstAsync( + public async static Task FirstAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstAsync(queryable, cancellationToken); } - public static async Task FirstAsync( + public async static Task FirstAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstAsync(queryable, predicate, cancellationToken); } - public static async Task FirstOrDefaultAsync( + public async static Task FirstOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstOrDefaultAsync(queryable, cancellationToken); } - public static async Task FirstOrDefaultAsync( + public async static Task FirstOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.FirstOrDefaultAsync(queryable, predicate, cancellationToken); } @@ -143,49 +145,63 @@ public static class RepositoryAsyncExtensions #region Last/LastOrDefault - public static async Task LastAsync( + public async static Task LastAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastAsync(queryable, cancellationToken); } - public static async Task LastAsync( + public async static Task LastAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastAsync(queryable, predicate, cancellationToken); } - public static async Task LastOrDefaultAsync( + public async static Task LastOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastOrDefaultAsync(queryable, cancellationToken); } - public static async Task LastOrDefaultAsync( + public async static Task LastOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) where T : class, IEntity { - var queryable = await repository.GetQueryableAsync(); + var queryable = AddOrderById(await repository.GetQueryableAsync()); return await repository.AsyncExecuter.LastOrDefaultAsync(queryable, predicate, cancellationToken); } #endregion + #region OrderById + + private static IQueryable AddOrderById([NotNull] this IQueryable queryable) + where T : class, IEntity + { + if (typeof(T).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntity<>))) + { + queryable = queryable.OrderBy(nameof(IEntity.Id)); + } + return queryable; + } + + #endregion + #region Single/SingleOrDefault - public static async Task SingleAsync( + public async static Task SingleAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -194,7 +210,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SingleAsync(queryable, cancellationToken); } - public static async Task SingleAsync( + public async static Task SingleAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -204,7 +220,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SingleAsync(queryable, predicate, cancellationToken); } - public static async Task SingleOrDefaultAsync( + public async static Task SingleOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -213,7 +229,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SingleOrDefaultAsync(queryable, cancellationToken); } - public static async Task SingleOrDefaultAsync( + public async static Task SingleOrDefaultAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> predicate, CancellationToken cancellationToken = default) @@ -227,7 +243,7 @@ public static class RepositoryAsyncExtensions #region Min - public static async Task MinAsync( + public async static Task MinAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -236,7 +252,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.MinAsync(queryable, cancellationToken); } - public static async Task MinAsync( + public async static Task MinAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -250,7 +266,7 @@ public static class RepositoryAsyncExtensions #region Max - public static async Task MaxAsync( + public async static Task MaxAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -259,7 +275,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.MaxAsync(queryable, cancellationToken); } - public static async Task MaxAsync( + public async static Task MaxAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -273,7 +289,7 @@ public static class RepositoryAsyncExtensions #region Sum - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -283,7 +299,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -293,7 +309,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -303,7 +319,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -313,7 +329,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -323,7 +339,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -333,7 +349,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -343,7 +359,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -353,7 +369,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -363,7 +379,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.SumAsync(queryable, selector, cancellationToken); } - public static async Task SumAsync( + public async static Task SumAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -377,7 +393,7 @@ public static class RepositoryAsyncExtensions #region Average - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -387,7 +403,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -397,7 +413,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -407,7 +423,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -417,7 +433,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -427,7 +443,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -437,7 +453,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -447,7 +463,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -457,7 +473,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.AverageAsync(queryable, selector, cancellationToken); } - public static async Task AverageAsync( + public async static Task AverageAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] Expression> selector, CancellationToken cancellationToken = default) @@ -471,7 +487,7 @@ public static class RepositoryAsyncExtensions #region ToList/Array - public static async Task> ToListAsync( + public async static Task> ToListAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity @@ -480,7 +496,7 @@ public static class RepositoryAsyncExtensions return await repository.AsyncExecuter.ToListAsync(queryable, cancellationToken); } - public static async Task ToArrayAsync( + public async static Task ToArrayAsync( [NotNull] this IReadOnlyRepository repository, CancellationToken cancellationToken = default) where T : class, IEntity diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpEventBusRabbitMqModule.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpEventBusRabbitMqModule.cs index 92399b43b0..5d811a76cc 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpEventBusRabbitMqModule.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpEventBusRabbitMqModule.cs @@ -1,4 +1,6 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; using Volo.Abp.Modularity; using Volo.Abp.RabbitMQ; @@ -12,8 +14,8 @@ public class AbpEventBusRabbitMqModule : AbpModule public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); - Configure(configuration.GetSection("RabbitMQ:EventBus")); + context.Services.TryAddEnumerable(ServiceDescriptor.Singleton, PostConfigureAbpRabbitMqEventBusOptions>()); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs index 130f5b38e2..0b450ca26e 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs @@ -17,10 +17,10 @@ public class AbpRabbitMqEventBusOptions public ushort? PrefetchCount { get; set; } - public IDictionary QueueArguments { get; set; } = new Dictionary(); + public IDictionary QueueArguments { get; set; } = new Dictionary(); + + public IDictionary ExchangeArguments { get; set; } = new Dictionary(); - public IDictionary ExchangeArguments { get; set; } = new Dictionary(); - public string GetExchangeTypeOrDefault() { return string.IsNullOrEmpty(ExchangeType) diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/PostConfigureAbpRabbitMqEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/PostConfigureAbpRabbitMqEventBusOptions.cs new file mode 100644 index 0000000000..f4e69c46c6 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/PostConfigureAbpRabbitMqEventBusOptions.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Options; + +namespace Volo.Abp.EventBus.RabbitMq; + +public class PostConfigureAbpRabbitMqEventBusOptions : IPostConfigureOptions +{ + private readonly HashSet _uint64QueueArguments = + [ + "x-delivery-limit", + "x-expires", + "x-message-ttl", + "x-max-length", + "x-max-length-bytes", + "x-quorum-initial-group-size", + "x-quorum-target-group-size", + "x-stream-filter-size-bytes", + "x-stream-max-segment-size-bytes", + ]; + + private readonly HashSet _boolQueueArguments = + [ + "x-single-active-consumer" + ]; + + public virtual void PostConfigure(string? name, AbpRabbitMqEventBusOptions options) + { + ParseBoolQueueArguments(options); + ParseIntegerQueueArguments(options); + } + + protected virtual void ParseBoolQueueArguments(AbpRabbitMqEventBusOptions options) + { + foreach (var argument in _boolQueueArguments) + { + if (options.QueueArguments.TryGetValue(argument, out var value) && value is string stringValue && bool.TryParse(stringValue, out var boolValue)) + { + options.QueueArguments[argument] = boolValue; + } + } + } + + protected virtual void ParseIntegerQueueArguments(AbpRabbitMqEventBusOptions options) + { + foreach (var argument in _uint64QueueArguments) + { + if (options.QueueArguments.TryGetValue(argument, out var value) && value is string stringValue && int.TryParse(stringValue, out var intValue)) + { + options.QueueArguments[argument] = intValue; + } + } + } + +} diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index b0f85afb56..3a647388b5 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -97,7 +97,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis SubscribeHandlers(AbpDistributedEventBusOptions.Handlers); } - private async Task ProcessEventAsync(IModel channel, BasicDeliverEventArgs ea) + private async Task ProcessEventAsync(IChannel channel, BasicDeliverEventArgs ea) { var eventName = ea.RoutingKey; var eventType = EventTypes.GetOrDefault(eventName); @@ -224,10 +224,10 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis IEnumerable outgoingEvents, OutboxConfig outboxConfig) { - using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) + using (var channel = await (await ConnectionPool.GetAsync(AbpRabbitMqEventBusOptions.ConnectionName)) + .CreateChannelAsync(new CreateChannelOptions(publisherConfirmationsEnabled: true, publisherConfirmationTrackingEnabled: true, new ThrottlingRateLimiter(256)))) { var outgoingEventArray = outgoingEvents.ToArray(); - channel.ConfirmSelect(); foreach (var outgoingEvent in outgoingEventArray) { @@ -248,8 +248,6 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis }); } } - - channel.WaitForConfirmsOrDie(); } } @@ -293,31 +291,33 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis return PublishAsync(eventName, body, headersArguments, eventId, correlationId); } - protected virtual Task PublishAsync( + protected virtual async Task PublishAsync( string eventName, byte[] body, Dictionary? headersArguments = null, Guid? eventId = null, string? correlationId = null) { - using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) + using (var channel = await (await ConnectionPool.GetAsync(AbpRabbitMqEventBusOptions.ConnectionName)).CreateChannelAsync()) { - return PublishAsync(channel, eventName, body, headersArguments, eventId, correlationId); + await PublishAsync(channel, eventName, body, headersArguments, eventId, correlationId); } } - protected virtual Task PublishAsync( - IModel channel, + protected virtual async Task PublishAsync( + IChannel channel, string eventName, byte[] body, Dictionary? headersArguments = null, Guid? eventId = null, string? correlationId = null) { - EnsureExchangeExists(channel); + await EnsureExchangeExistsAsync(channel); - var properties = channel.CreateBasicProperties(); - properties.DeliveryMode = RabbitMqConsts.DeliveryModes.Persistent; + var properties = new BasicProperties + { + DeliveryMode = DeliveryModes.Persistent + }; if (properties.MessageId.IsNullOrEmpty()) { @@ -331,18 +331,16 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis SetEventMessageHeaders(properties, headersArguments); - channel.BasicPublish( + await channel.BasicPublishAsync( exchange: AbpRabbitMqEventBusOptions.ExchangeName, routingKey: eventName, - mandatory: true, + mandatory: false, basicProperties: properties, body: body ); - - return Task.CompletedTask; } - private void EnsureExchangeExists(IModel channel) + protected virtual async Task EnsureExchangeExistsAsync(IChannel channel) { if (_exchangeCreated) { @@ -351,14 +349,14 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis try { - using (var temporaryChannel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) + using (var temporaryChannel = await (await ConnectionPool.GetAsync(AbpRabbitMqEventBusOptions.ConnectionName)).CreateChannelAsync()) { - temporaryChannel.ExchangeDeclarePassive(AbpRabbitMqEventBusOptions.ExchangeName); + await temporaryChannel.ExchangeDeclarePassiveAsync(AbpRabbitMqEventBusOptions.ExchangeName); } } catch (Exception) { - channel.ExchangeDeclare( + await channel.ExchangeDeclareAsync( AbpRabbitMqEventBusOptions.ExchangeName, AbpRabbitMqEventBusOptions.GetExchangeTypeOrDefault(), durable: true @@ -367,14 +365,14 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis _exchangeCreated = true; } - private void SetEventMessageHeaders(IBasicProperties properties, Dictionary? headersArguments) + protected virtual void SetEventMessageHeaders(IBasicProperties properties, Dictionary? headersArguments) { if (headersArguments == null) { return; } - properties.Headers ??= new Dictionary(); + properties.Headers ??= new Dictionary(); foreach (var header in headersArguments) { diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs index 63d6aa82ad..dd5df32b8a 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs @@ -236,6 +236,8 @@ public class DefaultExceptionToErrorInfoConverter : IExceptionToErrorInfoConvert errorInfo.ValidationErrors = GetValidationErrorInfos((exception as AbpValidationException)!); } + TryToLocalizeExceptionMessage(exception, errorInfo); + return errorInfo; } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs index 94822284f5..cdab8e74c8 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs @@ -1,5 +1,7 @@ -using System.Security.Principal; +using System; +using System.Security.Principal; using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; namespace Volo.Abp.Features; @@ -12,15 +14,25 @@ public class EditionFeatureValueProvider : FeatureValueProvider protected ICurrentPrincipalAccessor PrincipalAccessor; - public EditionFeatureValueProvider(IFeatureStore featureStore, ICurrentPrincipalAccessor principalAccessor) + protected ITenantStore TenantStore { get; } + + protected ICurrentTenant CurrentTenant { get; } + + public EditionFeatureValueProvider( + IFeatureStore featureStore, + ICurrentPrincipalAccessor principalAccessor, + ITenantStore tenantStore, + ICurrentTenant currentTenant) : base(featureStore) { PrincipalAccessor = principalAccessor; + TenantStore = tenantStore; + CurrentTenant = currentTenant; } - public override async Task GetOrNullAsync(FeatureDefinition feature) + public async override Task GetOrNullAsync(FeatureDefinition feature) { - var editionId = PrincipalAccessor.Principal?.FindEditionId(); + var editionId = await FindEditionIdAsync(); if (editionId == null) { return null; @@ -28,4 +40,21 @@ public class EditionFeatureValueProvider : FeatureValueProvider return await FeatureStore.GetOrNullAsync(feature.Name, Name, editionId.Value.ToString()); } + + protected virtual async Task FindEditionIdAsync() + { + var editionId = PrincipalAccessor.Principal?.FindEditionId(); + if (editionId != null) + { + return editionId; + } + + if (CurrentTenant.Id == null) + { + return null; + } + + var tenant = await TenantStore.FindAsync(CurrentTenant.Id.Value); + return tenant?.EditionId; + } } diff --git a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs index 9a2f53b988..da6b75b4b8 100644 --- a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs +++ b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageCompressorContributor.cs @@ -5,9 +5,6 @@ using System.Threading.Tasks; using Microsoft.Extensions.Options; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.Formats.Webp; using Volo.Abp.DependencyInjection; using Volo.Abp.Http; @@ -32,7 +29,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, return new ImageCompressResult(stream, ImageProcessState.Unsupported); } - var image = await Image.LoadAsync(stream, cancellationToken); + using var image = await Image.LoadAsync(stream, cancellationToken); if (!CanCompress(image.Metadata.DecodedImageFormat!.DefaultMimeType)) { @@ -46,7 +43,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, return new ImageCompressResult(memoryStream, ImageProcessState.Done); } - memoryStream.Dispose(); + await memoryStream.DisposeAsync(); return new ImageCompressResult(stream, ImageProcessState.Canceled); } @@ -69,7 +66,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, } var newBytes = await result.Result.GetAllBytesAsync(cancellationToken); - result.Result.Dispose(); + await result.Result.DisposeAsync(); return new ImageCompressResult(newBytes, result.State); } @@ -100,7 +97,7 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, } catch { - memoryStream.Dispose(); + await memoryStream.DisposeAsync(); throw; } } @@ -110,11 +107,11 @@ public class ImageSharpImageCompressorContributor : IImageCompressorContributor, switch (format.DefaultMimeType) { case MimeTypes.Image.Jpeg: - return Options.JpegEncoder ?? new JpegEncoder(); + return Options.JpegEncoder; case MimeTypes.Image.Png: - return Options.PngEncoder ?? new PngEncoder(); + return Options.PngEncoder; case MimeTypes.Image.Webp: - return Options.WebpEncoder ?? new WebpEncoder(); + return Options.WebpEncoder; default: throw new NotSupportedException($"No encoder available for the given format: {format.Name}"); } diff --git a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs index 6e17ddc9a8..e52155eaeb 100644 --- a/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs +++ b/framework/src/Volo.Abp.Imaging.ImageSharp/Volo/Abp/Imaging/ImageSharpImageResizerContributor.cs @@ -23,7 +23,7 @@ public class ImageSharpImageResizerContributor : IImageResizerContributor, ITran return new ImageResizeResult(stream, ImageProcessState.Unsupported); } - var image = await Image.LoadAsync(stream, cancellationToken); + using var image = await Image.LoadAsync(stream, cancellationToken); if (!CanResize(image.Metadata.DecodedImageFormat!.DefaultMimeType)) { @@ -49,7 +49,7 @@ public class ImageSharpImageResizerContributor : IImageResizerContributor, ITran } catch { - memoryStream.Dispose(); + await memoryStream.DisposeAsync(); throw; } } @@ -76,7 +76,7 @@ public class ImageSharpImageResizerContributor : IImageResizerContributor, ITran var newBytes = await result.Result.GetAllBytesAsync(cancellationToken); - result.Result.Dispose(); + await result.Result.DisposeAsync(); return new ImageResizeResult(newBytes, result.State); } diff --git a/framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpImageResizerContributor.cs b/framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpImageResizerContributor.cs index 760acd0916..0ba2c7c833 100644 --- a/framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpImageResizerContributor.cs +++ b/framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpImageResizerContributor.cs @@ -25,21 +25,19 @@ public class SkiaSharpImageResizerContributor : IImageResizerContributor, ITrans return new ImageResizeResult(bytes, ImageProcessState.Unsupported); } - using (var memoryStream = new MemoryStream(bytes)) - { - var result = await TryResizeAsync(memoryStream, resizeArgs, mimeType, cancellationToken); + using var memoryStream = new MemoryStream(bytes); + var result = await TryResizeAsync(memoryStream, resizeArgs, mimeType, cancellationToken); - if (result.State != ImageProcessState.Done) - { - return new ImageResizeResult(bytes, result.State); - } + if (result.State != ImageProcessState.Done) + { + return new ImageResizeResult(bytes, result.State); + } - var newBytes = await result.Result.GetAllBytesAsync(cancellationToken); + var newBytes = await result.Result.GetAllBytesAsync(cancellationToken); - result.Result.Dispose(); + result.Result.Dispose(); - return new ImageResizeResult(newBytes, result.State); - } + return new ImageResizeResult(newBytes, result.State); } public virtual async Task> TryResizeAsync(Stream stream, ImageResizeArgs resizeArgs, string? mimeType = null, CancellationToken cancellationToken = default) @@ -51,21 +49,14 @@ public class SkiaSharpImageResizerContributor : IImageResizerContributor, ITrans var (memoryBitmapStream, memorySkCodecStream) = await CreateMemoryStream(stream); - using (var original = SKBitmap.Decode(memoryBitmapStream)) - { - using (var resized = original.Resize(new SKImageInfo(resizeArgs.Width, resizeArgs.Height), Options.SKFilterQuality)) - { - using (var image = SKImage.FromBitmap(resized)) - { - using (var codec = SKCodec.Create(memorySkCodecStream)) - { - var memoryStream = new MemoryStream(); - image.Encode(codec.EncodedFormat, Options.Quality).SaveTo(memoryStream); - return new ImageResizeResult(memoryStream, ImageProcessState.Done); - } - } - } - } + using var original = SKBitmap.Decode(memoryBitmapStream); + using var resized = original.Resize(new SKImageInfo(resizeArgs.Width, resizeArgs.Height), Options.SKFilterQuality); + using var image = SKImage.FromBitmap(resized); + using var codec = SKCodec.Create(memorySkCodecStream); + var memoryStream = new MemoryStream(); + using var skData = image.Encode(codec.EncodedFormat, Options.Quality); + skData.SaveTo(memoryStream); + return new ImageResizeResult(memoryStream, ImageProcessState.Done); } protected virtual async Task<(MemoryStream, MemoryStream)> CreateMemoryStream(Stream stream) diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj b/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj index 15a6e37336..6d388b5764 100644 --- a/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj @@ -20,6 +20,9 @@ + + + diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/Clients/AbpMongoClientFactory.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/Clients/AbpMongoClientFactory.cs new file mode 100644 index 0000000000..983f7e067e --- /dev/null +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/Clients/AbpMongoClientFactory.cs @@ -0,0 +1,44 @@ +using System.Collections.Concurrent; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using MongoDB.Driver; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.MongoDB.Clients; + +public class AbpMongoClientFactory : IAbpMongoClientFactory, ISingletonDependency +{ + protected ConcurrentDictionary ClientCache { get; } + protected AbpMongoDbContextOptions Options { get; } + + public AbpMongoClientFactory(IOptions options) + { + Options = options.Value; + ClientCache = new ConcurrentDictionary(); + } + + public virtual Task GetAsync(MongoUrl mongoUrl) + { + Check.NotNull(mongoUrl, nameof(mongoUrl)); + + return Task.FromResult( + ClientCache.GetOrAdd(mongoUrl.ToString(), _ => + { + var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl); + Options.MongoClientSettingsConfigurer?.Invoke(mongoClientSettings); + return new MongoClient(mongoClientSettings); + })); + } + + public virtual MongoClient Get(MongoUrl mongoUrl) + { + Check.NotNull(mongoUrl, nameof(mongoUrl)); + + return ClientCache.GetOrAdd(mongoUrl.ToString(), _ => + { + var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl); + Options.MongoClientSettingsConfigurer?.Invoke(mongoClientSettings); + return new MongoClient(mongoClientSettings); + }); + } +} diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/Clients/IAbpMongoClientFactory.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/Clients/IAbpMongoClientFactory.cs new file mode 100644 index 0000000000..bf0d20d3ae --- /dev/null +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/Clients/IAbpMongoClientFactory.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using MongoDB.Driver; + +namespace Volo.Abp.MongoDB.Clients; + +public interface IAbpMongoClientFactory +{ + Task GetAsync(MongoUrl mongoUrl); + + [Obsolete("Use GetAsync method")] + MongoClient Get(MongoUrl mongoUrl); +} diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventInbox.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventInbox.cs index 9d1b706d8b..e5d726526b 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventInbox.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DistributedEvents/MongoDbContextEventInbox.cs @@ -64,7 +64,7 @@ public class MongoDbContextEventInbox : IMongoDbContextEventInb var outgoingEventRecords = await dbContext .IncomingEvents .AsQueryable() - .Where(x => !x.Processed) + .Where(x => x.Processed == false) .WhereIf(transformedFilter != null, transformedFilter!) .OrderBy(x => x.CreationTime) .Take(maxCount) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs index 1585bc1332..acea595dce 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs @@ -4,11 +4,11 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using Volo.Abp.Data; using Volo.Abp.MongoDB; +using Volo.Abp.MongoDB.Clients; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; @@ -24,23 +24,23 @@ public class UnitOfWorkMongoDbContextProvider : IMongoDbContext protected readonly IConnectionStringResolver ConnectionStringResolver; protected readonly ICancellationTokenProvider CancellationTokenProvider; protected readonly ICurrentTenant CurrentTenant; - protected readonly AbpMongoDbContextOptions Options; protected readonly IMongoDbContextTypeProvider DbContextTypeProvider; + protected readonly IAbpMongoClientFactory MongoClientFactory; public UnitOfWorkMongoDbContextProvider( IUnitOfWorkManager unitOfWorkManager, IConnectionStringResolver connectionStringResolver, ICancellationTokenProvider cancellationTokenProvider, ICurrentTenant currentTenant, - IOptions options, - IMongoDbContextTypeProvider dbContextTypeProvider) + IMongoDbContextTypeProvider dbContextTypeProvider, + IAbpMongoClientFactory mongoClientFactory) { UnitOfWorkManager = unitOfWorkManager; ConnectionStringResolver = connectionStringResolver; CancellationTokenProvider = cancellationTokenProvider; CurrentTenant = currentTenant; DbContextTypeProvider = dbContextTypeProvider; - Options = options.Value; + MongoClientFactory = mongoClientFactory; Logger = NullLogger>.Instance; } @@ -77,12 +77,11 @@ public class UnitOfWorkMongoDbContextProvider : IMongoDbContext databaseName = ConnectionStringNameAttribute.GetConnStringName(targetDbContextType); } - //TODO: Create only single MongoDbClient per connection string in an application (extract MongoClientCache for example). var databaseApi = unitOfWork.GetOrAddDatabaseApi( dbContextKey, () => new MongoDbDatabaseApi(CreateDbContext(unitOfWork, mongoUrl, databaseName))); - return (TMongoDbContext)((MongoDbDatabaseApi) databaseApi).DbContext; + return (TMongoDbContext)((MongoDbDatabaseApi)databaseApi).DbContext; } public virtual async Task GetDbContextAsync(CancellationToken cancellationToken = default) @@ -121,14 +120,13 @@ public class UnitOfWorkMongoDbContextProvider : IMongoDbContext unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); } - return (TMongoDbContext)((MongoDbDatabaseApi) databaseApi).DbContext; + return (TMongoDbContext)((MongoDbDatabaseApi)databaseApi).DbContext; } [Obsolete("Use CreateDbContextAsync")] - private TMongoDbContext CreateDbContext(IUnitOfWork unitOfWork, MongoUrl mongoUrl, string databaseName) { - var client = CreateMongoClient(mongoUrl); + var client = MongoClientFactory.Get(mongoUrl); var database = client.GetDatabase(databaseName); if (unitOfWork.Options.IsTransactional) @@ -148,7 +146,7 @@ public class UnitOfWorkMongoDbContextProvider : IMongoDbContext string databaseName, CancellationToken cancellationToken = default) { - var client = CreateMongoClient(mongoUrl); + var client = await MongoClientFactory.GetAsync(mongoUrl); var database = client.GetDatabase(databaseName); if (unitOfWork.Options.IsTransactional) @@ -297,14 +295,6 @@ public class UnitOfWorkMongoDbContextProvider : IMongoDbContext return ConnectionStringResolver.Resolve(dbContextType); } - protected virtual MongoClient CreateMongoClient(MongoUrl mongoUrl) - { - var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl); - Options.MongoClientSettingsConfigurer?.Invoke(mongoClientSettings); - - return new MongoClient(mongoClientSettings); - } - protected virtual CancellationToken GetCancellationToken(CancellationToken preferredValue = default) { return CancellationTokenProvider.FallbackToProvider(preferredValue); diff --git a/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs b/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs index 29b0971708..674bce6e94 100644 --- a/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs +++ b/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs @@ -17,6 +17,8 @@ public class TenantConfiguration public bool IsActive { get; set; } + public Guid? EditionId { get; set; } + public TenantConfiguration() { IsActive = true; @@ -33,11 +35,12 @@ public class TenantConfiguration ConnectionStrings = new ConnectionStrings(); } - public TenantConfiguration(Guid id, [NotNull] string name, [NotNull] string normalizedName) + public TenantConfiguration(Guid id, [NotNull] string name, [NotNull] string normalizedName, Guid? editionId = null) : this(id, name) { Check.NotNull(normalizedName, nameof(normalizedName)); NormalizedName = normalizedName; + EditionId = editionId; } } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/AbpRabbitMqModule.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/AbpRabbitMqModule.cs index da010b83c9..74b41dea23 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/AbpRabbitMqModule.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/AbpRabbitMqModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Json; using Volo.Abp.Modularity; using Volo.Abp.Threading; @@ -19,7 +20,6 @@ public class AbpRabbitMqModule : AbpModule { foreach (var connectionFactory in options.Connections.Values) { - connectionFactory.DispatchConsumersAsync = true; connectionFactory.AutomaticRecoveryEnabled = false; } }); @@ -27,12 +27,17 @@ public class AbpRabbitMqModule : AbpModule public override void OnApplicationShutdown(ApplicationShutdownContext context) { - context.ServiceProvider + AsyncHelper.RunSync(() => OnApplicationShutdownAsync(context)); + } + + public async override Task OnApplicationShutdownAsync(ApplicationShutdownContext context) + { + await context.ServiceProvider .GetRequiredService() - .Dispose(); + .DisposeAsync(); - context.ServiceProvider + await context.ServiceProvider .GetRequiredService() - .Dispose(); + .DisposeAsync(); } } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ChannelPool.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ChannelPool.cs index b7ed4c80c8..03d6029b69 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ChannelPool.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ChannelPool.cs @@ -3,10 +3,12 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using RabbitMQ.Client; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.RabbitMQ; @@ -16,6 +18,8 @@ public class ChannelPool : IChannelPool, ISingletonDependency protected ConcurrentDictionary Channels { get; } + protected SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); + protected bool IsDisposed { get; private set; } protected TimeSpan TotalDisposeWaitDuration { get; set; } = TimeSpan.FromSeconds(10); @@ -29,28 +33,54 @@ public class ChannelPool : IChannelPool, ISingletonDependency Logger = NullLogger.Instance; } - public virtual IChannelAccessor Acquire(string? channelName = null, string? connectionName = null) + public virtual async Task AcquireAsync(string? channelName = null, string? connectionName = null) { CheckDisposed(); channelName = channelName ?? ""; - var poolItem = Channels.GetOrAdd( - channelName, - _ => new ChannelPoolItem(CreateChannel(channelName, connectionName)) - ); + ChannelPoolItem poolItem; + + if (Channels.TryGetValue(channelName, out var existingChannelPoolItem)) + { + poolItem = existingChannelPoolItem; + } + else + { + using (await Semaphore.LockAsync()) + { + if (Channels.TryGetValue(channelName, out var existingChannelPoolItem2)) + { + poolItem = existingChannelPoolItem2; + } + else + { + poolItem = new ChannelPoolItem(await CreateChannelAsync(channelName, connectionName)); + Channels.TryAdd(channelName, poolItem); + } + } + } poolItem.Acquire(); if (poolItem.Channel.IsClosed) { - poolItem.Dispose(); + await poolItem.DisposeAsync(); Channels.TryRemove(channelName, out _); - poolItem = Channels.GetOrAdd( - channelName, - _ => new ChannelPoolItem(CreateChannel(channelName, connectionName)) - ); - + + using (await Semaphore.LockAsync()) + { + if (Channels.TryGetValue(channelName, out var existingChannelPoolItem3)) + { + poolItem = existingChannelPoolItem3; + } + else + { + poolItem = new ChannelPoolItem(await CreateChannelAsync(channelName, connectionName)); + Channels.TryAdd(channelName, poolItem); + } + } + poolItem.Acquire(); } @@ -61,14 +91,14 @@ public class ChannelPool : IChannelPool, ISingletonDependency ); } - protected virtual IModel CreateChannel(string channelName, string? connectionName) + protected virtual async Task CreateChannelAsync(string channelName, string? connectionName) { - return ConnectionPool - .Get(connectionName) - .CreateModel(); + return await (await ConnectionPool + .GetAsync(connectionName)) + .CreateChannelAsync(); } - protected void CheckDisposed() + protected virtual void CheckDisposed() { if (IsDisposed) { @@ -76,7 +106,7 @@ public class ChannelPool : IChannelPool, ISingletonDependency } } - public void Dispose() + public async ValueTask DisposeAsync() { if (IsDisposed) { @@ -104,10 +134,12 @@ public class ChannelPool : IChannelPool, ISingletonDependency try { poolItem.WaitIfInUse(remainingWaitDuration); - poolItem.Dispose(); + await poolItem.DisposeAsync(); } catch - { } + { + // ignored + } poolItemDisposeStopwatch.Stop(); @@ -128,9 +160,9 @@ public class ChannelPool : IChannelPool, ISingletonDependency Channels.Clear(); } - protected class ChannelPoolItem : IDisposable + protected class ChannelPoolItem : IAsyncDisposable { - public IModel Channel { get; } + public IChannel Channel { get; } public bool IsInUse { get => _isInUse; @@ -138,7 +170,7 @@ public class ChannelPool : IChannelPool, ISingletonDependency } private volatile bool _isInUse; - public ChannelPoolItem(IModel channel) + public ChannelPoolItem(IChannel channel) { Channel = channel; } @@ -178,21 +210,21 @@ public class ChannelPool : IChannelPool, ISingletonDependency } } - public void Dispose() + public async ValueTask DisposeAsync() { - Channel.Dispose(); + await Channel.DisposeAsync(); } } protected class ChannelAccessor : IChannelAccessor { - public IModel Channel { get; } + public IChannel Channel { get; } public string Name { get; } private readonly Action _disposeAction; - public ChannelAccessor(IModel channel, string name, Action disposeAction) + public ChannelAccessor(IChannel channel, string name, Action disposeAction) { _disposeAction = disposeAction; Name = name; diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs index 5f4556b96a..888de64613 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Options; using RabbitMQ.Client; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.RabbitMQ; @@ -11,55 +13,51 @@ public class ConnectionPool : IConnectionPool, ISingletonDependency { protected AbpRabbitMqOptions Options { get; } - protected ConcurrentDictionary> Connections { get; } + protected ConcurrentDictionary Connections { get; } + + protected SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); private bool _isDisposed; public ConnectionPool(IOptions options) { Options = options.Value; - Connections = new ConcurrentDictionary>(); + Connections = new ConcurrentDictionary(); } - public virtual IConnection Get(string? connectionName = null) + public virtual async Task GetAsync(string? connectionName = null) { - connectionName ??= RabbitMqConnections.DefaultConnectionName; - var connectionFactory = Options.Connections.GetOrDefault(connectionName); - try + using (await Semaphore.LockAsync()) { - var connection = GetConnection(connectionName, connectionFactory); - - if (connection.IsOpen) + connectionName ??= RabbitMqConnections.DefaultConnectionName; + + if (Connections.TryGetValue(connectionName, out var existingConnection) && existingConnection.IsOpen) { - return connection; + return existingConnection; } - - connection.Dispose(); - Connections.TryRemove(connectionName, out _); - return GetConnection(connectionName, connectionFactory); - } - catch (Exception) - { - Connections.TryRemove(connectionName, out _); - throw; + + if(existingConnection != null) + { + await existingConnection.DisposeAsync(); + } + + var connectionFactory = Options.Connections.GetOrDefault(connectionName); + var connection = await GetConnectionAsync(connectionName, connectionFactory); + Connections[connectionName] = connection; + return connection; } } - protected virtual IConnection GetConnection(string connectionName, ConnectionFactory connectionFactory) + protected virtual async Task GetConnectionAsync(string connectionName, ConnectionFactory connectionFactory) { - return Connections.GetOrAdd( - connectionName, () => new Lazy(() => - { - var hostnames = connectionFactory.HostName.TrimEnd(';').Split(';'); - // Handle Rabbit MQ Cluster. - return hostnames.Length == 1 - ? connectionFactory.CreateConnection() - : connectionFactory.CreateConnection(hostnames); - }) - ).Value; + var hostnames = connectionFactory.HostName.TrimEnd(';').Split(';'); + // Handle Rabbit MQ Cluster. + return hostnames.Length == 1 + ? await connectionFactory.CreateConnectionAsync() + : await connectionFactory.CreateConnectionAsync(hostnames); } - public void Dispose() + public async ValueTask DisposeAsync() { if (_isDisposed) { @@ -72,11 +70,11 @@ public class ConnectionPool : IConnectionPool, ISingletonDependency { try { - connection.Value.Dispose(); + await connection.DisposeAsync(); } catch { - + // ignored } } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs index 5c239893c7..4a5c0f01d0 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ExchangeDeclareConfiguration.cs @@ -12,19 +12,19 @@ public class ExchangeDeclareConfiguration public bool AutoDelete { get; set; } - public IDictionary Arguments { get; } + public IDictionary Arguments { get; } public ExchangeDeclareConfiguration( string exchangeName, string type, bool durable = false, bool autoDelete = false, - IDictionary? arguments = null) + IDictionary? arguments = null) { ExchangeName = exchangeName; Type = type; Durable = durable; AutoDelete = autoDelete; - Arguments = arguments?? new Dictionary(); + Arguments = arguments?? new Dictionary(); } } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelAccessor.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelAccessor.cs index ad8829f8ee..d4eb954a67 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelAccessor.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelAccessor.cs @@ -10,7 +10,7 @@ public interface IChannelAccessor : IDisposable /// Never dispose the object. /// Instead, dispose the after usage. /// - IModel Channel { get; } + IChannel Channel { get; } /// /// Name of the channel. diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelPool.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelPool.cs index 2ba6259fec..5a9611ad86 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelPool.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IChannelPool.cs @@ -1,8 +1,9 @@ using System; +using System.Threading.Tasks; namespace Volo.Abp.RabbitMQ; -public interface IChannelPool : IDisposable +public interface IChannelPool : IAsyncDisposable { - IChannelAccessor Acquire(string? channelName = null, string? connectionName = null); + Task AcquireAsync(string? channelName = null, string? connectionName = null); } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IConnectionPool.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IConnectionPool.cs index dc97476c84..02fdf286d9 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IConnectionPool.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IConnectionPool.cs @@ -1,9 +1,10 @@ using System; +using System.Threading.Tasks; using RabbitMQ.Client; namespace Volo.Abp.RabbitMQ; -public interface IConnectionPool : IDisposable +public interface IConnectionPool : IAsyncDisposable { - IConnection Get(string? connectionName = null); + Task GetAsync(string? connectionName = null); } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IRabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IRabbitMqMessageConsumer.cs index a24ad69a4a..8501b8958f 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IRabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/IRabbitMqMessageConsumer.cs @@ -11,5 +11,5 @@ public interface IRabbitMqMessageConsumer Task UnbindAsync(string routingKey); - void OnMessageReceived(Func callback); + void OnMessageReceived(Func callback); } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs index eb59ec3058..ebb2c3e1cc 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using JetBrains.Annotations; using RabbitMQ.Client; @@ -13,10 +14,10 @@ public class QueueDeclareConfiguration public bool Exclusive { get; set; } public bool AutoDelete { get; set; } - - public ushort? PrefetchCount { get; set; } - public IDictionary Arguments { get; } + public ushort? PrefetchCount { get; set; } + + public IDictionary Arguments { get; } public QueueDeclareConfiguration( [NotNull] string queueName, @@ -24,19 +25,19 @@ public class QueueDeclareConfiguration bool exclusive = false, bool autoDelete = false, ushort? prefetchCount = null, - IDictionary? arguments = null) + IDictionary? arguments = null) { QueueName = queueName; Durable = durable; Exclusive = exclusive; AutoDelete = autoDelete; - Arguments = arguments?? new Dictionary(); + Arguments = arguments?? new Dictionary(); PrefetchCount = prefetchCount; } - public virtual QueueDeclareOk Declare(IModel channel) + public virtual async Task DeclareAsync(IChannel channel) { - return channel.QueueDeclare( + return await channel.QueueDeclareAsync( queue: QueueName, durable: Durable, exclusive: Exclusive, diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs index 6f361f7670..74dac68a61 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs @@ -5,6 +5,7 @@ using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; using System.Collections.Concurrent; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; @@ -28,13 +29,13 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen protected string? ConnectionName { get; private set; } - protected ConcurrentBag> Callbacks { get; } + protected ConcurrentBag> Callbacks { get; } - protected IModel? Channel { get; private set; } + protected IChannel? Channel { get; private set; } protected ConcurrentQueue QueueBindCommands { get; } - protected object ChannelSendSyncLock { get; } = new object(); + protected SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); public RabbitMqMessageConsumer( IConnectionPool connectionPool, @@ -47,7 +48,7 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen Logger = NullLogger.Instance; QueueBindCommands = new ConcurrentQueue(); - Callbacks = new ConcurrentBag>(); + Callbacks = new ConcurrentBag>(); Timer.Period = 5000; //5 sec. Timer.Elapsed = Timer_Elapsed; @@ -88,21 +89,21 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen return; } - lock (ChannelSendSyncLock) + using (await Semaphore.LockAsync()) { if (QueueBindCommands.TryPeek(out var command)) { switch (command.Type) { case QueueBindType.Bind: - Channel.QueueBind( + await Channel.QueueBindAsync( queue: Queue.QueueName, exchange: Exchange.ExchangeName, routingKey: command.RoutingKey ); break; case QueueBindType.Unbind: - Channel.QueueUnbind( + await Channel.QueueUnbindAsync( queue: Queue.QueueName, exchange: Exchange.ExchangeName, routingKey: command.RoutingKey @@ -124,7 +125,7 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen } } - public virtual void OnMessageReceived(Func callback) + public virtual void OnMessageReceived(Func callback) { Callbacks.Add(callback); } @@ -144,11 +145,11 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen try { - Channel = ConnectionPool - .Get(ConnectionName) - .CreateModel(); + Channel = await (await ConnectionPool + .GetAsync(ConnectionName)) + .CreateChannelAsync(); - Channel.ExchangeDeclare( + await Channel.ExchangeDeclareAsync( exchange: Exchange.ExchangeName, type: Exchange.Type, durable: Exchange.Durable, @@ -156,7 +157,7 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen arguments: Exchange.Arguments ); - Channel.QueueDeclare( + await Channel.QueueDeclareAsync( queue: Queue.QueueName, durable: Queue.Durable, exclusive: Queue.Exclusive, @@ -166,13 +167,13 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen if (Queue.PrefetchCount.HasValue) { - Channel.BasicQos(0, Queue.PrefetchCount.Value, false); + await Channel.BasicQosAsync(0, Queue.PrefetchCount.Value, false); } - + var consumer = new AsyncEventingBasicConsumer(Channel); - consumer.Received += HandleIncomingMessageAsync; - - Channel.BasicConsume( + consumer.ReceivedAsync += HandleIncomingMessageAsync; + + await Channel.BasicConsumeAsync( queue: Queue.QueueName, autoAck: false, consumer: consumer @@ -194,17 +195,23 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen await callback(Channel!, basicDeliverEventArgs); } - Channel?.BasicAck(basicDeliverEventArgs.DeliveryTag, multiple: false); + if (Channel != null) + { + await Channel.BasicAckAsync(basicDeliverEventArgs.DeliveryTag, multiple: false); + } } catch (Exception ex) { try { - Channel?.BasicNack( - basicDeliverEventArgs.DeliveryTag, - multiple: false, - requeue: true - ); + if (Channel != null) + { + await Channel.BasicNackAsync( + basicDeliverEventArgs.DeliveryTag, + multiple: false, + requeue: true + ); + } } // ReSharper disable once EmptyGeneralCatchClause catch { } diff --git a/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.js b/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.js index 0e13317cbf..11cbe56803 100644 --- a/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.js +++ b/framework/src/Volo.Abp.Swashbuckle/wwwroot/swagger/ui/abp.js @@ -4,7 +4,9 @@ var abp = abp || {}; /* Application paths *****************************************/ //Current application root path (including virtual directory if exists). - abp.appPath = abp.appPath || '/'; + var baseElement = document.querySelector('base'); + var baseHref = baseElement ? baseElement.getAttribute('href') : null; + abp.appPath = baseHref || abp.appPath || '/'; /* UTILS ***************************************************/ diff --git a/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnActivated_Tests.cs b/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnActivated_Tests.cs index b2af6d85da..46c9ea2e8c 100644 --- a/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnActivated_Tests.cs +++ b/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnActivated_Tests.cs @@ -31,9 +31,9 @@ public class AutoFac_OnActivated_Tests : Autofac_Interception_Test var server = ServiceProvider.GetRequiredService(); server.Name.ShouldBe("MyServer12"); } -} -class MyServer -{ - public string Name { get; set; } = "MyServer"; + class MyServer + { + public string Name { get; set; } = "MyServer"; + } } diff --git a/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnRegistred_Tests.cs b/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnRegistred_Tests.cs new file mode 100644 index 0000000000..34b739cb7f --- /dev/null +++ b/framework/test/Volo.Abp.Autofac.Tests/Volo/Abp/Autofac/AutoFac_OnRegistred_Tests.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Autofac.Interception; +using Xunit; + +namespace Volo.Abp.Autofac; + +public class AutoFac_OnRegistred_Tests : Autofac_Interception_Test +{ + protected override Task AfterAddApplicationAsync(IServiceCollection services) + { + services.Add(ServiceDescriptor.KeyedTransient("key")); + services.OnRegistered(onServiceRegistredContext => + { + if (onServiceRegistredContext.ImplementationType == typeof(MyServer)) + { + onServiceRegistredContext.ServiceKey.ShouldBe("key"); + } + }); + + return base.AfterAddApplicationAsync(services); + } + + class MyServer + { + public string Name { get; set; } = "MyServer"; + } +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs index 480352d69c..4884f07d16 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Reflection; +using Microsoft.Extensions.Logging.Abstractions; using NSubstitute; using Shouldly; using Xunit; @@ -21,7 +22,7 @@ public class TypeFinder_Tests //Act - var typeFinder = new TypeFinder(fakeAssemblyFinder); + var typeFinder = new TypeFinder(NullLogger.Instance, fakeAssemblyFinder); //Assert diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs index 4c3b355367..2666695fd9 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Shouldly; using Volo.Abp.Domain.Repositories; using Volo.Abp.TestApp.Domain; @@ -55,4 +56,20 @@ public class EfCoreAsyncQueryableProvider_Tests : EntityFrameworkCoreTestBase await uow.CompleteAsync(); } } + + [Fact] + public async Task LastOrDefaultAsync_With_DefaultOrderBy() + { + using (var uow = _unitOfWorkManager.Begin()) + { + var lastOrDefault = await _personRepository.LastOrDefaultAsync(); + lastOrDefault.ShouldNotBeNull(); + + await Assert.ThrowsAsync(async () => + await (await _personRepository.GetQueryableAsync()).LastOrDefaultAsync() + ); + + await uow.CompleteAsync(); + } + } } diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Clients/MongoClient_Factory_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Clients/MongoClient_Factory_Tests.cs new file mode 100644 index 0000000000..df649132fa --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Clients/MongoClient_Factory_Tests.cs @@ -0,0 +1,79 @@ +using System; +using System.Threading.Tasks; +using MongoDB.Driver; +using Xunit; + +namespace Volo.Abp.MongoDB.Clients; + +[Collection(MongoTestCollection.Name)] +public class MongoClient_Factory_Tests : MongoDbTestBase +{ + private readonly IAbpMongoClientFactory _factory; + + public MongoClient_Factory_Tests() + { + _factory = GetRequiredService(); + } + + [Fact] + public async Task Should_Return_Same_Instance_For_Same_ConnectionString() + { + // Arrange + var mongoUrl = new MongoUrl("mongodb://localhost:27017/my-db"); + + // Act + var client1 = await _factory.GetAsync(mongoUrl); + var client2 = await _factory.GetAsync(mongoUrl); + + // Assert + Assert.Same(client1, client2); + } + + [Fact] + public async Task Should_Return_Different_Instances_For_Different_ConnectionStrings() + { + // Arrange + var mongoUrl1 = new MongoUrl("mongodb://localhost:27017/db1"); + var mongoUrl2 = new MongoUrl("mongodb://localhost:27017/db2"); + + // Act + var client1 = await _factory.GetAsync(mongoUrl1); + var client2 = await _factory.GetAsync(mongoUrl2); + + // Assert + Assert.NotSame(client1, client2); + } + + [Fact] + public async Task Should_Not_Throw_For_Valid_But_Unreachable_Connection() + { + // Arrange + var mongoUrl = new MongoUrl("mongodb://unreachablehost:12345/any"); + + // Act + var client = await _factory.GetAsync(mongoUrl); + + // Assert + Assert.NotNull(client); // Even though it's not connectable now, the instance can be created + } + + [Fact] + public async Task Should_Be_ThreadSafe_When_Accessed_Concurrently() + { + var mongoUrl = new MongoUrl("mongodb://localhost:27017/threadsafe"); + var results = new MongoClient[100]; + + await Parallel.ForAsync(0, 100, async (i, _) => + { + results[i] = await _factory.GetAsync(mongoUrl); + }); + + Assert.All(results, client => Assert.Same(results[0], client)); + } + + [Fact] + public async Task Should_Throw_If_ConnectionString_Is_Null_Or_Empty() + { + await Assert.ThrowsAsync(() => _factory.GetAsync(null!)); + } +} diff --git a/latest-versions.json b/latest-versions.json index 0ced5df485..7e756d726b 100644 --- a/latest-versions.json +++ b/latest-versions.json @@ -1,5 +1,32 @@ [ - { + { + "version": "9.2.0", + "releaseDate": "", + "type": "stable", + "message": "", + "leptonx": { + "version": "4.2.0" + } + }, + { + "version": "9.1.3", + "releaseDate": "", + "type": "stable", + "message": "", + "leptonx": { + "version": "4.1.3" + } + }, + { + "version": "9.1.1", + "releaseDate": "", + "type": "stable", + "message": "", + "leptonx": { + "version": "4.1.1" + } + }, + { "version": "9.1.0", "releaseDate": "", "type": "stable", @@ -8,6 +35,24 @@ "version": "4.1.0" } }, + { + "version": "9.0.8", + "releaseDate": "", + "type": "stable", + "message": "", + "leptonx": { + "version": "4.0.9" + } + }, + { + "version": "9.0.7", + "releaseDate": "", + "type": "stable", + "message": "", + "leptonx": { + "version": "4.0.8" + } + }, { "version": "9.0.6", "releaseDate": "", diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj b/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj index e32c705afb..d8c149f8b5 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj +++ b/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj @@ -17,7 +17,6 @@ - diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj index e4235dbd94..6abd877a2c 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Volo.Abp.Account.Web.IdentityServer.csproj @@ -33,10 +33,6 @@ - - - - diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index c17eb1e28f..cef45c2f4f 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -75,7 +75,7 @@ public class LoginModel : AccountPageModel public virtual async Task OnGetAsync() { - LoginInput = new LoginInputModel(); + LoginInput ??= new LoginInputModel(); ExternalProviders = await GetExternalProviders(); diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml index 145fd82d0d..4b3d2a67dc 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.cshtml @@ -13,6 +13,11 @@ } + +@section styles { + +} + @if (!Model.ReturnUrl.IsNullOrWhiteSpace()) { @@ -31,8 +36,6 @@ @foreach (var group in Model.ProfileManagementPageCreationContext.Groups) { -

@group.DisplayName

-
@await Component.InvokeAsync(group.ComponentType, new { parameter = group.Parameter diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.css b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.css new file mode 100644 index 0000000000..1493caceac --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Manage.css @@ -0,0 +1,3 @@ +#ProfileManagementWrapper .tab-content { + padding-top: 0 !important; +} \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AuditLogExcelFileConsts.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AuditLogExcelFileConsts.cs new file mode 100644 index 0000000000..7e74632910 --- /dev/null +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/AuditLogExcelFileConsts.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.AuditLogging; + +public static class AuditLogExcelFileConsts +{ + /// + /// Default value: 256 + /// + public static int MaxFileNameLength { get; set; } = 256; +} diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ar.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ar.json index 58f1b5bf7a..86a9ad9581 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ar.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ar.json @@ -79,9 +79,39 @@ "DurationMs": "المدة (مللي ثانية)", "StartDate": "تاريخ البدء", "EndDate": "تاريخ الانتهاء", - "Feature:AuditLoggingGroup": "تدوين التسجيل", + "Feature:AuditLoggingGroup": "تسجيل التدقيق", "Feature:AuditLoggingEnable": "تمكين صفحة تسجيل التدقيق", - "Feature:AuditLoggingEnableDescription": "تفعيل صفحة تسجيل التدقيق في التطبيق.", - "TenantId": "معرف المستأجر" + "Feature:AuditLoggingEnableDescription": "تمكين صفحة تسجيل التدقيق في التطبيق.", + "Feature:AuditLoggingSettingManagementEnable": "تمكين إدارة إعدادات تسجيل التدقيق", + "Feature:AuditLoggingSettingManagementEnableDescription": "تمكين تكوين إدارة إعدادات تسجيل التدقيق داخل التطبيق.", + "InvalidAuditLogDeletionSettings": "إعدادات حذف سجل التدقيق غير صالحة. إذا تم تمكين الحذف، يجب أن تكون الفترة أكبر من 0 أيام.", + "AuditLogSettingsGeneral": "عام", + "AuditLogSettingsGlobal": "عالمي", + "DisplayName:IsPeriodicDeleterEnabled": "تمكين خدمة التنظيف على مستوى النظام", + "Description:IsPeriodicDeleterEnabled": "إذا تم تعطيل هذا الخيار، فلن يعمل المحذف الدوري. لن يتم حذف سجلات التدقيق تلقائياً.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "تمكين خدمة التنظيف لجميع المستأجرين والمضيف", + "Description:GlobalIsExpiredDeleterEnabled": "إذا تم تمكين هذا الخيار، سيتم حذف جميع العناصر المنتهية الصلاحية للمستأجرين والمضيف تلقائياً ما لم يكن لديها إعداد محدد.", + "DisplayName:IsExpiredDeleterEnabled": "تمكين خدمة التنظيف", + "Description:IsExpiredDeleterEnabled": "إذا تم تمكين هذا الخيار، سيتم حذف العناصر المنتهية الصلاحية تلقائياً.", + "DisplayName:ExpiredDeleterPeriod": "فترة حذف العناصر المنتهية الصلاحية", + "Description:ExpiredDeleterPeriod": "حدد عدد الأيام التي سيتم بعدها حذف العناصر المنتهية الصلاحية تلقائياً.", + "ExpiredDeleterPeriodUnit": "يوم (أيام)", + "AuditLogsBeforeXWillBeDeleted": "سيتم حذف سجلات التدقيق قبل {0}.", + "TenantId": "معرف المستأجر", + "Permission:Export": "تصدير سجلات التدقيق", + "ExportToExcel": "تصدير إلى Excel", + "Exporting": "جاري التصدير", + "ExportCompleted": "تم إكمال التصدير بنجاح", + "ExportFailed": "فشل التصدير", + "ExportJobQueued": "تم وضع مهمة التصدير في الطابور لـ {0} سجل. ستتلقى بريداً إلكترونياً عند اكتمال التصدير.", + "ExportReady": "تم إكمال التصدير لـ {0} سجل وجاهز للتنزيل.", + "FileName": "اسم الملف", + "TotalRecords": "إجمالي السجلات", + "ExcelFileAttachedMessage": "ملف Excel مرفق بهذا البريد الإلكتروني.", + "EntityChangeExportCompletedSubject": "تم إكمال تصدير تغييرات الكيان", + "AuditLogExportCompletedSubject": "تم إكمال تصدير سجل التدقيق", + "DownloadLinkExplanation": "يمكنك تنزيل الملف باستخدام الرابط أدناه حتى {0} (UTC)", + "DownloadNow": "تنزيل الآن", + "TryAgainMessage": "الرجاء المحاولة مرة أخرى. إذا استمرت المشكلة، يرجى الاتصال بالدعم." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/cs.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/cs.json index b415c41556..a98da37703 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/cs.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/cs.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Protokolování auditu", "Feature:AuditLoggingEnable": "Povolena stránka protokolování auditu", "Feature:AuditLoggingEnableDescription": "Povolit stránku protokolování auditu v aplikaci.", - "TenantId": "ID nájemce" + "Feature:AuditLoggingSettingManagementEnable": "Povolit správu nastavení protokolování auditu", + "Feature:AuditLoggingSettingManagementEnableDescription": "Povolit konfiguraci správy nastavení protokolování auditu v aplikaci.", + "InvalidAuditLogDeletionSettings": "Neplatná nastavení mazání protokolu auditu. Pokud je mazání povoleno, období by mělo být větší než 0 dní.", + "AuditLogSettingsGeneral": "Obecné", + "AuditLogSettingsGlobal": "Globální", + "DisplayName:IsPeriodicDeleterEnabled": "Povolit službu čištění v celém systému", + "Description:IsPeriodicDeleterEnabled": "Pokud je tato možnost zakázána, periodický mazač nebude fungovat. Protokoly auditu nebudou automaticky mazány.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Povolit službu čištění pro všechny nájemce a hostitele", + "Description:GlobalIsExpiredDeleterEnabled": "Pokud je tato možnost povolena, všechny prošlé položky nájemců a hostitele budou automaticky smazány, pokud nemají specifické nastavení.", + "DisplayName:IsExpiredDeleterEnabled": "Povolit službu čištění", + "Description:IsExpiredDeleterEnabled": "Pokud je tato možnost povolena, prošlé položky budou automaticky smazány.", + "DisplayName:ExpiredDeleterPeriod": "Období mazání prošlých položek", + "Description:ExpiredDeleterPeriod": "Nastavte počet dní, po kterých budou prošlé položky automaticky smazány.", + "ExpiredDeleterPeriodUnit": "den(dny)", + "AuditLogsBeforeXWillBeDeleted": "Protokoly auditu před {0} budou smazány.", + "TenantId": "ID nájemce", + "Permission:Export": "Exportovat protokoly auditu", + "ExportToExcel": "Exportovat do Excelu", + "Exporting": "Exportování", + "ExportCompleted": "Export úspěšně dokončen", + "ExportFailed": "Export se nezdařil", + "ExportJobQueued": "Úloha exportu byla zařazena do fronty pro {0} záznamů. Obdržíte e-mail, když bude export dokončen.", + "ExportReady": "Export dokončen pro {0} záznamů a připraven ke stažení.", + "FileName": "Název souboru", + "TotalRecords": "Celkem záznamů", + "ExcelFileAttachedMessage": "Soubor Excel je připojen k tomuto e-mailu.", + "EntityChangeExportCompletedSubject": "Export změn entit dokončen", + "AuditLogExportCompletedSubject": "Export protokolu auditu dokončen", + "DownloadLinkExplanation": "Soubor můžete stáhnout pomocí odkazu níže až do {0} (UTC)", + "DownloadNow": "Stáhnout nyní", + "TryAgainMessage": "Zkuste to prosím znovu. Pokud problém přetrvává, kontaktujte podporu." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de-DE.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de-DE.json index 512556988f..334ada8c9a 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de-DE.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de-DE.json @@ -81,6 +81,9 @@ "Feature:AuditLoggingGroup": "Audit-Protokollierung", "Feature:AuditLoggingEnable": "Aktivieren Sie die Überwachungsprotokollseite", "Feature:AuditLoggingEnableDescription": "Aktivieren Sie die Überwachungsprotokollseite in der App.", - "TenantId": "Mandanten-ID" + "TenantId": "Mandanten-ID", + "DownloadLinkExplanation": "Sie können die Datei über den Link unten bis {0} (UTC) herunterladen", + "DownloadNow": "Jetzt herunterladen", + "TryAgainMessage": "Bitte versuchen Sie es erneut. Wenn das Problem weiterhin besteht, wenden Sie sich bitte an den Support." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de.json index 06d2a825f4..cc316ff867 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/de.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Audit-Protokollierung", "Feature:AuditLoggingEnable": "Aktivierte Audit-Logging-Seite", "Feature:AuditLoggingEnableDescription": "Aktivieren Sie die Audit-Logging-Seite in der Anwendung.", - "TenantId": "Mandanten-ID" + "Feature:AuditLoggingSettingManagementEnable": "Audit-Log-Einstellungsverwaltung aktivieren", + "Feature:AuditLoggingSettingManagementEnableDescription": "Aktivieren Sie die Konfiguration der Audit-Log-Einstellungsverwaltung in der Anwendung.", + "InvalidAuditLogDeletionSettings": "Ungültige Audit-Log-Löscheinstellungen. Wenn das Löschen aktiviert ist, sollte der Zeitraum größer als 0 Tage sein.", + "AuditLogSettingsGeneral": "Allgemein", + "AuditLogSettingsGlobal": "Global", + "DisplayName:IsPeriodicDeleterEnabled": "Bereinigungsdienst systemweit aktivieren", + "Description:IsPeriodicDeleterEnabled": "Wenn diese Option deaktiviert ist, funktioniert der periodische Löscher nicht. Audit-Logs werden nicht automatisch gelöscht.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Bereinigungsdienst für alle Mandanten und Host aktivieren", + "Description:GlobalIsExpiredDeleterEnabled": "Wenn diese Option aktiviert ist, werden alle abgelaufenen Elemente der Mandanten und des Hosts automatisch gelöscht, es sei denn, es gibt eine spezifische Einstellung.", + "DisplayName:IsExpiredDeleterEnabled": "Bereinigungsdienst aktivieren", + "Description:IsExpiredDeleterEnabled": "Wenn diese Option aktiviert ist, werden abgelaufene Elemente automatisch gelöscht.", + "DisplayName:ExpiredDeleterPeriod": "Löschzeitraum für abgelaufene Elemente", + "Description:ExpiredDeleterPeriod": "Legen Sie die Anzahl der Tage fest, nach denen abgelaufene Elemente automatisch gelöscht werden.", + "ExpiredDeleterPeriodUnit": "Tag(e)", + "AuditLogsBeforeXWillBeDeleted": "Audit-Logs vor {0} werden gelöscht.", + "TenantId": "Mandanten-ID", + "Permission:Export": "Audit-Logs exportieren", + "ExportToExcel": "Nach Excel exportieren", + "Exporting": "Exportieren", + "ExportCompleted": "Export erfolgreich abgeschlossen", + "ExportFailed": "Export fehlgeschlagen", + "ExportJobQueued": "Export-Job wurde für {0} Datensätze in die Warteschlange eingereiht. Sie erhalten eine E-Mail, wenn der Export abgeschlossen ist.", + "ExportReady": "Export für {0} Datensätze abgeschlossen und zum Download bereit.", + "FileName": "Dateiname", + "TotalRecords": "Gesamtdatensätze", + "ExcelFileAttachedMessage": "Die Excel-Datei ist an diese E-Mail angehängt.", + "EntityChangeExportCompletedSubject": "Entity-Änderungsexport abgeschlossen", + "AuditLogExportCompletedSubject": "Audit-Log-Export abgeschlossen", + "DownloadLinkExplanation": "Sie können die Datei über den Link unten bis {0} (UTC) herunterladen", + "DownloadNow": "Jetzt herunterladen", + "TryAgainMessage": "Bitte versuchen Sie es erneut. Wenn das Problem weiterhin besteht, wenden Sie sich bitte an den Support." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json index ac03e75db7..e837e01666 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json @@ -97,6 +97,21 @@ "Description:ExpiredDeleterPeriod": "Set the number of days after which expired items will be automatically deleted.", "ExpiredDeleterPeriodUnit": "day(s)", "AuditLogsBeforeXWillBeDeleted": "Audit logs before {0} will be deleted.", - "TenantId": "Tenant Id" + "TenantId": "Tenant Id", + "Permission:Export": "Export audit logs", + "ExportToExcel": "Export to Excel", + "Exporting": "Exporting", + "ExportCompleted": "Export completed successfully", + "ExportFailed": "Export failed", + "ExportJobQueued": "Export job has been queued for {0} records. You will receive an email when the export is completed.", + "ExportReady": "Export completed for {0} records and is ready for download.", + "FileName": "File name", + "TotalRecords": "Total records", + "ExcelFileAttachedMessage": "The Excel file is attached to this email.", + "EntityChangeExportCompletedSubject": "Entity change export completed", + "AuditLogExportCompletedSubject": "Audit log export completed", + "DownloadLinkExplanation": "You can download the file using the link below until {0} (UTC)", + "DownloadNow": "Download now", + "TryAgainMessage": "Please try again. If the problem persists, please contact support." } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/es.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/es.json index 310b5de91b..518c29d0ea 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/es.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/es.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Registros de auditoría", "Feature:AuditLoggingEnable": "Habilitar la página de registro de auditoría", "Feature:AuditLoggingEnableDescription": "Habilite la página de registro de auditoría en la aplicación.", - "TenantId": "ID de inquilino" + "Feature:AuditLoggingSettingManagementEnable": "Habilitar la gestión de configuración de registro de auditoría", + "Feature:AuditLoggingSettingManagementEnableDescription": "Habilite la configuración de la gestión de configuración de registro de auditoría dentro de la aplicación.", + "InvalidAuditLogDeletionSettings": "Configuración de eliminación de registro de auditoría no válida. Si la eliminación está habilitada, el período debe ser mayor a 0 días.", + "AuditLogSettingsGeneral": "General", + "AuditLogSettingsGlobal": "Global", + "DisplayName:IsPeriodicDeleterEnabled": "Habilitar servicio de limpieza en todo el sistema", + "Description:IsPeriodicDeleterEnabled": "Si esta opción está deshabilitada, el eliminador periódico no funcionará. Los registros de auditoría no se eliminarán automáticamente.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Habilitar servicio de limpieza para todos los inquilinos y host", + "Description:GlobalIsExpiredDeleterEnabled": "Si esta opción está habilitada, todos los elementos vencidos de los inquilinos y el host se eliminarán automáticamente a menos que tenga una configuración específica.", + "DisplayName:IsExpiredDeleterEnabled": "Habilitar servicio de limpieza", + "Description:IsExpiredDeleterEnabled": "Si esta opción está habilitada, los elementos vencidos se eliminarán automáticamente.", + "DisplayName:ExpiredDeleterPeriod": "Período de eliminación de elementos vencidos", + "Description:ExpiredDeleterPeriod": "Establezca el número de días después de los cuales los elementos vencidos se eliminarán automáticamente.", + "ExpiredDeleterPeriodUnit": "día(s)", + "AuditLogsBeforeXWillBeDeleted": "Los registros de auditoría antes de {0} serán eliminados.", + "TenantId": "ID de inquilino", + "Permission:Export": "Exportar registros de auditoría", + "ExportToExcel": "Exportar a Excel", + "Exporting": "Exportando", + "ExportCompleted": "Exportación completada exitosamente", + "ExportFailed": "Exportación fallida", + "ExportJobQueued": "El trabajo de exportación ha sido puesto en cola para {0} registros. Recibirá un correo electrónico cuando se complete la exportación.", + "ExportReady": "Exportación completada para {0} registros y lista para descarga.", + "FileName": "Nombre del archivo", + "TotalRecords": "Total de registros", + "ExcelFileAttachedMessage": "El archivo de Excel está adjunto a este correo electrónico.", + "EntityChangeExportCompletedSubject": "Exportación de cambios de entidad completada", + "AuditLogExportCompletedSubject": "Exportación de registro de auditoría completada", + "DownloadLinkExplanation": "Puede descargar el archivo usando el enlace a continuación hasta {0} (UTC)", + "DownloadNow": "Descargar ahora", + "TryAgainMessage": "Por favor, inténtelo de nuevo. Si el problema persiste, contacte con soporte." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fi.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fi.json index 76b374f51a..a71a9cf5e8 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fi.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fi.json @@ -79,9 +79,39 @@ "DurationMs": "Kesto (ms)", "StartDate": "Aloituspäivämäärä", "EndDate": "Päättymispäivä", - "Feature:AuditLoggingGroup": "Tarkastusten kirjaaminen", - "Feature:AuditLoggingEnable": "Aktivoi auditointilokisivu", - "Feature:AuditLoggingEnableDescription": "Ota käyttöön tarkastuksen kirjaussivu sovelluksessa.", - "TenantId": "Vuokralaisen tunnus" + "Feature:AuditLoggingGroup": "Tarkastuslokin kirjaaminen", + "Feature:AuditLoggingEnable": "Ota käyttöön tarkastuslokin kirjaussivu", + "Feature:AuditLoggingEnableDescription": "Ota käyttöön tarkastuslokin kirjaussivu sovelluksessa.", + "Feature:AuditLoggingSettingManagementEnable": "Ota käyttöön tarkastuslokin asetusten hallinta", + "Feature:AuditLoggingSettingManagementEnableDescription": "Ota käyttöön tarkastuslokin asetusten hallinnan konfigurointi sovelluksessa.", + "InvalidAuditLogDeletionSettings": "Virheelliset tarkastuslokin poisto-asetukset. Jos poistaminen on käytössä, ajanjakson tulee olla suurempi kuin 0 päivää.", + "AuditLogSettingsGeneral": "Yleinen", + "AuditLogSettingsGlobal": "Globaali", + "DisplayName:IsPeriodicDeleterEnabled": "Ota käyttöön siivouspalvelu koko järjestelmässä", + "Description:IsPeriodicDeleterEnabled": "Jos tämä vaihtoehto on poistettu käytöstä, jaksollinen poistaja ei toimi. Tarkastuslokeja ei poisteta automaattisesti.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Ota käyttöön siivouspalvelu kaikille vuokralaisille ja isännälle", + "Description:GlobalIsExpiredDeleterEnabled": "Jos tämä vaihtoehto on käytössä, kaikki vuokralaisten ja isännän vanhentuneet kohteet poistetaan automaattisesti, ellei niillä ole erityistä asetusta.", + "DisplayName:IsExpiredDeleterEnabled": "Ota käyttöön siivouspalvelu", + "Description:IsExpiredDeleterEnabled": "Jos tämä vaihtoehto on käytössä, vanhentuneet kohteet poistetaan automaattisesti.", + "DisplayName:ExpiredDeleterPeriod": "Vanhentuneiden kohteiden poistojakso", + "Description:ExpiredDeleterPeriod": "Aseta päivien määrä, jonka jälkeen vanhentuneet kohteet poistetaan automaattisesti.", + "ExpiredDeleterPeriodUnit": "päivä(ä)", + "AuditLogsBeforeXWillBeDeleted": "Tarkastuslokit ennen {0} poistetaan.", + "TenantId": "Vuokralaisen tunnus", + "Permission:Export": "Vie tarkastuslokit", + "ExportToExcel": "Vie Exceliin", + "Exporting": "Viedään", + "ExportCompleted": "Vienti suoritettu onnistuneesti", + "ExportFailed": "Vienti epäonnistui", + "ExportJobQueued": "Vientityö on asetettu jonoon {0} tietueelle. Saat sähköpostin, kun vienti on valmis.", + "ExportReady": "Vienti valmis {0} tietueelle ja valmis ladattavaksi.", + "FileName": "Tiedostonimi", + "TotalRecords": "Tietueiden kokonaismäärä", + "ExcelFileAttachedMessage": "Excel-tiedosto on liitetty tähän sähköpostiin.", + "EntityChangeExportCompletedSubject": "Entiteettimuutosten vienti valmis", + "AuditLogExportCompletedSubject": "Tarkastuslokin vienti valmis", + "DownloadLinkExplanation": "Voit ladata tiedoston alla olevan linkin kautta {0} (UTC) asti", + "DownloadNow": "Lataa nyt", + "TryAgainMessage": "Yritä uudelleen. Jos ongelma jatkuu, ota yhteyttä tukeen." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fr.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fr.json index 5ea79065aa..c12e499403 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fr.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/fr.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Journalisation d'audit", "Feature:AuditLoggingEnable": "Page de journalisation d'audit activée", "Feature:AuditLoggingEnableDescription": "Activez la page de journalisation d'audit dans l'application.", - "TenantId": "ID du locataire" + "Feature:AuditLoggingSettingManagementEnable": "Activer la gestion des paramètres de journalisation d'audit", + "Feature:AuditLoggingSettingManagementEnableDescription": "Activez la configuration de la gestion des paramètres de journalisation d'audit dans l'application.", + "InvalidAuditLogDeletionSettings": "Paramètres de suppression de journal d'audit non valides. Si la suppression est activée, la période doit être supérieure à 0 jour.", + "AuditLogSettingsGeneral": "Général", + "AuditLogSettingsGlobal": "Global", + "DisplayName:IsPeriodicDeleterEnabled": "Activer le service de nettoyage à l'échelle du système", + "Description:IsPeriodicDeleterEnabled": "Si cette option est désactivée, le suppresseur périodique ne fonctionnera pas. Les journaux d'audit ne seront pas supprimés automatiquement.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Activer le service de nettoyage pour tous les locataires et l'hôte", + "Description:GlobalIsExpiredDeleterEnabled": "Si cette option est activée, tous les éléments expirés des locataires et de l'hôte seront supprimés automatiquement, sauf s'il y a un paramètre spécifique.", + "DisplayName:IsExpiredDeleterEnabled": "Activer le service de nettoyage", + "Description:IsExpiredDeleterEnabled": "Si cette option est activée, les éléments expirés seront supprimés automatiquement.", + "DisplayName:ExpiredDeleterPeriod": "Période de suppression des éléments expirés", + "Description:ExpiredDeleterPeriod": "Définissez le nombre de jours après lesquels les éléments expirés seront automatiquement supprimés.", + "ExpiredDeleterPeriodUnit": "jour(s)", + "AuditLogsBeforeXWillBeDeleted": "Les journaux d'audit avant {0} seront supprimés.", + "TenantId": "ID du locataire", + "Permission:Export": "Exporter les journaux d'audit", + "ExportToExcel": "Exporter vers Excel", + "Exporting": "Exportation", + "ExportCompleted": "Exportation terminée avec succès", + "ExportFailed": "Échec de l'exportation", + "ExportJobQueued": "Le travail d'exportation a été mis en file d'attente pour {0} enregistrements. Vous recevrez un e-mail lorsque l'exportation sera terminée.", + "ExportReady": "Exportation terminée pour {0} enregistrements et prête pour le téléchargement.", + "FileName": "Nom du fichier", + "TotalRecords": "Total des enregistrements", + "ExcelFileAttachedMessage": "Le fichier Excel est joint à cet e-mail.", + "EntityChangeExportCompletedSubject": "Exportation des changements d'entité terminée", + "AuditLogExportCompletedSubject": "Exportation du journal d'audit terminée", + "DownloadLinkExplanation": "Vous pouvez télécharger le fichier en utilisant le lien ci-dessous jusqu'au {0} (UTC)", + "DownloadNow": "Télécharger maintenant", + "TryAgainMessage": "Veuillez réessayer. Si le problème persiste, veuillez contacter le support." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hi.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hi.json index 7e1e84de7e..b2e2788e52 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hi.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hi.json @@ -82,6 +82,9 @@ "Feature:AuditLoggingGroup": "ऑडिट लॉगिंग", "Feature:AuditLoggingEnable": "सक्षम ऑडिट लॉगिंग पृष्ठ", "Feature:AuditLoggingEnableDescription": "एप्लिकेशन में ऑडिट लॉगिंग पृष्ठ सक्षम करें।", - "TenantId": "किरायेदार आईडी" + "TenantId": "किरायेदार आईडी", + "DownloadLinkExplanation": "आप {0} (UTC) तक नीचे दिए गए लिंक का उपयोग करके फ़ाइल डाउनलोड कर सकते हैं", + "DownloadNow": "अभी डाउनलोड करें", + "TryAgainMessage": "कृपया पुनः प्रयास करें। यदि समस्या बनी रहती है, तो कृपया सहायता से संपर्क करें।" } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hr.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hr.json index ed6c345578..7d4a3f57b6 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hr.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hr.json @@ -82,6 +82,9 @@ "Feature:AuditLoggingGroup": "Zapisivanje revizije", "Feature:AuditLoggingEnable": "Omogućena stranica za bilježenje revizije", "Feature:AuditLoggingEnableDescription": "Omogućite stranicu za bilježenje revizije u aplikaciji.", - "TenantId": "ID stanara" + "TenantId": "ID stanara", + "DownloadLinkExplanation": "Datoteku možete preuzeti pomoću veze u nastavku do {0} (UTC)", + "DownloadNow": "Preuzmi odmah", + "TryAgainMessage": "Molimo pokušajte ponovno. Ako se problem nastavi, obratite se podršci." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hu.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hu.json index 816aa4c0d5..af744ac07b 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hu.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/hu.json @@ -80,8 +80,38 @@ "StartDate": "Kezdő dátum", "EndDate": "Befejezés dátuma", "Feature:AuditLoggingGroup": "Audit naplózás", - "Feature:AuditLoggingEnable": "Engedélyezett naplózási oldal", - "Feature:AuditLoggingEnableDescription": "Engedélyezze a naplózási oldalt az alkalmazásban.", - "TenantId": "Bérlő azonosító" + "Feature:AuditLoggingEnable": "Audit naplózási oldal engedélyezése", + "Feature:AuditLoggingEnableDescription": "Engedélyezze az audit naplózási oldalt az alkalmazásban.", + "Feature:AuditLoggingSettingManagementEnable": "Audit napló beállítások kezelésének engedélyezése", + "Feature:AuditLoggingSettingManagementEnableDescription": "Engedélyezze az audit napló beállítások kezelésének konfigurációját az alkalmazásban.", + "InvalidAuditLogDeletionSettings": "Érvénytelen audit napló törlési beállítások. Ha a törlés engedélyezett, az időszaknak nagyobbnak kell lennie 0 napnál.", + "AuditLogSettingsGeneral": "Általános", + "AuditLogSettingsGlobal": "Globális", + "DisplayName:IsPeriodicDeleterEnabled": "Takarítási szolgáltatás engedélyezése rendszerszinten", + "Description:IsPeriodicDeleterEnabled": "Ha ez az opció le van tiltva, a periodikus törlő nem fog működni. Az audit naplók nem lesznek automatikusan törölve.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Takarítási szolgáltatás engedélyezése minden bérlő és host számára", + "Description:GlobalIsExpiredDeleterEnabled": "Ha ez az opció engedélyezett, minden bérlő és host lejárt elemei automatikusan törölve lesznek, kivéve ha van specifikus beállítás.", + "DisplayName:IsExpiredDeleterEnabled": "Takarítási szolgáltatás engedélyezése", + "Description:IsExpiredDeleterEnabled": "Ha ez az opció engedélyezett, a lejárt elemek automatikusan törölve lesznek.", + "DisplayName:ExpiredDeleterPeriod": "Lejárt elemek törlési időszaka", + "Description:ExpiredDeleterPeriod": "Állítsa be a napok számát, amely után a lejárt elemek automatikusan törölve lesznek.", + "ExpiredDeleterPeriodUnit": "nap(ok)", + "AuditLogsBeforeXWillBeDeleted": "Az audit naplók {0} előtt törölve lesznek.", + "TenantId": "Bérlő azonosító", + "Permission:Export": "Audit naplók exportálása", + "ExportToExcel": "Exportálás Excelbe", + "Exporting": "Exportálás", + "ExportCompleted": "Exportálás sikeresen befejezve", + "ExportFailed": "Exportálás sikertelen", + "ExportJobQueued": "Exportálási feladat sorba állítva {0} rekordhoz. E-mailt fog kapni, amikor az exportálás befejeződött.", + "ExportReady": "Exportálás befejezve {0} rekordhoz és letöltésre kész.", + "FileName": "Fájlnév", + "TotalRecords": "Összes rekord", + "ExcelFileAttachedMessage": "Az Excel fájl csatolva van ehhez az e-mailhez.", + "EntityChangeExportCompletedSubject": "Entitás változás exportálás befejezve", + "AuditLogExportCompletedSubject": "Audit napló exportálás befejezve", + "DownloadLinkExplanation": "A fájlt letöltheti az alábbi linken keresztül {0} (UTC) időpontig", + "DownloadNow": "Letöltés most", + "TryAgainMessage": "Kérjük, próbálja újra. Ha a probléma továbbra is fennáll, forduljon az ügyfélszolgálathoz." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/is.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/is.json index fc556570ff..2d2f8915f3 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/is.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/is.json @@ -82,6 +82,9 @@ "Feature:AuditLoggingGroup": "Endurskoðunarskráning", "Feature:AuditLoggingEnable": "Virkjað endurskoðunarskráningarsíða", "Feature:AuditLoggingEnableDescription": "Virkjaðu endurskoðunarskráningarsíðu í forritinu.", - "TenantId": "Leigutakaauðkenni" + "TenantId": "Leigutakaauðkenni", + "DownloadLinkExplanation": "Þú getur sótt skrána með tenglinum hér að neðan til {0} (UTC)", + "DownloadNow": "Sækja núna", + "TryAgainMessage": "Vinsamlegast reyndu aftur. Ef vandamálið er viðvarandi, hafðu samband við þjónustuaðila." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/it.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/it.json index 6e3ef94959..b43511d03b 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/it.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/it.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Registrazione di controllo", "Feature:AuditLoggingEnable": "Pagina di registrazione di controllo abilitata", "Feature:AuditLoggingEnableDescription": "Abilita la pagina di registrazione dell'audit nell'applicazione.", - "TenantId": "ID inquilino" + "Feature:AuditLoggingSettingManagementEnable": "Abilita gestione impostazioni log di audit", + "Feature:AuditLoggingSettingManagementEnableDescription": "Abilita la configurazione della gestione delle impostazioni del log di audit nell'applicazione.", + "InvalidAuditLogDeletionSettings": "Impostazioni di eliminazione del log di audit non valide. Se l'eliminazione è abilitata, il periodo dovrebbe essere maggiore di 0 giorni.", + "AuditLogSettingsGeneral": "Generale", + "AuditLogSettingsGlobal": "Globale", + "DisplayName:IsPeriodicDeleterEnabled": "Abilita servizio di pulizia a livello di sistema", + "Description:IsPeriodicDeleterEnabled": "Se questa opzione è disabilitata, l'eliminatore periodico non funzionerà. I log di audit non verranno eliminati automaticamente.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Abilita servizio di pulizia per tutti i tenant e l'host", + "Description:GlobalIsExpiredDeleterEnabled": "Se questa opzione è abilitata, tutti gli elementi scaduti dei tenant e dell'host verranno eliminati automaticamente a meno che non abbiano un'impostazione specifica.", + "DisplayName:IsExpiredDeleterEnabled": "Abilita servizio di pulizia", + "Description:IsExpiredDeleterEnabled": "Se questa opzione è abilitata, gli elementi scaduti verranno eliminati automaticamente.", + "DisplayName:ExpiredDeleterPeriod": "Periodo di eliminazione elementi scaduti", + "Description:ExpiredDeleterPeriod": "Imposta il numero di giorni dopo i quali gli elementi scaduti verranno eliminati automaticamente.", + "ExpiredDeleterPeriodUnit": "giorno(i)", + "AuditLogsBeforeXWillBeDeleted": "I log di audit prima di {0} verranno eliminati.", + "TenantId": "ID inquilino", + "Permission:Export": "Esporta log di audit", + "ExportToExcel": "Esporta in Excel", + "Exporting": "Esportazione", + "ExportCompleted": "Esportazione completata con successo", + "ExportFailed": "Esportazione fallita", + "ExportJobQueued": "Il lavoro di esportazione è stato messo in coda per {0} record. Riceverai un'email quando l'esportazione sarà completata.", + "ExportReady": "Esportazione completata per {0} record e pronta per il download.", + "FileName": "Nome file", + "TotalRecords": "Record totali", + "ExcelFileAttachedMessage": "Il file Excel è allegato a questa email.", + "EntityChangeExportCompletedSubject": "Esportazione modifiche entità completata", + "AuditLogExportCompletedSubject": "Esportazione log di audit completata", + "DownloadLinkExplanation": "Puoi scaricare il file utilizzando il link qui sotto fino a {0} (UTC)", + "DownloadNow": "Scarica ora", + "TryAgainMessage": "Per favore riprova. Se il problema persiste, contatta il supporto." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/nl.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/nl.json index 289b2318e3..9b44a3c884 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/nl.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/nl.json @@ -79,9 +79,39 @@ "DurationMs": "Duur (ms)", "StartDate": "Begin datum", "EndDate": "Einddatum", - "Feature:AuditLoggingGroup": "Auditregistratie", - "Feature:AuditLoggingEnable": "Pagina voor auditregistratie ingeschakeld", - "Feature:AuditLoggingEnableDescription": "Schakel de auditlogboekpagina in de applicatie in.", - "TenantId": "Huurder-ID" + "Feature:AuditLoggingGroup": "Auditlogboekregistratie", + "Feature:AuditLoggingEnable": "Auditlogboekregistratiepagina ingeschakeld", + "Feature:AuditLoggingEnableDescription": "Schakel de auditlogboekregistratiepagina in de applicatie in.", + "Feature:AuditLoggingSettingManagementEnable": "Beheer van auditlog-instellingen inschakelen", + "Feature:AuditLoggingSettingManagementEnableDescription": "Schakel de configuratie van het beheer van auditlog-instellingen binnen de applicatie in.", + "InvalidAuditLogDeletionSettings": "Ongeldige instellingen voor het verwijderen van auditlogs. Als verwijdering is ingeschakeld, moet de periode groter zijn dan 0 dagen.", + "AuditLogSettingsGeneral": "Algemeen", + "AuditLogSettingsGlobal": "Globaal", + "DisplayName:IsPeriodicDeleterEnabled": "Opruimservice systeembreed inschakelen", + "Description:IsPeriodicDeleterEnabled": "Als deze optie is uitgeschakeld, werkt de periodieke verwijderaar niet. Auditlogs worden niet automatisch verwijderd.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Opruimservice inschakelen voor alle huurders en host", + "Description:GlobalIsExpiredDeleterEnabled": "Als deze optie is ingeschakeld, worden alle verlopen items van huurders en de host automatisch verwijderd, tenzij er een specifieke instelling is.", + "DisplayName:IsExpiredDeleterEnabled": "Opruimservice inschakelen", + "Description:IsExpiredDeleterEnabled": "Als deze optie is ingeschakeld, worden verlopen items automatisch verwijderd.", + "DisplayName:ExpiredDeleterPeriod": "Verwijderingsperiode voor verlopen items", + "Description:ExpiredDeleterPeriod": "Stel het aantal dagen in waarna verlopen items automatisch worden verwijderd.", + "ExpiredDeleterPeriodUnit": "dag(en)", + "AuditLogsBeforeXWillBeDeleted": "Auditlogs vóór {0} worden verwijderd.", + "TenantId": "Huurder-ID", + "Permission:Export": "Auditlogs exporteren", + "ExportToExcel": "Exporteren naar Excel", + "Exporting": "Exporteren", + "ExportCompleted": "Export succesvol voltooid", + "ExportFailed": "Export mislukt", + "ExportJobQueued": "Exporttaak is in de wachtrij geplaatst voor {0} records. U ontvangt een e-mail wanneer de export is voltooid.", + "ExportReady": "Export voltooid voor {0} records en klaar voor download.", + "FileName": "Bestandsnaam", + "TotalRecords": "Totaal aantal records", + "ExcelFileAttachedMessage": "Het Excel-bestand is bijgevoegd bij deze e-mail.", + "EntityChangeExportCompletedSubject": "Export van entiteitswijzigingen voltooid", + "AuditLogExportCompletedSubject": "Auditlog export voltooid", + "DownloadLinkExplanation": "U kunt het bestand downloaden via de onderstaande link tot {0} (UTC)", + "DownloadNow": "Download nu", + "TryAgainMessage": "Probeer het opnieuw. Als het probleem aanhoudt, neem dan contact op met de ondersteuning." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pl-PL.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pl-PL.json index 9f4f6db58f..17162d6af8 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pl-PL.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pl-PL.json @@ -80,8 +80,38 @@ "StartDate": "Data rozpoczęcia", "EndDate": "Data końcowa", "Feature:AuditLoggingGroup": "Rejestrowanie audytu", - "Feature:AuditLoggingEnable": "Włączono stronę rejestrowania audytu", + "Feature:AuditLoggingEnable": "Włącz stronę rejestrowania audytu", "Feature:AuditLoggingEnableDescription": "Włącz stronę rejestrowania audytu w aplikacji.", - "TenantId": "Identyfikator najemcy" + "Feature:AuditLoggingSettingManagementEnable": "Włącz zarządzanie ustawieniami dziennika audytu", + "Feature:AuditLoggingSettingManagementEnableDescription": "Włącz konfigurację zarządzania ustawieniami dziennika audytu w aplikacji.", + "InvalidAuditLogDeletionSettings": "Nieprawidłowe ustawienia usuwania dziennika audytu. Jeśli usuwanie jest włączone, okres powinien być większy niż 0 dni.", + "AuditLogSettingsGeneral": "Ogólne", + "AuditLogSettingsGlobal": "Globalne", + "DisplayName:IsPeriodicDeleterEnabled": "Włącz usługę czyszczenia w całym systemie", + "Description:IsPeriodicDeleterEnabled": "Jeśli ta opcja jest wyłączona, okresowy usuwacz nie będzie działać. Dzienniki audytu nie będą automatycznie usuwane.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Włącz usługę czyszczenia dla wszystkich najemców i hosta", + "Description:GlobalIsExpiredDeleterEnabled": "Jeśli ta opcja jest włączona, wszystkie wygasłe elementy najemców i hosta będą automatycznie usuwane, chyba że mają określone ustawienie.", + "DisplayName:IsExpiredDeleterEnabled": "Włącz usługę czyszczenia", + "Description:IsExpiredDeleterEnabled": "Jeśli ta opcja jest włączona, wygasłe elementy będą automatycznie usuwane.", + "DisplayName:ExpiredDeleterPeriod": "Okres usuwania wygasłych elementów", + "Description:ExpiredDeleterPeriod": "Ustaw liczbę dni, po których wygasłe elementy będą automatycznie usuwane.", + "ExpiredDeleterPeriodUnit": "dzień(dni)", + "AuditLogsBeforeXWillBeDeleted": "Dzienniki audytu przed {0} zostaną usunięte.", + "TenantId": "ID najemcy", + "Permission:Export": "Eksportuj dzienniki audytu", + "ExportToExcel": "Eksportuj do Excela", + "Exporting": "Eksportowanie", + "ExportCompleted": "Eksport zakończony pomyślnie", + "ExportFailed": "Eksport nieudany", + "ExportJobQueued": "Zadanie eksportu zostało umieszczone w kolejce dla {0} rekordów. Otrzymasz e-mail po zakończeniu eksportu.", + "ExportReady": "Eksport zakończony dla {0} rekordów i gotowy do pobrania.", + "FileName": "Nazwa pliku", + "TotalRecords": "Łączna liczba rekordów", + "ExcelFileAttachedMessage": "Plik Excel jest załączony do tego e-maila.", + "EntityChangeExportCompletedSubject": "Eksport zmian encji zakończony", + "AuditLogExportCompletedSubject": "Eksport dziennika audytu zakończony", + "DownloadLinkExplanation": "Możesz pobrać plik, korzystając z poniższego łącza do {0} (UTC)", + "DownloadNow": "Pobierz teraz", + "TryAgainMessage": "Proszę spróbuj ponownie. Jeśli problem nie ustąpi, skontaktuj się z pomocą techniczną." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pt-BR.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pt-BR.json index d88aba16a6..03ec81d51e 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pt-BR.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/pt-BR.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Registro de auditoria", "Feature:AuditLoggingEnable": "Página de registro de auditoria habilitada", "Feature:AuditLoggingEnableDescription": "Habilite a página de registro de auditoria no aplicativo.", - "TenantId": "ID do inquilino" + "Feature:AuditLoggingSettingManagementEnable": "Habilitar gerenciamento de configurações de log de auditoria", + "Feature:AuditLoggingSettingManagementEnableDescription": "Habilite a configuração do gerenciamento de configurações de log de auditoria dentro do aplicativo.", + "InvalidAuditLogDeletionSettings": "Configurações de exclusão de log de auditoria inválidas. Se a exclusão estiver habilitada, o período deve ser maior que 0 dias.", + "AuditLogSettingsGeneral": "Geral", + "AuditLogSettingsGlobal": "Global", + "DisplayName:IsPeriodicDeleterEnabled": "Habilitar serviço de limpeza em todo o sistema", + "Description:IsPeriodicDeleterEnabled": "Se esta opção estiver desabilitada, o excluidor periódico não funcionará. Os logs de auditoria não serão excluídos automaticamente.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Habilitar serviço de limpeza para todos os inquilinos e host", + "Description:GlobalIsExpiredDeleterEnabled": "Se esta opção estiver habilitada, todos os itens expirados dos inquilinos e do host serão excluídos automaticamente, a menos que tenham uma configuração específica.", + "DisplayName:IsExpiredDeleterEnabled": "Habilitar serviço de limpeza", + "Description:IsExpiredDeleterEnabled": "Se esta opção estiver habilitada, os itens expirados serão excluídos automaticamente.", + "DisplayName:ExpiredDeleterPeriod": "Período de exclusão de itens expirados", + "Description:ExpiredDeleterPeriod": "Defina o número de dias após os quais os itens expirados serão excluídos automaticamente.", + "ExpiredDeleterPeriodUnit": "dia(s)", + "AuditLogsBeforeXWillBeDeleted": "Os logs de auditoria antes de {0} serão excluídos.", + "TenantId": "ID do inquilino", + "Permission:Export": "Exportar logs de auditoria", + "ExportToExcel": "Exportar para Excel", + "Exporting": "Exportando", + "ExportCompleted": "Exportação concluída com sucesso", + "ExportFailed": "Exportação falhou", + "ExportJobQueued": "O trabalho de exportação foi enfileirado para {0} registros. Você receberá um email quando a exportação for concluída.", + "ExportReady": "Exportação concluída para {0} registros e pronta para download.", + "FileName": "Nome do arquivo", + "TotalRecords": "Total de registros", + "ExcelFileAttachedMessage": "O arquivo Excel está anexado a este email.", + "EntityChangeExportCompletedSubject": "Exportação de mudanças de entidade concluída", + "AuditLogExportCompletedSubject": "Exportação de log de auditoria concluída", + "DownloadLinkExplanation": "Você pode baixar o arquivo usando o link abaixo até {0} (UTC)", + "DownloadNow": "Baixar agora", + "TryAgainMessage": "Por favor, tente novamente. Se o problema persistir, entre em contato com o suporte." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ro-RO.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ro-RO.json index 0b546c4866..2cc471a1e4 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ro-RO.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ro-RO.json @@ -82,6 +82,9 @@ "Feature:AuditLoggingGroup": "Înregistrare de audit", "Feature:AuditLoggingEnable": "Pagina de înregistrare a auditului activată", "Feature:AuditLoggingEnableDescription": "Activați pagina de înregistrare a auditului în aplicație.", - "TenantId": "ID chiriaș" + "TenantId": "ID chiriaș", + "DownloadLinkExplanation": "Puteți descărca fișierul folosind link-ul de mai jos până la {0} (UTC)", + "DownloadNow": "Descărcați acum", + "TryAgainMessage": "Vă rugăm să încercați din nou. Dacă problema persistă, vă rugăm să contactați asistența." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ru.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ru.json index 9d12238ac2..f07c7baa78 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ru.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/ru.json @@ -82,6 +82,36 @@ "Feature:AuditLoggingGroup": "Ведение журнала аудита", "Feature:AuditLoggingEnable": "Включенная страница ведения журнала аудита", "Feature:AuditLoggingEnableDescription": "Включить страницу ведения журнала аудита в приложении.", - "TenantId": "Идентификатор арендатора" + "Feature:AuditLoggingSettingManagementEnable": "Включить управление настройками журнала аудита", + "Feature:AuditLoggingSettingManagementEnableDescription": "Включить конфигурацию управления настройками журнала аудита в приложении.", + "InvalidAuditLogDeletionSettings": "Недопустимые настройки удаления журнала аудита. Если удаление включено, период должен быть больше 0 дней.", + "AuditLogSettingsGeneral": "Общие", + "AuditLogSettingsGlobal": "Глобальные", + "DisplayName:IsPeriodicDeleterEnabled": "Включить службу очистки в масштабе системы", + "Description:IsPeriodicDeleterEnabled": "Если эта опция отключена, периодический удалитель не будет работать. Журналы аудита не будут удаляться автоматически.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Включить службу очистки для всех арендаторов и хоста", + "Description:GlobalIsExpiredDeleterEnabled": "Если эта опция включена, все просроченные элементы арендаторов и хоста будут удаляться автоматически, если у них нет специальной настройки.", + "DisplayName:IsExpiredDeleterEnabled": "Включить службу очистки", + "Description:IsExpiredDeleterEnabled": "Если эта опция включена, просроченные элементы будут удаляться автоматически.", + "DisplayName:ExpiredDeleterPeriod": "Период удаления просроченных элементов", + "Description:ExpiredDeleterPeriod": "Установите количество дней, после которых просроченные элементы будут автоматически удалены.", + "ExpiredDeleterPeriodUnit": "день(дни)", + "AuditLogsBeforeXWillBeDeleted": "Журналы аудита до {0} будут удалены.", + "TenantId": "Идентификатор арендатора", + "Permission:Export": "Экспорт журналов аудита", + "ExportToExcel": "Экспорт в Excel", + "Exporting": "Экспорт", + "ExportCompleted": "Экспорт успешно завершен", + "ExportFailed": "Экспорт не удался", + "ExportJobQueued": "Задача экспорта поставлена в очередь для {0} записей. Вы получите электронное письмо, когда экспорт будет завершен.", + "ExportReady": "Экспорт завершен для {0} записей и готов к загрузке.", + "FileName": "Имя файла", + "TotalRecords": "Всего записей", + "ExcelFileAttachedMessage": "Файл Excel прикреплен к этому электронному письму.", + "EntityChangeExportCompletedSubject": "Экспорт изменений сущности завершен", + "AuditLogExportCompletedSubject": "Экспорт журнала аудита завершен", + "DownloadLinkExplanation": "Вы можете скачать файл по ссылке ниже до {0} (UTC)", + "DownloadNow": "Скачать сейчас", + "TryAgainMessage": "Пожалуйста, попробуйте еще раз. Если проблема не исчезнет, обратитесь в службу поддержки." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sk.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sk.json index ae3925ea79..e406b3ec25 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sk.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sk.json @@ -79,9 +79,39 @@ "DurationMs": "Trvanie (ms)", "StartDate": "Dátum začiatku", "EndDate": "Dátum konca", - "Feature:AuditLoggingGroup": "Audit logovanie", - "Feature:AuditLoggingEnable": "Povoliť stránku audit logovania", - "Feature:AuditLoggingEnableDescription": "Povolená stránka audit logovania v aplikácii.", - "TenantId": "ID nájomníka" + "Feature:AuditLoggingGroup": "Protokolovanie auditu", + "Feature:AuditLoggingEnable": "Povoliť stránku protokolovania auditu", + "Feature:AuditLoggingEnableDescription": "Povoliť stránku protokolovania auditu v aplikácii.", + "Feature:AuditLoggingSettingManagementEnable": "Povoliť správu nastavení protokolu auditu", + "Feature:AuditLoggingSettingManagementEnableDescription": "Povoliť konfiguráciu správy nastavení protokolu auditu v aplikácii.", + "InvalidAuditLogDeletionSettings": "Neplatné nastavenia mazania protokolu auditu. Ak je mazanie povolené, obdobie by malo byť väčšie ako 0 dní.", + "AuditLogSettingsGeneral": "Všeobecné", + "AuditLogSettingsGlobal": "Globálne", + "DisplayName:IsPeriodicDeleterEnabled": "Povoliť službu čistenia v celom systéme", + "Description:IsPeriodicDeleterEnabled": "Ak je táto možnosť zakázaná, periodický mazač nebude fungovať. Protokoly auditu nebudú automaticky mazané.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Povoliť službu čistenia pre všetkých nájomcov a hostiteľa", + "Description:GlobalIsExpiredDeleterEnabled": "Ak je táto možnosť povolená, všetky prešlé položky nájomcov a hostiteľa budú automaticky zmazané, pokiaľ nemajú špecifické nastavenie.", + "DisplayName:IsExpiredDeleterEnabled": "Povoliť službu čistenia", + "Description:IsExpiredDeleterEnabled": "Ak je táto možnosť povolená, prešlé položky budú automaticky zmazané.", + "DisplayName:ExpiredDeleterPeriod": "Obdobie mazania prešlých položiek", + "Description:ExpiredDeleterPeriod": "Nastavte počet dní, po ktorých budú prešlé položky automaticky zmazané.", + "ExpiredDeleterPeriodUnit": "deň(dni)", + "AuditLogsBeforeXWillBeDeleted": "Protokoly auditu pred {0} budú zmazané.", + "TenantId": "ID nájomcu", + "Permission:Export": "Exportovať protokoly auditu", + "ExportToExcel": "Exportovať do Excelu", + "Exporting": "Exportovanie", + "ExportCompleted": "Export úspešne dokončený", + "ExportFailed": "Export sa nepodaril", + "ExportJobQueued": "Úloha exportu bola zaradená do fronty pre {0} záznamov. Dostanete e-mail, keď bude export dokončený.", + "ExportReady": "Export dokončený pre {0} záznamov a pripravený na stiahnutie.", + "FileName": "Názov súboru", + "TotalRecords": "Celkom záznamov", + "ExcelFileAttachedMessage": "Súbor Excel je pripojený k tomuto e-mailu.", + "EntityChangeExportCompletedSubject": "Export zmien entít dokončený", + "AuditLogExportCompletedSubject": "Export protokolu auditu dokončený", + "DownloadLinkExplanation": "Súbor si môžete stiahnuť pomocou odkazu nižšie do {0} (UTC)", + "DownloadNow": "Stiahnuť teraz", + "TryAgainMessage": "Skúste to prosím znova. Ak problém pretrváva, kontaktujte podporu." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sl.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sl.json index 460e43458e..0efc30a3d0 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sl.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sl.json @@ -79,9 +79,39 @@ "DurationMs": "Trajanje (ms)", "StartDate": "Začetni datum", "EndDate": "Končni datum", - "Feature:AuditLoggingGroup": "Revizijsko beleženje", - "Feature:AuditLoggingEnable": "Omogočena stran za beleženje revizije", - "Feature:AuditLoggingEnableDescription": "Omogočite stran za beleženje revizije v aplikaciji.", - "TenantId": "ID najemnika" + "Feature:AuditLoggingGroup": "Beleženje revizije", + "Feature:AuditLoggingEnable": "Omogoči stran beleženja revizije", + "Feature:AuditLoggingEnableDescription": "Omogočite stran beleženja revizije v aplikaciji.", + "Feature:AuditLoggingSettingManagementEnable": "Omogoči upravljanje nastavitev dnevnika revizije", + "Feature:AuditLoggingSettingManagementEnableDescription": "Omogočite konfiguracijo upravljanja nastavitev dnevnika revizije v aplikaciji.", + "InvalidAuditLogDeletionSettings": "Neveljavne nastavitve brisanja dnevnika revizije. Če je brisanje omogočeno, mora biti obdobje večje od 0 dni.", + "AuditLogSettingsGeneral": "Splošno", + "AuditLogSettingsGlobal": "Globalno", + "DisplayName:IsPeriodicDeleterEnabled": "Omogoči storitev čiščenja po celotnem sistemu", + "Description:IsPeriodicDeleterEnabled": "Če je ta možnost onemogočena, periodični brisalec ne bo deloval. Dnevniki revizije ne bodo samodejno izbrisani.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Omogoči storitev čiščenja za vse najemnike in gostitelja", + "Description:GlobalIsExpiredDeleterEnabled": "Če je ta možnost omogočena, bodo vsi potekli elementi najemnikov in gostitelja samodejno izbrisani, razen če imajo specifično nastavitev.", + "DisplayName:IsExpiredDeleterEnabled": "Omogoči storitev čiščenja", + "Description:IsExpiredDeleterEnabled": "Če je ta možnost omogočena, bodo potekli elementi samodejno izbrisani.", + "DisplayName:ExpiredDeleterPeriod": "Obdobje brisanja poteklih elementov", + "Description:ExpiredDeleterPeriod": "Nastavite število dni, po katerih bodo potekli elementi samodejno izbrisani.", + "ExpiredDeleterPeriodUnit": "dan(i)", + "AuditLogsBeforeXWillBeDeleted": "Dnevniki revizije pred {0} bodo izbrisani.", + "TenantId": "ID najemnika", + "Permission:Export": "Izvozi dnevnike revizije", + "ExportToExcel": "Izvozi v Excel", + "Exporting": "Izvažanje", + "ExportCompleted": "Izvoz uspešno dokončan", + "ExportFailed": "Izvoz neuspešen", + "ExportJobQueued": "Naloga izvoza je bila postavljena v vrsto za {0} zapisov. Prejeli boste e-pošto, ko bo izvoz dokončan.", + "ExportReady": "Izvoz dokončan za {0} zapisov in pripravljen za prenos.", + "FileName": "Ime datoteke", + "TotalRecords": "Skupaj zapisov", + "ExcelFileAttachedMessage": "Datoteka Excel je priložena tej e-pošti.", + "EntityChangeExportCompletedSubject": "Izvoz sprememb entitet dokončan", + "AuditLogExportCompletedSubject": "Izvoz dnevnika revizije dokončan", + "DownloadLinkExplanation": "Datoteko lahko prenesete s spodnjo povezavo do {0} (UTC)", + "DownloadNow": "Prenesi zdaj", + "TryAgainMessage": "Prosimo, poskusite znova. Če težava vztraja, se obrnite na podporo." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sv.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sv.json index 3c57005a3d..b3a44c27ed 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sv.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/sv.json @@ -79,24 +79,39 @@ "DurationMs": "Varaktighet (ms)", "StartDate": "Startdatum", "EndDate": "Slutdatum", - "Feature:AuditLoggingGroup": "Granskning av loggning", - "Feature:AuditLoggingEnable": "Aktivera granskningsloggning sida", - "Feature:AuditLoggingEnableDescription": "Aktivera sidan för granskningsloggning i programmet.", - "Feature:AuditLoggingSettingManagementEnable": "Aktivera hantering av inställningar för granskningslogg", - "Feature:AuditLoggingSettingManagementEnableDescription": "Aktivera konfigurationen av inställningshanteringen för granskningsloggen i programmet.", - "InvalidAuditLogDeletionSettings": "Ogiltiga inställningar för radering av revisionslogg. Om radering är aktiverad ska perioden vara större än 0 dagar.", + "Feature:AuditLoggingGroup": "Granskningsloggning", + "Feature:AuditLoggingEnable": "Aktivera granskningsloggningssida", + "Feature:AuditLoggingEnableDescription": "Aktivera granskningsloggningssidan i applikationen.", + "Feature:AuditLoggingSettingManagementEnable": "Aktivera hantering av granskningslogginställningar", + "Feature:AuditLoggingSettingManagementEnableDescription": "Aktivera konfiguration av hantering av granskningslogginställningar inom applikationen.", + "InvalidAuditLogDeletionSettings": "Ogiltiga inställningar för borttagning av granskningslogg. Om borttagning är aktiverat ska perioden vara större än 0 dagar.", "AuditLogSettingsGeneral": "Allmänt", "AuditLogSettingsGlobal": "Globalt", - "DisplayName:IsPeriodicDeleterEnabled": "Möjliggör uppstädning av hela systemet", - "Description:IsPeriodicDeleterEnabled": "Om detta alternativ är avaktiverat fungerar inte den periodiska raderingen. Granskningsloggar kommer inte att raderas automatiskt.", - "DisplayName:GlobalIsExpiredDeleterEnabled": "Aktivera städservice för alla hyresgäster och värd", - "Description:GlobalIsExpiredDeleterEnabled": "Om det här alternativet är aktiverat raderas alla förfallna objekt för hyresgäster och värd automatiskt om det inte har en specifik inställning.", - "DisplayName:IsExpiredDeleterEnabled": "Möjliggör städning", - "Description:IsExpiredDeleterEnabled": "Om detta alternativ är aktiverat raderas de utgångna artiklarna automatiskt.", - "DisplayName:ExpiredDeleterPeriod": "Utgången raderingsperiod för objekt", - "Description:ExpiredDeleterPeriod": "Ställ in antalet dagar efter vilka utgångna objekt automatiskt ska raderas.", + "DisplayName:IsPeriodicDeleterEnabled": "Aktivera rengöringstjänst systemomfattande", + "Description:IsPeriodicDeleterEnabled": "Om detta alternativ är inaktiverat kommer den periodiska raderaren inte att fungera. Granskningsloggar kommer inte att raderas automatiskt.", + "DisplayName:GlobalIsExpiredDeleterEnabled": "Aktivera rengöringstjänst för alla hyresgäster och värd", + "Description:GlobalIsExpiredDeleterEnabled": "Om detta alternativ är aktiverat kommer alla utgångna objekt för hyresgäster och värd att raderas automatiskt såvida de inte har en specifik inställning.", + "DisplayName:IsExpiredDeleterEnabled": "Aktivera rengöringstjänst", + "Description:IsExpiredDeleterEnabled": "Om detta alternativ är aktiverat kommer utgångna objekt att raderas automatiskt.", + "DisplayName:ExpiredDeleterPeriod": "Period för radering av utgångna objekt", + "Description:ExpiredDeleterPeriod": "Ange antalet dagar efter vilka utgångna objekt kommer att raderas automatiskt.", "ExpiredDeleterPeriodUnit": "dag(ar)", "AuditLogsBeforeXWillBeDeleted": "Granskningsloggar före {0} kommer att raderas.", - "TenantId": "Hyresgäst-ID" + "TenantId": "Hyresgäst-ID", + "Permission:Export": "Exportera granskningsloggar", + "ExportToExcel": "Exportera till Excel", + "Exporting": "Exporterar", + "ExportCompleted": "Export slutförd framgångsrikt", + "ExportFailed": "Export misslyckades", + "ExportJobQueued": "Exportjobb har köats för {0} poster. Du kommer att få ett e-postmeddelande när exporten är klar.", + "ExportReady": "Export slutförd för {0} poster och redo för nedladdning.", + "FileName": "Filnamn", + "TotalRecords": "Totalt antal poster", + "ExcelFileAttachedMessage": "Excel-filen är bifogad till detta e-postmeddelande.", + "EntityChangeExportCompletedSubject": "Export av entitetsändringar slutförd", + "AuditLogExportCompletedSubject": "Export av granskningslogg slutförd", + "DownloadLinkExplanation": "Du kan ladda ner filen via länken nedan fram till {0} (UTC)", + "DownloadNow": "Ladda ner nu", + "TryAgainMessage": "Försök igen. Om problemet kvarstår, kontakta support." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/tr.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/tr.json index b3e09335fc..86105e1a08 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/tr.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/tr.json @@ -82,6 +82,21 @@ "Feature:AuditLoggingEnable": "İşlem kayıtları sayfasını etkinleştirin", "Feature:AuditLoggingEnableDescription": "Uygulamadanızdaki işlem kayıtları sayfasını etkinleştirir.", "MinMaxDuration": "Süre (Min. - Max.)", - "TenantId": "Müşteri Id" + "TenantId": "Müşteri Id", + "Permission:Export": "İşlem kayıtlarını dışa aktar", + "ExportToExcel": "Excel'e Aktar", + "Exporting": "Aktarılıyor", + "ExportCompleted": "Aktarma başarıyla tamamlandı", + "ExportFailed": "Aktarma başarısız", + "ExportJobQueued": "{0} kayıt için dışa aktarma işi sıraya alındı. İşlem tamamlandığında e-posta ile bilgilendirileceksiniz.", + "ExportReady": "{0} kayıt için dışa aktarma tamamlandı ve indirme için hazır.", + "FileName": "Dosya adı", + "TotalRecords": "Toplam kayıt", + "ExcelFileAttachedMessage": "Excel dosyası bu e-postaya eklenmiştir.", + "EntityChangeExportCompletedSubject": "Entity değişiklik dışa aktarma tamamlandı", + "AuditLogExportCompletedSubject": "İşlem log dışa aktarma tamamlandı", + "DownloadLinkExplanation": "Dosyayı aşağıdaki bağlantıyı kullanarak {0} (UTC) tarihine kadar indirebilirsiniz", + "DownloadNow": "Şimdi İndir", + "TryAgainMessage": "Lütfen tekrar deneyin. Sorun devam ederse, lütfen destek ekibiyle iletişime geçin." } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/vi.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/vi.json index 933593c168..ad4f040a96 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/vi.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/vi.json @@ -82,6 +82,9 @@ "Feature:AuditLoggingGroup": "Ghi nhật ký kiểm tra", "Feature:AuditLoggingEnable": "Đã bật trang ghi nhật ký kiểm tra", "Feature:AuditLoggingEnableDescription": "Kích hoạt trang ghi nhật ký kiểm tra trong ứng dụng.", - "TenantId": "ID người thuê" + "TenantId": "ID người thuê", + "DownloadLinkExplanation": "Bạn có thể tải xuống tệp bằng liên kết bên dưới cho đến {0} (UTC)", + "DownloadNow": "Tải xuống ngay", + "TryAgainMessage": "Vui lòng thử lại. Nếu sự cố vẫn tiếp diễn, vui lòng liên hệ bộ phận hỗ trợ." } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hans.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hans.json index dc9cc4d667..4b3d61f2a3 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hans.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hans.json @@ -80,8 +80,38 @@ "StartDate": "开始日期", "EndDate": "结束日期", "Feature:AuditLoggingGroup": "审计日志", - "Feature:AuditLoggingEnable": "启用审计记录页面", + "Feature:AuditLoggingEnable": "启用审计日志页面", "Feature:AuditLoggingEnableDescription": "在应用程序中启用审计日志页面。", - "TenantId": "租户 ID" + "Feature:AuditLoggingSettingManagementEnable": "启用审计日志设置管理", + "Feature:AuditLoggingSettingManagementEnableDescription": "在应用程序中启用审计日志设置管理的配置。", + "InvalidAuditLogDeletionSettings": "无效的审计日志删除设置。如果启用删除,期间应大于0天。", + "AuditLogSettingsGeneral": "常规", + "AuditLogSettingsGlobal": "全局", + "DisplayName:IsPeriodicDeleterEnabled": "启用系统范围的清理服务", + "Description:IsPeriodicDeleterEnabled": "如果禁用此选项,定期删除器将不工作。审计日志不会自动删除。", + "DisplayName:GlobalIsExpiredDeleterEnabled": "为所有租户和主机启用清理服务", + "Description:GlobalIsExpiredDeleterEnabled": "如果启用此选项,所有租户和主机的过期项目将自动删除,除非有特定设置。", + "DisplayName:IsExpiredDeleterEnabled": "启用清理服务", + "Description:IsExpiredDeleterEnabled": "如果启用此选项,过期项目将自动删除。", + "DisplayName:ExpiredDeleterPeriod": "过期项目删除期间", + "Description:ExpiredDeleterPeriod": "设置过期项目自动删除的天数。", + "ExpiredDeleterPeriodUnit": "天", + "AuditLogsBeforeXWillBeDeleted": "{0}之前的审计日志将被删除。", + "TenantId": "租户ID", + "Permission:Export": "导出审计日志", + "ExportToExcel": "导出到Excel", + "Exporting": "导出中", + "ExportCompleted": "导出成功完成", + "ExportFailed": "导出失败", + "ExportJobQueued": "导出作业已为{0}条记录排队。导出完成后您将收到电子邮件。", + "ExportReady": "{0}条记录的导出已完成,可以下载。", + "FileName": "文件名", + "TotalRecords": "总记录数", + "ExcelFileAttachedMessage": "Excel文件已附加到此电子邮件。", + "EntityChangeExportCompletedSubject": "实体变更导出已完成", + "AuditLogExportCompletedSubject": "审计日志导出已完成", + "DownloadLinkExplanation": "您可以使用下面的链接下载文件,直到{0}(UTC)", + "DownloadNow": "立即下载", + "TryAgainMessage": "请再试一次。如果问题仍然存在,请联系支持人员。" } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hant.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hant.json index dc0275186d..00e9cc4c08 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hant.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/zh-Hant.json @@ -79,9 +79,39 @@ "DurationMs": "持續時間(毫秒)", "StartDate": "開始時間", "EndDate": "結束時間", - "Feature:AuditLoggingGroup": "審計日誌", - "Feature:AuditLoggingEnable": "啟用審計日誌頁面", - "Feature:AuditLoggingEnableDescription": "在應用程序中啟用審計日誌頁面.", - "TenantId": "租戶 ID" + "Feature:AuditLoggingGroup": "稽核日誌", + "Feature:AuditLoggingEnable": "啟用稽核日誌頁面", + "Feature:AuditLoggingEnableDescription": "在應用程式中啟用稽核日誌頁面。", + "Feature:AuditLoggingSettingManagementEnable": "啟用稽核日誌設定管理", + "Feature:AuditLoggingSettingManagementEnableDescription": "在應用程式中啟用稽核日誌設定管理的配置。", + "InvalidAuditLogDeletionSettings": "無效的稽核日誌刪除設定。如果啟用刪除,期間應大於0天。", + "AuditLogSettingsGeneral": "一般", + "AuditLogSettingsGlobal": "全域", + "DisplayName:IsPeriodicDeleterEnabled": "啟用系統範圍的清理服務", + "Description:IsPeriodicDeleterEnabled": "如果停用此選項,定期刪除器將不工作。稽核日誌不會自動刪除。", + "DisplayName:GlobalIsExpiredDeleterEnabled": "為所有租戶和主機啟用清理服務", + "Description:GlobalIsExpiredDeleterEnabled": "如果啟用此選項,所有租戶和主機的過期項目將自動刪除,除非有特定設定。", + "DisplayName:IsExpiredDeleterEnabled": "啟用清理服務", + "Description:IsExpiredDeleterEnabled": "如果啟用此選項,過期項目將自動刪除。", + "DisplayName:ExpiredDeleterPeriod": "過期項目刪除期間", + "Description:ExpiredDeleterPeriod": "設定過期項目自動刪除的天數。", + "ExpiredDeleterPeriodUnit": "天", + "AuditLogsBeforeXWillBeDeleted": "{0}之前的稽核日誌將被刪除。", + "TenantId": "租戶ID", + "Permission:Export": "匯出稽核日誌", + "ExportToExcel": "匯出到Excel", + "Exporting": "匯出中", + "ExportCompleted": "匯出成功完成", + "ExportFailed": "匯出失敗", + "ExportJobQueued": "匯出作業已為{0}條記錄排隊。匯出完成後您將收到電子郵件。", + "ExportReady": "{0}條記錄的匯出已完成,可以下載。", + "FileName": "檔案名稱", + "TotalRecords": "總記錄數", + "ExcelFileAttachedMessage": "Excel檔案已附加到此電子郵件。", + "EntityChangeExportCompletedSubject": "實體變更匯出已完成", + "AuditLogExportCompletedSubject": "稽核日誌匯出已完成", + "DownloadLinkExplanation": "您可以使用下面的連結下載檔案,直到{0}(UTC)", + "DownloadNow": "立即下載", + "TryAgainMessage": "請再試一次。如果問題仍然存在,請聯絡支援人員。" } } \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogExcelFile.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogExcelFile.cs new file mode 100644 index 0000000000..ed2e99db4c --- /dev/null +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogExcelFile.cs @@ -0,0 +1,27 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.AuditLogging; + +public class AuditLogExcelFile : CreationAuditedEntity, IMultiTenant +{ + public virtual Guid? TenantId { get; protected set; } + + public virtual string FileName { get; protected set; } + + protected AuditLogExcelFile() + { + } + + public AuditLogExcelFile( + Guid id, + string fileName, + Guid? tenantId = null, + Guid? creatorId = null) : base(id) + { + FileName = Check.NotNullOrWhiteSpace(fileName, nameof(fileName), AuditLogExcelFileConsts.MaxFileNameLength); + TenantId = tenantId; + CreatorId = creatorId; + } +} \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogExcelFileRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogExcelFileRepository.cs new file mode 100644 index 0000000000..b29ec07684 --- /dev/null +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogExcelFileRepository.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.AuditLogging; + +public interface IAuditLogExcelFileRepository : IRepository +{ + Task> GetListCreationTimeBeforeAsync( + DateTime creationTimeBefore, + int maxResultCount = 50, + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContext.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContext.cs index b0e4eee5ba..16f6ac5603 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContext.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContext.cs @@ -9,6 +9,8 @@ public class AbpAuditLoggingDbContext : AbpDbContext, { public DbSet AuditLogs { get; set; } + public DbSet AuditLogExcelFiles { get; set; } + public AbpAuditLoggingDbContext(DbContextOptions options) : base(options) { diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContextModelBuilderExtensions.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContextModelBuilderExtensions.cs index e63d806993..da73060c8e 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContextModelBuilderExtensions.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContextModelBuilderExtensions.cs @@ -103,6 +103,13 @@ public static class AbpAuditLoggingDbContextModelBuilderExtensions b.ApplyObjectExtensionMappings(); }); + builder.Entity(b => + { + b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogExcelFiles", AbpAuditLoggingDbProperties.DbSchema); + b.ConfigureByConvention(); + b.Property(x => x.FileName).HasMaxLength(AuditLogExcelFileConsts.MaxFileNameLength).HasColumnName(nameof(AuditLogExcelFile.FileName)); + }); + builder.TryConfigureObjectExtensions(); } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingEntityFrameworkCoreModule.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingEntityFrameworkCoreModule.cs index d413994f87..28d1436088 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingEntityFrameworkCoreModule.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingEntityFrameworkCoreModule.cs @@ -13,6 +13,7 @@ public class AbpAuditLoggingEntityFrameworkCoreModule : AbpModule context.Services.AddAbpDbContext(options => { options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogExcelFileRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogExcelFileRepository.cs new file mode 100644 index 0000000000..d3b8cc8d7c --- /dev/null +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogExcelFileRepository.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.AuditLogging.EntityFrameworkCore; + +public class EfCoreAuditLogExcelFileRepository : EfCoreRepository, IAuditLogExcelFileRepository +{ + public EfCoreAuditLogExcelFileRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + + public async Task> GetListCreationTimeBeforeAsync( + DateTime creationTimeBefore, + int maxResultCount = 50, + CancellationToken cancellationToken = default) + { + var queryable = await GetQueryableAsync(); + return await queryable.Where(x => x.CreationTime < creationTimeBefore).Take(maxResultCount).ToListAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/IAuditLoggingDbContext.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/IAuditLoggingDbContext.cs index ca03f6b6a3..d2f47e574b 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/IAuditLoggingDbContext.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/IAuditLoggingDbContext.cs @@ -8,4 +8,6 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore; public interface IAuditLoggingDbContext : IEfCoreDbContext { DbSet AuditLogs { get; } + + DbSet AuditLogExcelFiles { get; } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbContextExtensions.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbContextExtensions.cs index b20a2b20a2..3f48b34bb2 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbContextExtensions.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbContextExtensions.cs @@ -13,5 +13,10 @@ public static class AbpAuditLoggingMongoDbContextExtensions { b.CollectionName = AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogs"; }); + + builder.Entity(b => + { + b.CollectionName = AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogExcelFiles"; + }); } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbModule.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbModule.cs index 116df1f0f6..ab46e8d1cc 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbModule.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AbpAuditLoggingMongoDbModule.cs @@ -13,6 +13,7 @@ public class AbpAuditLoggingMongoDbModule : AbpModule context.Services.AddMongoDbContext(options => { options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AuditLoggingMongoDbContext.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AuditLoggingMongoDbContext.cs index d755029372..1d286022e1 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AuditLoggingMongoDbContext.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/AuditLoggingMongoDbContext.cs @@ -9,6 +9,8 @@ public class AuditLoggingMongoDbContext : AbpMongoDbContext, IAuditLoggingMongoD { public IMongoCollection AuditLogs => Collection(); + public IMongoCollection AuditLogExcelFiles => Collection(); + protected override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder); diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/IAuditLoggingMongoDbContext.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/IAuditLoggingMongoDbContext.cs index 54350672ab..e11241ddb1 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/IAuditLoggingMongoDbContext.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/IAuditLoggingMongoDbContext.cs @@ -8,4 +8,6 @@ namespace Volo.Abp.AuditLogging.MongoDB; public interface IAuditLoggingMongoDbContext : IAbpMongoDbContext { IMongoCollection AuditLogs { get; } + + IMongoCollection AuditLogExcelFiles { get; } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogExcelFileRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogExcelFileRepository.cs new file mode 100644 index 0000000000..3e2ab68361 --- /dev/null +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogExcelFileRepository.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.AuditLogging.MongoDB; + +public class MongoAuditLogExcelFileRepository : MongoDbRepository, IAuditLogExcelFileRepository +{ + public MongoAuditLogExcelFileRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + + public async Task> GetListCreationTimeBeforeAsync(DateTime creationTimeBefore, int maxResultCount = 50, CancellationToken cancellationToken = default) + { + var queryable = await GetQueryableAsync(); + return await queryable.Where(x => x.CreationTime < creationTimeBefore).Take(maxResultCount).ToListAsync(cancellationToken); + } +} \ No newline at end of file diff --git a/modules/basic-theme/Volo.Abp.BasicTheme.sln b/modules/basic-theme/Volo.Abp.BasicTheme.sln index ac0ab4ed3b..66f19dad9a 100644 --- a/modules/basic-theme/Volo.Abp.BasicTheme.sln +++ b/modules/basic-theme/Volo.Abp.BasicTheme.sln @@ -1,5 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.35906.104 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0BC55E3B-4964-48E3-A390-2ADD37980149}" @@ -65,6 +68,9 @@ Global {D02053D9-10EF-4717-A792-A53F83347816}.Release|Any CPU.ActiveCfg = Release|Any CPU {D02053D9-10EF-4717-A792-A53F83347816}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection GlobalSection(NestedProjects) = preSolution {C8068E7F-4A04-4755-8976-C2A4C0ADC708} = {ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1} {655C0CF7-7BFA-45E4-A157-E868A97FB45B} = {ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1} diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml index 5f7298ca25..6c4aa7f3b8 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml @@ -9,7 +9,7 @@ @Model.CurrentLanguage.DisplayName - - \ No newline at end of file + + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpBadgeTagHelper)) \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Blockquotes.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Blockquotes.cshtml index 34ab545163..63bfbd519c 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Blockquotes.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Blockquotes.cshtml @@ -30,3 +30,6 @@ +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpBlockquoteTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Borders.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Borders.cshtml index 7473c84bb8..4f7a7a93b6 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Borders.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Borders.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Border @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.BordersModel @{ ViewData["Title"] = "Borders"; @@ -196,3 +197,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpBorderTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Breadcrumbs.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Breadcrumbs.cshtml index 4c4164a823..f7e056ed3b 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Breadcrumbs.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Breadcrumbs.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Breadcrumb @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.BreadcrumbsModel @{ ViewData["Title"] = "Breadcrumbs"; @@ -77,3 +78,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpBreadcrumbTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ButtonGroups.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ButtonGroups.cshtml index 94e0d7ee70..36f3f41be3 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ButtonGroups.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ButtonGroups.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.ButtonGroupsModel @{ ViewData["Title"] = "ButtonGroups"; @@ -268,4 +269,8 @@
- \ No newline at end of file + + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpButtonGroupTagHelper)) \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Buttons.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Buttons.cshtml index 08d1e0093a..ad6324614c 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Buttons.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Buttons.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.ButtonsModel @{ ViewData["Title"] = "Buttons"; @@ -258,4 +259,8 @@ - \ No newline at end of file + + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpButtonTagHelper)) \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml index 2880f8b179..bfdf80e784 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml @@ -1,5 +1,7 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card +@using Volo.Abp.DependencyInjection @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.CardsModel @{ ViewData["Title"] = "Cards"; @@ -41,7 +43,7 @@

-<div class="card" style="width: 18rem;">
+<div class="card mb-3" style="width: 18rem;">
   <img class="card-img-top" src=".../100px180/" alt="Card image cap">
   <div class="card-body">
     <h5 class="card-title">Card title</h5>
@@ -88,7 +90,7 @@
             
             
                 

-<div class="card" style="width: 18rem;">
+<div class="card mb-3" style="width: 18rem;">
   <div class="card-body">
     <h5 class="card-title">Card title</h5>
     <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
@@ -132,7 +134,7 @@
             
             
                 

-<div class="card" style="width: 18rem;">
+<div class="card mb-3" style="width: 18rem;">
   <ul class="list-group list-group-flush">
     <li class="list-group-item">Cras justo odio</li>
     <li class="list-group-item">Dapibus ac facilisis in</li>
@@ -174,7 +176,7 @@
             
             
                 

-<div class="card" style="width: 18rem;">
+<div class="card mb-3" style="width: 18rem;">
   <div class="card-header">
     Featured
   </div>
@@ -237,7 +239,7 @@
             
             
                 

-<div class="card" style="width: 18rem;">
+<div class="card mb-3" style="width: 18rem;">
   <img class="card-img-top" src=".../100px180/?text=Image cap" alt="Card image cap">
   <div class="card-body">
     <h5 class="card-title">Card title</h5>
@@ -290,7 +292,7 @@
             
             
                 

-<div class="card">
+<div class="card mb-3">
   <div class="card-header">
     Featured
   </div>
@@ -337,7 +339,7 @@
             
             
                 

-<div class="card">
+<div class="card mb-3">
   <div class="card-header">
     Quote
   </div>
@@ -586,4 +588,8 @@
             
         
     
-
\ No newline at end of file
+
+
+
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpCardTagHelper)) \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml.cs index 4a5d541668..01323da4d0 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Cards.cshtml.cs @@ -1,4 +1,10 @@ -using Microsoft.AspNetCore.Mvc.RazorPages; +using System; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Card; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components; @@ -6,6 +12,6 @@ public class CardsModel : PageModel { public void OnGet() { - + } } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Carousel.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Carousel.cshtml index d1b6cbe0b1..9d44f19453 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Carousel.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Carousel.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Carousel @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.CarouselsModel @{ ViewData["Title"] = "Carousels"; @@ -266,3 +267,6 @@ +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpCarouselTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Collapse.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Collapse.cshtml index 728afc0a1e..b8b01ec60e 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Collapse.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Collapse.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Collapse @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.CollapseModel @{ ViewData["Title"] = "Collapse"; @@ -214,3 +215,28 @@ + +
+ + + + + +

abp-accordion

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpAccordionTagHelper)) + +
+ + + + +

abp-accordion-item

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpAccordionItemTagHelper)) + +
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml index b65eaf15be..800fc4bf36 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DatePicker.cshtml @@ -1,4 +1,4 @@ -@page +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.DatePickerModel

Date Picker & Date Range Picker

@@ -775,5 +775,7 @@ public class DatePickerModel : PageModel +
+@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDatePickerTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Dropdowns.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Dropdowns.cshtml index 3f5717033d..c2d84593cf 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Dropdowns.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Dropdowns.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Dropdown @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.DropdownsModel @{ ViewData["Title"] = "Dropdowns"; @@ -735,4 +736,8 @@ - \ No newline at end of file + + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDropdownTagHelper)) \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml index cbec1ee01c..ab44e878c7 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/DynamicForms.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form @model DynamicFormsModel @{ @@ -428,4 +429,8 @@ public class DynamicFormsModel : PageModel - \ No newline at end of file + + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpDynamicFormTagHelper)) \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml index e637aebfad..3ed17afd37 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/FormElements.cshtml @@ -1,6 +1,7 @@ @page -@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components -@model FormElementsModel +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form +@model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.FormElementsModel @{ ViewData["Title"] = "Form Elements"; @@ -65,7 +66,7 @@ <input type="password" data-val="true" data-val-required="The Password field is required." id="MyModel_Password" name="MyModel.Password" class="form-control "> <span class="text-danger field-validation-valid" data-valmsg-for="MyModel.Password" data-valmsg-replace="true"></span> </div> -<div class="form-check"> +<div class="mb-2 form-check"> <input type="checkbox" data-val="true" data-val-required="The CheckMeOut field is required." id="MyModel_CheckMeOut" name="MyModel.CheckMeOut" value="true" class="form-check-input "><input name="MyModel.CheckMeOut" type="hidden" value="false"> <label class="form-check-label" for="MyModel_CheckMeOut">Check Me Out</label> </div> @@ -495,4 +496,30 @@ - \ No newline at end of file + + +
+ + + + +

abp-input

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpInputTagHelper)) + +
+ + + + +

abp-select

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpSelectTagHelper)) + +
+ + diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml index 0e33d39c59..37a9ad4428 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Grids.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.GridsModel @{ ViewData["Title"] = "Grids"; @@ -830,4 +831,38 @@
+ + + + +

abp-container

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpContainerTagHelper)) + +
+ + + + +

abp-row

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpRowTagHelper)) + +
+ + + + +

abp-column

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpColumnTagHelper)) + +
+ < back \ No newline at end of file diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml index ce66b8d5aa..71668d3496 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ListGroup.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ListGroup @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.ListGroupsModel @{ ViewData["Title"] = "List Groups"; @@ -347,3 +348,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpListGroupTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml index 9e51ef25a3..fa208cb0a8 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Modals.cshtml @@ -73,3 +73,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpModalTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml index ca9828d348..28d46eb59e 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Navs.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Nav @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.NavsModel @{ ViewData["Title"] = "Navs"; @@ -201,3 +202,31 @@ + +
+ + + + +

abp-nav-bar

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpNavBarTagHelper)) + +
+ + + + +

abp-nav-item

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpNavItemTagHelper)) + +
+ + + + diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml index 00666c091a..77fe1530a3 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Paginator.cshtml @@ -1,4 +1,6 @@ @page +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.PaginatorModel @{ ViewData["Title"] = "Paginator"; @@ -89,3 +91,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpPaginationTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml index ddc87ba66d..10fb759853 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Popovers.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Popover @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.PopoversModel @{ ViewData["Title"] = "Popovers"; @@ -69,3 +70,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpPopoverTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml index 0390090e9a..3566c194db 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/ProgressBars.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.ProgressBar @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.ProgressBarsModel @{ ViewData["Title"] = "Progress Bars"; @@ -77,3 +78,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpProgressBarTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml index e39fe8cae3..f73a6d2ca5 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tables.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Table @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.TablesModel @{ ViewData["Title"] = "Tables"; @@ -449,3 +450,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpTableTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml index e9631ed179..a0efeb0c0a 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tabs.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.TabsModel @{ ViewData["Title"] = "Tabs"; @@ -293,4 +294,39 @@ - \ No newline at end of file + + +
+ + + + +

abp-tab

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpTabTagHelper)) + +
+ + + + +

abp-tab-link

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpTabLinkTagHelper)) + +
+ + + + +

abp-tab-dropdown

+
+
+ + @await Component.InvokeAsync("TagHelperProperties", typeof(AbpTabDropdownTagHelper)) + +
diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml index f19161d515..7bbf1cd2da 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Components/Tooltips.cshtml @@ -1,5 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tooltip @model Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components.TooltipsModel @{ ViewData["Title"] = "Tooltips"; @@ -84,3 +85,7 @@ + +
+ +@await Component.InvokeAsync("TagHelperProperties", typeof(AbpTooltipTagHelper)) diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs index e36f329306..625fb60a80 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenuContributor.cs @@ -25,6 +25,7 @@ public class BootstrapDemoMenuContributor : IMenuContributor { new ApplicationMenuItem(BootstrapDemoMenus.Components.Alerts, "Alerts", url: "/Components/Alerts"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Badges, "Badges", url: "/Components/Badges"), + new ApplicationMenuItem(BootstrapDemoMenus.Components.Blockquotes, "Blockquotes", url: "/Components/Blockquotes"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Borders, "Borders", url: "/Components/Borders"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Breadcrumbs, "Breadcrumbs", url: "/Components/Breadcrumbs"), new ApplicationMenuItem(BootstrapDemoMenus.Components.Buttons, "Buttons", url: "/Components/Buttons"), diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs index 2f381221ed..7a758523af 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Pages/Menus/BootstrapDemoMenus.cs @@ -11,6 +11,7 @@ public class BootstrapDemoMenus public const string Alerts = Root + ".Alerts"; public const string Badges = Root + ".Badges"; public const string Borders = Root + ".Borders"; + public const string Blockquotes = Root + ".Blockquotes"; public const string Breadcrumbs = Root + ".Breadcrumbs"; public const string ButtonGroups = Root + ".ButtonGroups"; public const string Buttons = Root + ".Buttons"; diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs index ad3a39c746..ac9601cda3 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Program.cs @@ -1,31 +1,42 @@ using System; -using System.IO; -using Microsoft.AspNetCore.Hosting; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; -using Serilog.Events; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo; public class Program { - public static int Main(string[] args) + public async static Task Main(string[] args) { Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() //TODO: Should be configurable! - .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .MinimumLevel.Debug() .Enrich.FromLogContext() - .WriteTo.File("Logs/logs.txt") + .WriteTo.Async(c => c.Console()) .CreateLogger(); try { Log.Information("Starting web host."); - CreateHostBuilder(args).Build().Run(); + var builder = WebApplication.CreateBuilder(args); + builder.Host.AddAppSettingsSecretsJson() + .UseAutofac() + .UseSerilog(); + await builder.AddApplicationAsync(); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); return 0; } catch (Exception ex) { + if (ex is HostAbortedException) + { + throw; + } + Log.Fatal(ex, "Host terminated unexpectedly!"); return 1; } @@ -34,14 +45,4 @@ public class Program Log.CloseAndFlush(); } } - - - internal static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) - .UseAutofac() - .UseSerilog(); } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json index 07a310a660..7ad9d24119 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Properties/launchSettings.json @@ -1,27 +1,12 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:51339", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Volo.AbpIo.Commercial.Web": { + "Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "https://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } -} \ No newline at end of file +} diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs deleted file mode 100644 index 838cf43402..0000000000 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Startup.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj index f8202b97ec..9aa8142fda 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj @@ -10,7 +10,7 @@ - + @@ -23,5 +23,5 @@ Always - + diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json index d0e6ac3931..0d4611bedc 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/package.json @@ -3,8 +3,8 @@ "name": "asp.net", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.shared": "~9.2.0", - "@abp/prismjs": "~9.2.0", - "@abp/highlight.js": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.shared": "~9.3.0-rc.1", + "@abp/prismjs": "~9.3.0-rc.1", + "@abp/highlight.js": "~9.3.0-rc.1" } } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock index 267e042944..ea1cf877f6 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/yarn.lock @@ -2,203 +2,203 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== - dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/clipboard@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.2.0.tgz#348a0e45752c7eb055fb00af52660593ad340caf" - integrity sha512-2+wt2ShLBfoHqx0DNNevJkaz1POLcs1tcK1hL4ZqsjOnS7BrTk1r8zwNvCw1XEeH2S1rPftAWH4PvzL4j86DFA== +"@abp/clipboard@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.3.0-rc.1.tgz#ee71a9f7d9bfa2983246471856d9b49881157cf2" + integrity sha512-mm0laSC0OQkn5m3Wg6zFqFrqH7+fPOQYwaZltbeWJ48i0In44j0On6CsqtBmQ+stB5etdPOXJaIOgYm8eSle9A== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" clipboard "^2.0.11" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/highlight.js@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/highlight.js/-/highlight.js-9.2.0.tgz#85ac7c252aee377c2ff9e15153c692fdea5cb96d" - integrity sha512-zD6UVZNUQEJ22ynqQs14jR8eBWQR7loOCpt9lPlIjXF6tnoBvcc7NBeBFw9ehKjkG2cegJCmahYb4cFnlJFigA== +"@abp/highlight.js@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/highlight.js/-/highlight.js-9.3.0-rc.1.tgz#7c00e4b5d3e3a12cece9a1fa271dc086fe675027" + integrity sha512-a6BJ75+P9wiEprSNBe1zyYTYAkM8KB0eKMHl+228Wf7IOQ99AEW8qhaJX292jAxzRNVlhx1o+AMSRNo3HY4m2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@highlightjs/cdn-assets" "~11.10.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/prismjs@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.2.0.tgz#03fca8cd2f4bdc09a68bd9b1fcdeaede56f96542" - integrity sha512-OUbjaxeXKxmrR9fZe/wazS9hGrYXYam/CypnQNTVaNNgSpwvgoKoCFCll9SJUGV8tXA6iEpVdszMGyRY5Hov+g== +"@abp/prismjs@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.3.0-rc.1.tgz#7d2dba62467475f4f43ce1d951b4c704d22dfcd7" + integrity sha512-9R28n3iIbB9fkjklNXf147yLlopfFYisEtuL1p6Rhon3iRYK7kUEdg3GdM/GdiQVaDkLXJWgAK8/jU6bK+vQiw== dependencies: - "@abp/clipboard" "~9.2.0" - "@abp/core" "~9.2.0" + "@abp/clipboard" "~9.3.0-rc.1" + "@abp/core" "~9.3.0-rc.1" prismjs "^1.29.0" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs index 4ebeb18498..c887825b2b 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/AbpAspNetCoreMvcUiThemeBasicDemoModule.cs @@ -55,8 +55,8 @@ public class AbpAspNetCoreMvcUiThemeBasicDemoModule : AbpModule app.UseDeveloperExceptionPage(); } - app.MapAbpStaticAssets(); app.UseRouting(); + app.MapAbpStaticAssets(); app.UseConfiguredEndpoints(); } } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs index a27f797715..d2ca3053b8 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Program.cs @@ -1,30 +1,42 @@ using System; -using Microsoft.AspNetCore.Hosting; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; -using Serilog.Events; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo; public class Program { - public static int Main(string[] args) + public async static Task Main(string[] args) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .Enrich.FromLogContext() - .WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.Console()) .CreateLogger(); try { Log.Information("Starting web host."); - CreateHostBuilder(args).Build().Run(); + var builder = WebApplication.CreateBuilder(args); + builder.Host.AddAppSettingsSecretsJson() + .UseAutofac() + .UseSerilog(); + await builder.AddApplicationAsync(); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); return 0; } catch (Exception ex) { + if (ex is HostAbortedException) + { + throw; + } + Log.Fatal(ex, "Host terminated unexpectedly!"); return 1; } @@ -33,14 +45,4 @@ public class Program Log.CloseAndFlush(); } } - - - internal static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) - .UseAutofac() - .UseSerilog(); } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json index 9bee4298ff..4ae3999794 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Properties/launchSettings.json @@ -1,24 +1,9 @@ { - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:61659", - "sslPort": 0 - } - }, "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "https://localhost:5001", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs deleted file mode 100644 index a11ca855da..0000000000 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/Startup.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo; - -public class Startup -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) - { - app.InitializeApplication(); - } -} diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json index 63f441f6f3..9f591b6fa5 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/package.json @@ -3,8 +3,8 @@ "name": "asp.net", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0", - "@abp/prismjs": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1", + "@abp/prismjs": "~9.3.0-rc.1" }, "devDependencies": {} } diff --git a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock index e2f54a2f6b..e3dc2860d3 100644 --- a/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock +++ b/modules/basic-theme/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo/yarn.lock @@ -2,202 +2,202 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" - -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== - dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/clipboard@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.2.0.tgz#348a0e45752c7eb055fb00af52660593ad340caf" - integrity sha512-2+wt2ShLBfoHqx0DNNevJkaz1POLcs1tcK1hL4ZqsjOnS7BrTk1r8zwNvCw1XEeH2S1rPftAWH4PvzL4j86DFA== +"@abp/clipboard@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.3.0-rc.1.tgz#ee71a9f7d9bfa2983246471856d9b49881157cf2" + integrity sha512-mm0laSC0OQkn5m3Wg6zFqFrqH7+fPOQYwaZltbeWJ48i0In44j0On6CsqtBmQ+stB5etdPOXJaIOgYm8eSle9A== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" clipboard "^2.0.11" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/prismjs@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.2.0.tgz#03fca8cd2f4bdc09a68bd9b1fcdeaede56f96542" - integrity sha512-OUbjaxeXKxmrR9fZe/wazS9hGrYXYam/CypnQNTVaNNgSpwvgoKoCFCll9SJUGV8tXA6iEpVdszMGyRY5Hov+g== +"@abp/prismjs@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.3.0-rc.1.tgz#7d2dba62467475f4f43ce1d951b4c704d22dfcd7" + integrity sha512-9R28n3iIbB9fkjklNXf147yLlopfFYisEtuL1p6Rhon3iRYK7kUEdg3GdM/GdiQVaDkLXJWgAK8/jU6bK+vQiw== dependencies: - "@abp/clipboard" "~9.2.0" - "@abp/core" "~9.2.0" + "@abp/clipboard" "~9.3.0-rc.1" + "@abp/core" "~9.3.0-rc.1" prismjs "^1.29.0" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/blogging/app/Volo.BloggingTestApp/package.json b/modules/blogging/app/Volo.BloggingTestApp/package.json index 7a947aa7e3..cf23da5e9d 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/package.json +++ b/modules/blogging/app/Volo.BloggingTestApp/package.json @@ -3,7 +3,7 @@ "name": "volo.blogtestapp", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0", - "@abp/blogging": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1", + "@abp/blogging": "~9.3.0-rc.1" } } diff --git a/modules/blogging/app/Volo.BloggingTestApp/yarn.lock b/modules/blogging/app/Volo.BloggingTestApp/yarn.lock index 7da6e7ae57..b444c8b417 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/yarn.lock +++ b/modules/blogging/app/Volo.BloggingTestApp/yarn.lock @@ -2,228 +2,228 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" - -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== - dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/blogging@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/blogging/-/blogging-9.2.0.tgz#62f4490e4c454fff8e10a84c1a7d8aee85b94313" - integrity sha512-ptaawKmyUTgGCWOxKPjLCxTY7X/fYTyxoB4sTy2O9vcaDrNqZephppKGl/nTn2EBxsYLKRGDKCl5z0Kl9MG6pQ== +"@abp/blogging@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/blogging/-/blogging-9.3.0-rc.1.tgz#6bc2ca73b57f683523652f22c7657db12b6cf4e3" + integrity sha512-cgSj2JEo91n66BAV3+/k/sASXRGfSDjIcg68eIDnHvFHIQTatx+EEjgNvia9/Sp2B6BYm97Ay4ckbfFNRAg93Q== dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" - "@abp/owl.carousel" "~9.2.0" - "@abp/prismjs" "~9.2.0" - "@abp/tui-editor" "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" + "@abp/owl.carousel" "~9.3.0-rc.1" + "@abp/prismjs" "~9.3.0-rc.1" + "@abp/tui-editor" "~9.3.0-rc.1" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/clipboard@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.2.0.tgz#348a0e45752c7eb055fb00af52660593ad340caf" - integrity sha512-2+wt2ShLBfoHqx0DNNevJkaz1POLcs1tcK1hL4ZqsjOnS7BrTk1r8zwNvCw1XEeH2S1rPftAWH4PvzL4j86DFA== +"@abp/clipboard@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.3.0-rc.1.tgz#ee71a9f7d9bfa2983246471856d9b49881157cf2" + integrity sha512-mm0laSC0OQkn5m3Wg6zFqFrqH7+fPOQYwaZltbeWJ48i0In44j0On6CsqtBmQ+stB5etdPOXJaIOgYm8eSle9A== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" clipboard "^2.0.11" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/owl.carousel@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/owl.carousel/-/owl.carousel-9.2.0.tgz#e2bd2c6a67cf942302393cd12c44519ea55eb27b" - integrity sha512-nu1noD/VX9Fae6PGDPMGMTV+/973xoRS4oolYDiYUBVcCzXjPNI6bvVGpnwNJbx+pgHyW07eh008qZ6pR3R3ug== +"@abp/owl.carousel@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/owl.carousel/-/owl.carousel-9.3.0-rc.1.tgz#2875a010f4ec4967964137b9fe941c36fb987706" + integrity sha512-wFHNAlWnb8XM3tIrOFl8smSYYnQmjh3x75Qlq9L80ICAVO5lDNkFisa7vmRP5xbE9FylhuKad7PoM6PAaIVBGQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" owl.carousel "^2.3.4" -"@abp/prismjs@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.2.0.tgz#03fca8cd2f4bdc09a68bd9b1fcdeaede56f96542" - integrity sha512-OUbjaxeXKxmrR9fZe/wazS9hGrYXYam/CypnQNTVaNNgSpwvgoKoCFCll9SJUGV8tXA6iEpVdszMGyRY5Hov+g== +"@abp/prismjs@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.3.0-rc.1.tgz#7d2dba62467475f4f43ce1d951b4c704d22dfcd7" + integrity sha512-9R28n3iIbB9fkjklNXf147yLlopfFYisEtuL1p6Rhon3iRYK7kUEdg3GdM/GdiQVaDkLXJWgAK8/jU6bK+vQiw== dependencies: - "@abp/clipboard" "~9.2.0" - "@abp/core" "~9.2.0" + "@abp/clipboard" "~9.3.0-rc.1" + "@abp/core" "~9.3.0-rc.1" prismjs "^1.29.0" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/tui-editor@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/tui-editor/-/tui-editor-9.2.0.tgz#f28e1099e39def76ff81d1db64f5e352f0d28f02" - integrity sha512-h3Nq0LmkmPWBx1tzPnImJAhPFlAD8sX/GnlAvEZGY3XJ7X6146TPl7HIzZ4fnttm+ilhuDUG2qydgIek/5pWLw== +"@abp/tui-editor@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/tui-editor/-/tui-editor-9.3.0-rc.1.tgz#a0017b22dfc5b09493789da2b49fa52a9fa769a5" + integrity sha512-Blrpb0c3ZskKEb5xivG8BcSfcWgFosLbsWaw03AHJ5qzZ5GF9GAqWr8UtqqxOB8EDJCdtKh64VldsY6WK63Vfg== dependencies: - "@abp/jquery" "~9.2.0" - "@abp/prismjs" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" + "@abp/prismjs" "~9.3.0-rc.1" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json index d190683ea4..44d7654a94 100644 --- a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json +++ b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package.json @@ -3,6 +3,6 @@ "name": "client-simulation-web", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1" } } diff --git a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock index 6c8afa8deb..93d0931275 100644 --- a/modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock +++ b/modules/client-simulation/demo/Volo.ClientSimulation.Demo/yarn.lock @@ -2,185 +2,185 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/cms-kit/angular/package.json b/modules/cms-kit/angular/package.json index c3f2f5712a..7750c8a578 100644 --- a/modules/cms-kit/angular/package.json +++ b/modules/cms-kit/angular/package.json @@ -15,11 +15,11 @@ }, "private": true, "dependencies": { - "@abp/ng.account": "~9.2.0", - "@abp/ng.identity": "~9.2.0", - "@abp/ng.setting-management": "~9.2.0", - "@abp/ng.tenant-management": "~9.2.0", - "@abp/ng.theme.basic": "~9.2.0", + "@abp/ng.account": "~9.3.0-rc.1", + "@abp/ng.identity": "~9.3.0-rc.1", + "@abp/ng.setting-management": "~9.3.0-rc.1", + "@abp/ng.tenant-management": "~9.3.0-rc.1", + "@abp/ng.theme.basic": "~9.3.0-rc.1", "@angular/animations": "~10.0.0", "@angular/common": "~10.0.0", "@angular/compiler": "~10.0.0", diff --git a/modules/cms-kit/angular/projects/cms-kit/package.json b/modules/cms-kit/angular/projects/cms-kit/package.json index b02a75bb34..31580c4923 100644 --- a/modules/cms-kit/angular/projects/cms-kit/package.json +++ b/modules/cms-kit/angular/projects/cms-kit/package.json @@ -4,8 +4,8 @@ "peerDependencies": { "@angular/common": "^9.1.11", "@angular/core": "^9.1.11", - "@abp/ng.core": ">=9.2.0", - "@abp/ng.theme.shared": ">=9.2.0" + "@abp/ng.core": ">=9.3.0-rc.1", + "@abp/ng.theme.shared": ">=9.3.0-rc.1" }, "dependencies": { "tslib": "^2.0.0" diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/package.json b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/package.json index 39e7548d18..62fc74b2d3 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/package.json +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/package.json @@ -3,6 +3,6 @@ "name": "my-app-identityserver", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1" } } diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/yarn.lock b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/yarn.lock index 6c8afa8deb..93d0931275 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/yarn.lock +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/yarn.lock @@ -2,185 +2,185 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Host/package.json b/modules/cms-kit/host/Volo.CmsKit.Web.Host/package.json index 8bcd4ab173..a7b7d09091 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Host/package.json +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Host/package.json @@ -3,6 +3,6 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1" } } diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Host/yarn.lock b/modules/cms-kit/host/Volo.CmsKit.Web.Host/yarn.lock index 6c8afa8deb..93d0931275 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Host/yarn.lock +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Host/yarn.lock @@ -2,185 +2,185 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json index 697f1c7ba2..0dd61fb515 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json @@ -3,7 +3,7 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0", - "@abp/cms-kit": "9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1", + "@abp/cms-kit": "9.3.0-rc.1" } } diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock index 37cacca8fb..fde3263832 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock @@ -2,293 +2,293 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" - -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== - dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/clipboard@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.2.0.tgz#348a0e45752c7eb055fb00af52660593ad340caf" - integrity sha512-2+wt2ShLBfoHqx0DNNevJkaz1POLcs1tcK1hL4ZqsjOnS7BrTk1r8zwNvCw1XEeH2S1rPftAWH4PvzL4j86DFA== +"@abp/clipboard@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.3.0-rc.1.tgz#ee71a9f7d9bfa2983246471856d9b49881157cf2" + integrity sha512-mm0laSC0OQkn5m3Wg6zFqFrqH7+fPOQYwaZltbeWJ48i0In44j0On6CsqtBmQ+stB5etdPOXJaIOgYm8eSle9A== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" clipboard "^2.0.11" -"@abp/cms-kit.admin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/cms-kit.admin/-/cms-kit.admin-9.2.0.tgz#b86b76692214ab793175d275c9c2845ac44524ce" - integrity sha512-s5Mh7OrDBngxD67AE5amtFFCpqY3ZaYVCPnboIvsMNiGk5U3JTqRZU+Ec1L1OpuoBg+jJDbKvPGQEFRuadMKQA== +"@abp/cms-kit.admin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/cms-kit.admin/-/cms-kit.admin-9.3.0-rc.1.tgz#176a17837a59e9d0047492fe490178daed838814" + integrity sha512-2kO5LvUnFaGV/qZ0jJRI6zH0N6q7oXGc2sREce2/CCFJo4YSM4LpiDt7CZbP6zlqHZwVoLQuIxYvFQRSjNNbtA== dependencies: - "@abp/codemirror" "~9.2.0" - "@abp/jstree" "~9.2.0" - "@abp/markdown-it" "~9.2.0" - "@abp/slugify" "~9.2.0" - "@abp/tui-editor" "~9.2.0" - "@abp/uppy" "~9.2.0" + "@abp/codemirror" "~9.3.0-rc.1" + "@abp/jstree" "~9.3.0-rc.1" + "@abp/markdown-it" "~9.3.0-rc.1" + "@abp/slugify" "~9.3.0-rc.1" + "@abp/tui-editor" "~9.3.0-rc.1" + "@abp/uppy" "~9.3.0-rc.1" -"@abp/cms-kit.public@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/cms-kit.public/-/cms-kit.public-9.2.0.tgz#a85c5923593354614f7a339a5ef17b12ea71a2ea" - integrity sha512-W2KhpFZLBK+Q9ZdHI0IYhrfC1ZRem+Ox55tg1G0Ai3TabOLMyr6ubgE4maU6BUNak76DKBkzDXB/SxNFWMvS+g== +"@abp/cms-kit.public@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/cms-kit.public/-/cms-kit.public-9.3.0-rc.1.tgz#e4ef7d347e51ff73c5ef73ad1bc4d0de153852a8" + integrity sha512-r9zdSD44A1+pJ+S/CHwn1JX25ubwDgHKU24YCFCTI+MhFB/KUfnqX6hBQ5btwrGr7wee3Csmd9VX9YUvIgvcbQ== dependencies: - "@abp/highlight.js" "~9.2.0" - "@abp/star-rating-svg" "~9.2.0" + "@abp/highlight.js" "~9.3.0-rc.1" + "@abp/star-rating-svg" "~9.3.0-rc.1" -"@abp/cms-kit@9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/cms-kit/-/cms-kit-9.2.0.tgz#da9a3dfc3c83755a3c920b0392ec2b37106b5bf1" - integrity sha512-JHAiyppt9+Vx9f70duawR8OSWFaSrlPl1mOdLOD4fUWek7j7HhSyFgjddwzaBjLXqSnicTFwg2pmY1qTa8XjMw== +"@abp/cms-kit@9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/cms-kit/-/cms-kit-9.3.0-rc.1.tgz#b1994b700d302fc7291d86ac779598dbf5c9acdb" + integrity sha512-Ljqg9E5nnMbnamXsd8GzOOQEwC2f1VSkCAdkXGW5hxNVKp/zo7DoxiVuW0c/kAP0qxqYKeBFSiLilBBHYGTKAw== dependencies: - "@abp/cms-kit.admin" "~9.2.0" - "@abp/cms-kit.public" "~9.2.0" + "@abp/cms-kit.admin" "~9.3.0-rc.1" + "@abp/cms-kit.public" "~9.3.0-rc.1" -"@abp/codemirror@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/codemirror/-/codemirror-9.2.0.tgz#83b9c805669640e739a68ad26788547202958bff" - integrity sha512-feYwaVZT7LH46BZPEkgpRHIEpn/vqcU5yo4QQ/u8t/D4veYfgLUdMqzt6P6kyFpgzb0X1+SOqvlWBRHBAHeQrQ== +"@abp/codemirror@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/codemirror/-/codemirror-9.3.0-rc.1.tgz#df37bb732e679f4d1a398620ed351361b61486a4" + integrity sha512-+iqJsEJRmGOf6GPS7/kasmnnWslHwKROVj8yQ9Oe+Hj+ofVDC3Bg1vt5RWw3qq5f2EvehQ0moGnj9sK5wRGgdw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" codemirror "^5.65.1" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/highlight.js@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/highlight.js/-/highlight.js-9.2.0.tgz#85ac7c252aee377c2ff9e15153c692fdea5cb96d" - integrity sha512-zD6UVZNUQEJ22ynqQs14jR8eBWQR7loOCpt9lPlIjXF6tnoBvcc7NBeBFw9ehKjkG2cegJCmahYb4cFnlJFigA== +"@abp/highlight.js@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/highlight.js/-/highlight.js-9.3.0-rc.1.tgz#7c00e4b5d3e3a12cece9a1fa271dc086fe675027" + integrity sha512-a6BJ75+P9wiEprSNBe1zyYTYAkM8KB0eKMHl+228Wf7IOQ99AEW8qhaJX292jAxzRNVlhx1o+AMSRNo3HY4m2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@highlightjs/cdn-assets" "~11.10.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/jstree@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jstree/-/jstree-9.2.0.tgz#eb167f0909aacbe3652f169f35b8e62743ed43b8" - integrity sha512-Aj35TeMTN1zwgITeCUsg9rFsiJ0r3IeGfKCv7PEL1AJUh37fU0CwVtHNhM0aOi1oUNJeMjs4XnFVYCqzJzVaNw== +"@abp/jstree@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jstree/-/jstree-9.3.0-rc.1.tgz#8cac6ceb2efc14687a02166b658ff11eacd7924a" + integrity sha512-8L9DGXusrzPYTSr//NuLgXKJG95GKbvqApE+wkL/pWYOZoEDoWE29tVEsDf1N7G257L9yrDoWRJterbkrJvNqA== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jstree "^3.3.17" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/markdown-it@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/markdown-it/-/markdown-it-9.2.0.tgz#74946415e4893deb5952e626d7314db1b926e4a3" - integrity sha512-yc0N0MeaqhBYkUw3/mIMuafNCk/tnh/paG3xObTFrGTqvU7yhlNH5je3ZQ2oBOlF3wHe/6ge0foS/3/fuGvsOQ== +"@abp/markdown-it@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/markdown-it/-/markdown-it-9.3.0-rc.1.tgz#1b1db292bad4d5a1c663b60833d3894c21f9f1aa" + integrity sha512-av1eFFEGbl83iCgs2rI7kwxq43vtuQFf+JzmIFK98T6GiXD6jXng8rMGFcuVx/rgZ6zjgAm1cjMEAZebY4l/cg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" markdown-it "^14.1.0" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/prismjs@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.2.0.tgz#03fca8cd2f4bdc09a68bd9b1fcdeaede56f96542" - integrity sha512-OUbjaxeXKxmrR9fZe/wazS9hGrYXYam/CypnQNTVaNNgSpwvgoKoCFCll9SJUGV8tXA6iEpVdszMGyRY5Hov+g== +"@abp/prismjs@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.3.0-rc.1.tgz#7d2dba62467475f4f43ce1d951b4c704d22dfcd7" + integrity sha512-9R28n3iIbB9fkjklNXf147yLlopfFYisEtuL1p6Rhon3iRYK7kUEdg3GdM/GdiQVaDkLXJWgAK8/jU6bK+vQiw== dependencies: - "@abp/clipboard" "~9.2.0" - "@abp/core" "~9.2.0" + "@abp/clipboard" "~9.3.0-rc.1" + "@abp/core" "~9.3.0-rc.1" prismjs "^1.29.0" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/slugify@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/slugify/-/slugify-9.2.0.tgz#b71ae2f237866a97422c4fe1720ab62b8971ead5" - integrity sha512-yjNKhWOTxW9T87g+5CGH9R3w/Pm97H5eJLAEMYs4th5CqpU6ECtab4+1xIboF7LEkB1HwLHjAxa80UUKpdGe+A== +"@abp/slugify@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/slugify/-/slugify-9.3.0-rc.1.tgz#ec0705bb95d4cfb2258520f5726be34f070bf9d6" + integrity sha512-z1kblo9IhYk4stEX64QILa5wrDAZueaBJYAir2yrHdNh+1C9GpIeFQZvHVyA60nU2zVhOggGtzwA1lXUCNHmZg== dependencies: slugify "^1.6.6" -"@abp/star-rating-svg@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/star-rating-svg/-/star-rating-svg-9.2.0.tgz#a1cccb2dd82bbaf1288dc530b3c5ff81a4dd772e" - integrity sha512-eMYhBlWzEK8EUIS/FYEafhyc1CbCB3qL8PpenFYyLDjMb9kfv3z5x05MYIn2o8vTYYuMrTS/bWAYCAYQOVJCBg== +"@abp/star-rating-svg@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/star-rating-svg/-/star-rating-svg-9.3.0-rc.1.tgz#cde2c9a13f043a5cfc948e2e3564735c92d2e85f" + integrity sha512-7u3Z7id6gp/smUn3N+aoJKmiPO2bz7LLKH3Rz9k53hyhm5ZvKNfwC3E64fk+F/NiklTwBPfxI/gvDDaeRvq3IQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" star-rating-svg "^3.5.0" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/tui-editor@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/tui-editor/-/tui-editor-9.2.0.tgz#f28e1099e39def76ff81d1db64f5e352f0d28f02" - integrity sha512-h3Nq0LmkmPWBx1tzPnImJAhPFlAD8sX/GnlAvEZGY3XJ7X6146TPl7HIzZ4fnttm+ilhuDUG2qydgIek/5pWLw== +"@abp/tui-editor@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/tui-editor/-/tui-editor-9.3.0-rc.1.tgz#a0017b22dfc5b09493789da2b49fa52a9fa769a5" + integrity sha512-Blrpb0c3ZskKEb5xivG8BcSfcWgFosLbsWaw03AHJ5qzZ5GF9GAqWr8UtqqxOB8EDJCdtKh64VldsY6WK63Vfg== dependencies: - "@abp/jquery" "~9.2.0" - "@abp/prismjs" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" + "@abp/prismjs" "~9.3.0-rc.1" -"@abp/uppy@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/uppy/-/uppy-9.2.0.tgz#319cc21b655c310e5bf76bca787a181cd59bb2df" - integrity sha512-8SpMK46F9nNwZpXGn1AjzSTARC47K1hPqX2uzuNePCC0nT4RtP/711XrloawOhlefFwvG7n66cknU9LSBvwcMA== +"@abp/uppy@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/uppy/-/uppy-9.3.0-rc.1.tgz#7517a58502ce3f3b38587dd5f5bd764451311e35" + integrity sha512-B1VXv2gwLl92/14OPjW+gMZ3UAV/4f8n9LzXU1T4iaRcCaXaIu2lUmUvsM5vg6RUWWljj3pYkL8k2GeDlcw/cQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" uppy "^4.4.1" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml index a9d064235f..8cb0b482b5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml @@ -3,6 +3,7 @@ @using System.Globalization @using Microsoft.AspNetCore.Mvc.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Layout +@using Volo.Abp.Timing @using Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments @using Volo.CmsKit.Admin.Web.Menus @using Volo.CmsKit.Comments @@ -10,6 +11,7 @@ @inject IPageLayout PageLayout @inject IHtmlLocalizer L +@inject IClock Clock @model DetailsModel @@ -50,7 +52,7 @@ @L["CreationTime"]: - @Model.CommentWithAuthorDto.CreationTime.ToString(CultureInfo.CurrentUICulture) + @Clock.ConvertToUserTime(Model.CommentWithAuthorDto.CreationTime).ToString(CultureInfo.CurrentUICulture)) @L["Username"]: diff --git a/modules/docs/Volo.Docs.abpmdl b/modules/docs/Volo.Docs.abpmdl index 77c70bddf8..bb861a309d 100644 --- a/modules/docs/Volo.Docs.abpmdl +++ b/modules/docs/Volo.Docs.abpmdl @@ -86,6 +86,22 @@ "Volo.Docs.MongoDB.Tests": { "path": "test/Volo.Docs.MongoDB.Tests/Volo.Docs.MongoDB.Tests.abppkg", "folder": "test" + }, + "Volo.Docs.Common.Application": { + "path": "src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.abppkg", + "folder": "src" + }, + "Volo.Docs.Common.Application.Contracts": { + "path": "src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.abppkg", + "folder": "src" + }, + "Volo.Docs.Common.HttpApi": { + "path": "src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.abppkg", + "folder": "src" + }, + "Volo.Docs.Common.HttpApi.Client": { + "path": "src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.abppkg", + "folder": "src" } } } \ No newline at end of file diff --git a/modules/docs/Volo.Docs.sln b/modules/docs/Volo.Docs.sln index 6bb8d84d0a..af9282dca3 100644 --- a/modules/docs/Volo.Docs.sln +++ b/modules/docs/Volo.Docs.sln @@ -63,6 +63,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Docs.MongoDB.Tests", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Installer", "src\Volo.Docs.Installer\Volo.Docs.Installer.csproj", "{50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.Application", "src\Volo.Docs.Common.Application\Volo.Docs.Common.Application.csproj", "{914EDEC4-EFCE-46D5-B6E0-A928B1907307}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.Application.Contracts", "src\Volo.Docs.Common.Application.Contracts\Volo.Docs.Common.Application.Contracts.csproj", "{8CA19527-6870-4617-B6D1-EA8CAF224DF4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.HttpApi", "src\Volo.Docs.Common.HttpApi\Volo.Docs.Common.HttpApi.csproj", "{052C076D-56FF-4DFA-838B-48BD30A1DB0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Docs.Common.HttpApi.Client", "src\Volo.Docs.Common.HttpApi.Client\Volo.Docs.Common.HttpApi.Client.csproj", "{349C36A0-552D-44A3-AC74-03A4828D43AB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -165,6 +175,22 @@ Global {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}.Debug|Any CPU.Build.0 = Debug|Any CPU {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}.Release|Any CPU.ActiveCfg = Release|Any CPU {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1}.Release|Any CPU.Build.0 = Release|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Debug|Any CPU.Build.0 = Debug|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Release|Any CPU.ActiveCfg = Release|Any CPU + {914EDEC4-EFCE-46D5-B6E0-A928B1907307}.Release|Any CPU.Build.0 = Release|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CA19527-6870-4617-B6D1-EA8CAF224DF4}.Release|Any CPU.Build.0 = Release|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {052C076D-56FF-4DFA-838B-48BD30A1DB0A}.Release|Any CPU.Build.0 = Release|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {349C36A0-552D-44A3-AC74-03A4828D43AB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -197,6 +223,11 @@ Global {DBE846CD-1BED-4F2C-ABF2-94F6240BCB9B} = {A982A58E-1E92-4764-9F56-39E7AABB8556} {C5E2A2A3-D54D-4C2E-97BA-EA50A49ED7AD} = {59D430A9-AC61-4457-8338-5DA0705ABB5D} {50B9AC1D-C03E-47AA-9ED8-E7986BCFABA1} = {A982A58E-1E92-4764-9F56-39E7AABB8556} + {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} = {42416152-5BAB-4706-93A6-57A19E71FE14} + {914EDEC4-EFCE-46D5-B6E0-A928B1907307} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} + {8CA19527-6870-4617-B6D1-EA8CAF224DF4} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} + {052C076D-56FF-4DFA-838B-48BD30A1DB0A} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} + {349C36A0-552D-44A3-AC74-03A4828D43AB} = {F778B2C3-2E6D-4CF3-ACA7-10E21E6A7961} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {13691265-2547-4FFF-B757-E8FACB05679D} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.Designer.cs similarity index 93% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.Designer.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.Designer.cs index ad7dfa9576..325052b498 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.Designer.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.Designer.cs @@ -13,8 +13,8 @@ using VoloDocs.EntityFrameworkCore; namespace Migrations { [DbContext(typeof(VoloDocsDbContext))] - [Migration("20241231072012_Initial")] - partial class Initial + [Migration("20250411070040_initial")] + partial class initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -22,11 +22,88 @@ namespace Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("ProductVersion", "9.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -1119,6 +1196,15 @@ namespace Migrations b.ToTable("DocsProjects", (string)null); }); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => { b.HasOne("Volo.Abp.Identity.IdentityRole", null) diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.cs similarity index 93% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.cs index 25791fabf4..1c03234da9 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20241231072012_Initial.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250411070040_initial.cs @@ -6,11 +6,26 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Migrations { /// - public partial class Initial : Migration + public partial class initial : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.CreateTable( + name: "AbpBlobContainers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBlobContainers", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -336,6 +351,29 @@ namespace Migrations table.PrimaryKey("PK_DocsProjects", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpBlobs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ContainerId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Content = table.Column(type: "varbinary(max)", maxLength: 2147483647, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBlobs", x => x.Id); + table.ForeignKey( + name: "FK_AbpBlobs_AbpBlobContainers_ContainerId", + column: x => x.ContainerId, + principalTable: "AbpBlobContainers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "AbpOrganizationUnitRoles", columns: table => new @@ -520,6 +558,21 @@ namespace Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateIndex( + name: "IX_AbpBlobContainers_TenantId_Name", + table: "AbpBlobContainers", + columns: new[] { "TenantId", "Name" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpBlobs_ContainerId", + table: "AbpBlobs", + column: "ContainerId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpBlobs_TenantId_ContainerId_Name", + table: "AbpBlobs", + columns: new[] { "TenantId", "ContainerId", "Name" }); + migrationBuilder.CreateIndex( name: "IX_AbpLinkUsers_SourceUserId_SourceTenantId_TargetUserId_TargetTenantId", table: "AbpLinkUsers", @@ -668,6 +721,9 @@ namespace Migrations /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "AbpBlobs"); + migrationBuilder.DropTable( name: "AbpClaimTypes"); @@ -725,6 +781,9 @@ namespace Migrations migrationBuilder.DropTable( name: "DocsProjects"); + migrationBuilder.DropTable( + name: "AbpBlobContainers"); + migrationBuilder.DropTable( name: "AbpOrganizationUnits"); diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs new file mode 100644 index 0000000000..c284a80f8b --- /dev/null +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.Designer.cs @@ -0,0 +1,1376 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using VoloDocs.EntityFrameworkCore; + +#nullable disable + +namespace Migrations +{ + [DbContext(typeof(VoloDocsDbContext))] + [Migration("20250425082043_add_pdf_file")] + partial class add_pdf_file + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Device") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("DeviceInfo") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IpAddresses") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("LastAccessed") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("SignedIn") + .HasColumnType("datetime2"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Device"); + + b.HasIndex("SessionId"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSessions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("bit") + .HasColumnName("IsActive"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("AbpUserDelegations", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[TenantId] IS NOT NULL"); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique() + .HasFilter("[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("bit"); + + b.Property("IsInherited") + .HasColumnType("bit"); + + b.Property("IsVisibleToClients") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Documents.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("EditLink") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Format") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LanguageCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LastCachedTime") + .HasColumnType("datetime2"); + + b.Property("LastSignificantUpdateTime") + .HasColumnType("datetime2"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetime2"); + + b.Property("LocalDirectory") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("RawRootUrl") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("RootUrl") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("Version") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("DocsDocuments", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Documents.DocumentContributor", b => + { + b.Property("DocumentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Username") + .HasColumnType("nvarchar(450)"); + + b.Property("AvatarUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("CommitCount") + .HasColumnType("int"); + + b.Property("UserProfileUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("DocumentId", "Username"); + + b.ToTable("DocsDocumentContributors", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("DocumentStoreType") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Format") + .HasColumnType("nvarchar(max)"); + + b.Property("LatestVersionBranchName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("MainWebsiteUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("MinimumVersion") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("NavigationDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParametersDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ShortName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.ToTable("DocsProjects", (string)null); + }); + + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("FileName") + .HasColumnType("nvarchar(450)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("LanguageCode") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("Version") + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProjectId", "FileName"); + + b.ToTable("DocsProjectPdfFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Docs.Documents.DocumentContributor", b => + { + b.HasOne("Volo.Docs.Documents.Document", null) + .WithMany("Contributors") + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.HasOne("Volo.Docs.Projects.Project", null) + .WithMany("PdfFiles") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Docs.Documents.Document", b => + { + b.Navigation("Contributors"); + }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Navigation("PdfFiles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs new file mode 100644 index 0000000000..2f9f296c25 --- /dev/null +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20250425082043_add_pdf_file.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Migrations +{ + /// + public partial class add_pdf_file : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DocsProjectPdfFiles", + columns: table => new + { + ProjectId = table.Column(type: "uniqueidentifier", nullable: false), + FileName = table.Column(type: "nvarchar(450)", nullable: false), + Version = table.Column(type: "nvarchar(max)", nullable: true), + LanguageCode = table.Column(type: "nvarchar(max)", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + LastModificationTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DocsProjectPdfFiles", x => new { x.ProjectId, x.FileName }); + table.ForeignKey( + name: "FK_DocsProjectPdfFiles_DocsProjects_ProjectId", + column: x => x.ProjectId, + principalTable: "DocsProjects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DocsProjectPdfFiles"); + } + } +} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs index 17e18940bb..14f36cafb1 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs @@ -19,11 +19,88 @@ namespace Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("ProductVersion", "9.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers", (string)null); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -1116,6 +1193,42 @@ namespace Migrations b.ToTable("DocsProjects", (string)null); }); + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("FileName") + .HasColumnType("nvarchar(450)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("LanguageCode") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("Version") + .HasColumnType("nvarchar(max)"); + + b.HasKey("ProjectId", "FileName"); + + b.ToTable("DocsProjectPdfFiles", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => { b.HasOne("Volo.Abp.Identity.IdentityRole", null) @@ -1213,6 +1326,15 @@ namespace Migrations .IsRequired(); }); + modelBuilder.Entity("Volo.Docs.Projects.ProjectPdfFile", b => + { + b.HasOne("Volo.Docs.Projects.Project", null) + .WithMany("PdfFiles") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => { b.Navigation("Claims"); @@ -1240,6 +1362,11 @@ namespace Migrations { b.Navigation("Contributors"); }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Navigation("PdfFiles"); + }); #pragma warning restore 612, 618 } } diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj index 38f85e7541..f7a6f89231 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocs.EntityFrameworkCore.csproj @@ -13,6 +13,7 @@ + diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs index fb6aca4e19..08ca58dd72 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsDbContext.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Volo.Abp.BlobStoring.Database.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.PermissionManagement.EntityFrameworkCore; @@ -23,6 +24,7 @@ namespace VoloDocs.EntityFrameworkCore modelBuilder.ConfigureSettingManagement(); modelBuilder.ConfigureIdentity(); modelBuilder.ConfigureDocs(); + modelBuilder.ConfigureBlobStoring(); } } } diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs index 44acea9a58..f94ec123bf 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/VoloDocsEntityFrameworkCoreModule.cs @@ -1,4 +1,5 @@ -using Volo.Abp.EntityFrameworkCore.SqlServer; +using Volo.Abp.BlobStoring.Database.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.EntityFrameworkCore; @@ -12,6 +13,7 @@ namespace VoloDocs.EntityFrameworkCore typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(BlobStoringDatabaseEntityFrameworkCoreModule), typeof(AbpEntityFrameworkCoreSqlServerModule))] public class VoloDocsEntityFrameworkCoreModule : AbpModule { diff --git a/modules/docs/app/VoloDocs.Migrator/appsettings.json b/modules/docs/app/VoloDocs.Migrator/appsettings.json index b554a47fed..9668adc1e2 100644 --- a/modules/docs/app/VoloDocs.Migrator/appsettings.json +++ b/modules/docs/app/VoloDocs.Migrator/appsettings.json @@ -1,3 +1,3 @@ { - "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;TrustServerCertificate=True" + "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;TrustServerCertificate=True", } \ No newline at end of file diff --git a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs index c335612ec4..512900e637 100644 --- a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs +++ b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Options; using Volo.Docs; -using Volo.Docs.Projects; +using Volo.Docs.Common.Projects; namespace VoloDocs.Web.Pages { diff --git a/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj b/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj index 0a59f42c87..316f29f84c 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj +++ b/modules/docs/app/VoloDocs.Web/VoloDocs.Web.csproj @@ -43,6 +43,7 @@ + diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index 743944c6d3..a28da09273 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -32,10 +32,15 @@ using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Volo.Abp.Account; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.BlobStoring; +using Volo.Abp.BlobStoring.Database; using Volo.Abp.PermissionManagement.HttpApi; using Volo.Abp.Validation.Localization; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Abp.Caching.StackExchangeRedis; +using Volo.Docs.Common.Documents; +using Volo.Docs.Projects.Pdf; namespace VoloDocs.Web { @@ -58,7 +63,8 @@ namespace VoloDocs.Web typeof(AbpPermissionManagementApplicationModule), typeof(AbpPermissionManagementHttpApiModule), typeof(AbpAspNetCoreMvcUiBasicThemeModule) - ,typeof(AbpCachingStackExchangeRedisModule) + ,typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpBackgroundJobsModule) )] public class VoloDocsWebModule : AbpModule { @@ -68,6 +74,11 @@ namespace VoloDocs.Web { options.AddAssemblyResource(typeof(DocsResource), typeof(VoloDocsWebModule).Assembly); }); + + PreConfigure(options => + { + options.ApplicationName = context.Services.GetApplicationName()!; + }); } public override void ConfigureServices(ServiceConfigurationContext context) @@ -82,7 +93,7 @@ namespace VoloDocs.Web // options.SingleProjectMode.ProjectName = "abp"; // options.MultiLanguageMode = false; // }); - + Configure(options => { options.Enable = false; @@ -170,6 +181,22 @@ namespace VoloDocs.Web options.EnableGoogleProgrammableSearchEngine = true; options.GoogleSearchEngineId = "77c7266532da1427f"; }); + + Configure(options => + { + options.BaseUrl = configuration["App:SelfUrl"]; + options.IndexPagePath = "index.md"; + options.CalculatePdfFileTitle = project => project.ShortName == "abp" ? "ABP Documentation" : null; + options.DocumentContentNormalizer = content => content.Replace("", "No").Replace("", "Yes"); + }); + + Configure(options => + { + options.Containers.ConfigureDefault(container => + { + container.UseDatabase(); + }); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/modules/docs/app/VoloDocs.Web/appsettings.json b/modules/docs/app/VoloDocs.Web/appsettings.json index 21a2883937..75d1b9890e 100644 --- a/modules/docs/app/VoloDocs.Web/appsettings.json +++ b/modules/docs/app/VoloDocs.Web/appsettings.json @@ -1,4 +1,7 @@ { + "App": { + "SelfUrl": "https://localhost:5001" + }, "Kestrel": { "EndPoints": { "Https": { diff --git a/modules/docs/app/VoloDocs.Web/package.json b/modules/docs/app/VoloDocs.Web/package.json index 440ad2c655..952dca14a7 100644 --- a/modules/docs/app/VoloDocs.Web/package.json +++ b/modules/docs/app/VoloDocs.Web/package.json @@ -3,7 +3,7 @@ "name": "volo.docstestapp", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0", - "@abp/docs": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1", + "@abp/docs": "~9.3.0-rc.1" } } diff --git a/modules/docs/app/VoloDocs.Web/yarn.lock b/modules/docs/app/VoloDocs.Web/yarn.lock index 6cff27f688..93c5fdd67a 100644 --- a/modules/docs/app/VoloDocs.Web/yarn.lock +++ b/modules/docs/app/VoloDocs.Web/yarn.lock @@ -2,229 +2,229 @@ # yarn lockfile v1 -"@abp/anchor-js@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/anchor-js/-/anchor-js-9.2.0.tgz#86aab2407c30a61be5babadb54e137e5ad4bfa9c" - integrity sha512-CdWo4jUxHiAFA6T0rx1ZxpmGB6GwUmklTSfugRbCRdhoUSTXXoh+xdUaoMkBmygP+S/o2BWekhIz1TE0dUeseg== +"@abp/anchor-js@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/anchor-js/-/anchor-js-9.3.0-rc.1.tgz#f0d7b1f8a2afe81fe8594f769a42582cd6a5461e" + integrity sha512-1ZaikqXvjjA+IgC7AGSPHVp5ombA1NmJ1i0ymqi0KaazntI0NNQRrDtK0NJDIEHloXPZz1I7lJwzdgR0ZriYbA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" anchor-js "^5.0.0" -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" - -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== - dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/clipboard@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.2.0.tgz#348a0e45752c7eb055fb00af52660593ad340caf" - integrity sha512-2+wt2ShLBfoHqx0DNNevJkaz1POLcs1tcK1hL4ZqsjOnS7BrTk1r8zwNvCw1XEeH2S1rPftAWH4PvzL4j86DFA== +"@abp/clipboard@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-9.3.0-rc.1.tgz#ee71a9f7d9bfa2983246471856d9b49881157cf2" + integrity sha512-mm0laSC0OQkn5m3Wg6zFqFrqH7+fPOQYwaZltbeWJ48i0In44j0On6CsqtBmQ+stB5etdPOXJaIOgYm8eSle9A== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" clipboard "^2.0.11" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/docs@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/docs/-/docs-9.2.0.tgz#6a400df7f91710ff529cbcfbaa6c6657bad9927b" - integrity sha512-zW3gh+VpaBubCMMMsH5gu8mcq3Mdm8kNCAQs/BlzRsrX1XqgRwXGOh9Dmrw7f5Ul1htbibsMYMDEXH0HNumebg== +"@abp/docs@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/docs/-/docs-9.3.0-rc.1.tgz#9bc1a3c6ab4cf21909f66660d1d46794e892c04d" + integrity sha512-evc28lbI5pThs5i7qFbpg66MR5us1AgQDafcse9vZlW4GlfIqGFnEDAsLzrLAwnCevDlCxknggN9W9SnDYc3Ng== dependencies: - "@abp/anchor-js" "~9.2.0" - "@abp/clipboard" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/popper.js" "~9.2.0" - "@abp/prismjs" "~9.2.0" + "@abp/anchor-js" "~9.3.0-rc.1" + "@abp/clipboard" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/popper.js" "~9.3.0-rc.1" + "@abp/prismjs" "~9.3.0-rc.1" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/popper.js@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/popper.js/-/popper.js-9.2.0.tgz#674cda57e74e3ce20d7e6e1a21fa48b72c35aeb6" - integrity sha512-OVsAbW1UbuLZlfoQg1BR8GNQpARvUMx2GE7MrobVVDQ0l8a9JM1i/MQzmCi1XAns5nCk/NqPzSN0NywF/G4FTg== +"@abp/popper.js@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/popper.js/-/popper.js-9.3.0-rc.1.tgz#722775deb63b00f7e631dd39ad20ab25205a0786" + integrity sha512-C8Kc+QbMR70XGII5wcZp1H2xuQCuQmMcAY+cZLLW7dFGTAFGekUI8grjDBbdt8kmrp9oX7rdmmArWjSFgcG3xA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@popperjs/core" "^2.11.8" -"@abp/prismjs@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.2.0.tgz#03fca8cd2f4bdc09a68bd9b1fcdeaede56f96542" - integrity sha512-OUbjaxeXKxmrR9fZe/wazS9hGrYXYam/CypnQNTVaNNgSpwvgoKoCFCll9SJUGV8tXA6iEpVdszMGyRY5Hov+g== +"@abp/prismjs@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-9.3.0-rc.1.tgz#7d2dba62467475f4f43ce1d951b4c704d22dfcd7" + integrity sha512-9R28n3iIbB9fkjklNXf147yLlopfFYisEtuL1p6Rhon3iRYK7kUEdg3GdM/GdiQVaDkLXJWgAK8/jU6bK+vQiw== dependencies: - "@abp/clipboard" "~9.2.0" - "@abp/core" "~9.2.0" + "@abp/clipboard" "~9.3.0-rc.1" + "@abp/core" "~9.3.0-rc.1" prismjs "^1.29.0" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj index a49d9146db..796a4a83c4 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo.Docs.Admin.Application.Contracts.csproj @@ -18,6 +18,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs index 0962a28aef..1e20041974 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminApplicationContractsModule.cs @@ -4,6 +4,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Common; using Volo.Docs.Localization; namespace Volo.Docs.Admin @@ -11,7 +12,8 @@ namespace Volo.Docs.Admin [DependsOn( typeof(DocsDomainSharedModule), typeof(AbpDddApplicationContractsModule), - typeof(AbpAuthorizationAbstractionsModule) + typeof(AbpAuthorizationAbstractionsModule), + typeof(DocsCommonApplicationContractsModule) )] public class DocsAdminApplicationContractsModule : AbpModule { diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs index 6f9bb6407e..0ce42e3143 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissionDefinitionProvider.cs @@ -14,6 +14,7 @@ namespace Volo.Docs.Admin projects.AddChild(DocsAdminPermissions.Projects.Update, L("Permission:Edit")); projects.AddChild(DocsAdminPermissions.Projects.Delete, L("Permission:Delete")); projects.AddChild(DocsAdminPermissions.Projects.Create, L("Permission:Create")); + projects.AddChild(DocsAdminPermissions.Projects.ManagePdfFiles, L("Permission:ManagePdfFiles")); group.AddPermission(DocsAdminPermissions.Documents.Default, L("Permission:Documents")); } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs index e6043241ea..f5d9a94410 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/DocsAdminPermissions.cs @@ -12,6 +12,7 @@ namespace Volo.Docs.Admin public const string Delete = Default + ".Delete"; public const string Update = Default + ".Update"; public const string Create = Default + ".Create"; + public const string ManagePdfFiles = Default + ".ManagePdfFiles"; } public static class Documents diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentPdfAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentPdfAdminAppService.cs new file mode 100644 index 0000000000..ad253cecef --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentPdfAdminAppService.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Docs.Admin.Projects; +using Volo.Docs.Common.Documents; + +namespace Volo.Docs.Admin.Documents; + +public interface IDocumentPdfAdminAppService : IDocumentPdfAppService +{ + Task GeneratePdfAsync(DocumentPdfGeneratorInput input); + + Task> GetPdfFilesAsync(GetPdfFilesInput input); + + Task DeletePdfFileAsync(DeletePdfFileInput input); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json index 458d1592f0..bd2b0c6526 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json @@ -1,7 +1,7 @@ { "culture": "ar", "texts": { - "Permission:DocumentManagement": "إدارة الوثائق", + "Permission:DocumentManagement": "إدارة المستندات", "Permission:Projects": "المشروعات", "Permission:Edit": "تعديل", "Permission:Delete": "حذف", @@ -57,6 +57,18 @@ "LastCachedTime": "وقت ذاكرة التخزين", "Project": "مشروع ", "AdvancedFilters": "مرشحات متقدمة", - "RemoveCacheAndReIndexConfirmation": "ستتم إزالة المستند \"{0}\" من ذاكرة التخزين المؤقت وإعادة فهرسته. هل تؤكد؟" + "RemoveCacheAndReIndexConfirmation": "ستتم إزالة المستند \"{0}\" من ذاكرة التخزين المؤقت وإعادة فهرسته. هل تؤكد؟", + "GeneratePdf": "توليد PDF", + "Generating": "يتم توليد...", + "Language": "اللغة", + "ForceToGenerateNewPdf": "قوة لتوليد PDF جديد", + "PdfGeneratedSuccessfully": "تم توليد PDF بنجاح", + "GenerateAndDownloadPdf": "توليد وتحميل PDF", + "PdfFileDeletionWarningMessage": "هل أنت متأكد أنك تريد حذف ملف PDF \"{0}\"?", + "ManagePdfFiles": "إدارة ملفات PDF", + "Permission:ManagePdfFiles": "إدارة ملفات PDF", + "PdfDeletedSuccessfully": "تم حذف ملف PDF بنجاح", + "PdfGenerationStarted": "بدأ إنشاء ملف PDF", + "PdfGenerationStartedInfoMessage": "بدأ إنشاء ملف PDF. بمجرد اكتمال العملية، يمكنك التحقق مما إذا تمت إضافة الملف في قسم ملفات PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json index ff6c135a90..da63abd836 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json @@ -57,6 +57,18 @@ "LastCachedTime": "Čas uložení v mezipaměti", "Project": "Projekt", "AdvancedFilters": "Pokročilé filtry", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bude odstraněn z mezipaměti a znovu zaindexován. Potvrzujete to?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bude odstraněn z mezipaměti a znovu zaindexován. Potvrzujete to?", + "GeneratePdf": "Generovat PDF", + "Generating": "Generování...", + "Language": "Jazyk", + "ForceToGenerateNewPdf": "Vynutit generování nového PDF", + "PdfGeneratedSuccessfully": "PDF generován úspěšně", + "GenerateAndDownloadPdf": "Generovat a stáhnout PDF", + "PdfFileDeletionWarningMessage": "Opravdu chcete odstranit soubor PDF \"{0}\"?", + "ManagePdfFiles": "Správa PDF souborů", + "Permission:ManagePdfFiles": "Správa PDF souborů", + "PdfDeletedSuccessfully": "PDF soubor byl úspěšně smazán", + "PdfGenerationStarted": "Generování PDF bylo zahájeno", + "PdfGenerationStartedInfoMessage": "Generování PDF bylo zahájeno. Po dokončení můžete zkontrolovat, zda byl soubor přidán do sekce PDF souborů." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json index ce7c8cafb0..dcbc32e310 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json @@ -56,6 +56,18 @@ "FileName": "Dateiname", "LastCachedTime": "Cache-Zeit", "Project": "Projekt", - "RemoveCacheAndReIndexConfirmation": "Das Dokument \"{0}\" wird aus dem Cache entfernt und neu indiziert. Können Sie das bestätigen?" + "RemoveCacheAndReIndexConfirmation": "Das Dokument \"{0}\" wird aus dem Cache entfernt und neu indiziert. Können Sie das bestätigen?", + "GeneratePdf": "PDF generieren", + "Generating": "Generieren...", + "Language": "Sprache", + "ForceToGenerateNewPdf": "Neues PDF erzwingen", + "PdfGeneratedSuccessfully": "PDF erfolgreich generiert", + "GenerateAndDownloadPdf": "PDF generieren und herunterladen", + "PdfFileDeletionWarningMessage": "Sind Sie sicher, dass Sie das PDF-Datei \"{0}\" löschen wollen?", + "ManagePdfFiles": "PDF-Dateien verwalten", + "Permission:ManagePdfFiles": "PDF-Dateien verwalten", + "PdfDeletedSuccessfully": "PDF-Datei wurde erfolgreich gelöscht", + "PdfGenerationStarted": "PDF-Generierung wurde gestartet", + "PdfGenerationStartedInfoMessage": "Die PDF-Generierung wurde gestartet. Nach Abschluss können Sie überprüfen, ob die Datei im PDF-Dateibereich hinzugefügt wurde." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json index 0fd1c535b2..972553c8ab 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json @@ -57,6 +57,18 @@ "LastCachedTime": "Zwischenspeicher", "Project": "Projekt", "AdvancedFilters": "Erweiterte Filter", - "RemoveCacheAndReIndexConfirmation": "Das Dokument „{0}“ wird aus dem Cache entfernt und neu indiziert. Bestätigen Sie?" + "RemoveCacheAndReIndexConfirmation": "Das Dokument „{0}“ wird aus dem Cache entfernt und neu indiziert. Bestätigen Sie?", + "GeneratePdf": "PDF generieren", + "Generating": "Generieren...", + "Language": "Sprache", + "ForceToGenerateNewPdf": "Neues PDF erzwingen", + "PdfGeneratedSuccessfully": "PDF erfolgreich generiert", + "GenerateAndDownloadPdf": "PDF generieren und herunterladen", + "PdfFileDeletionWarningMessage": "Sind Sie sicher, dass Sie das PDF-Datei \"{0}\" löschen wollen?", + "ManagePdfFiles": "PDF-Dateien verwalten", + "Permission:ManagePdfFiles": "PDF-Dateien verwalten", + "PdfDeletedSuccessfully": "PDF-Datei wurde erfolgreich gelöscht", + "PdfGenerationStarted": "PDF-Generierung gestartet", + "PdfGenerationStartedInfoMessage": "Die PDF-Generierung wurde gestartet. Nach Abschluss können Sie überprüfen, ob die Datei im PDF-Dateibereich hinzugefügt wurde." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json index c2a3f69a53..d4142c99ad 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json @@ -1,7 +1,7 @@ { "culture": "el", "texts": { - "Permission:DocumentManagement": "Διαχείρηση αρχείων", + "Permission:DocumentManagement": "Διαχείριση εγγράφων", "Permission:Projects": "Εργα", "Permission:Edit": "Επεξεργασία", "Permission:Delete": "Διαγραφή", @@ -56,6 +56,18 @@ "FileName": "Όνομα αρχείου", "LastCachedTime": "Χρόνος προσωρινής αποθήκευσης", "Project": "Εργο", - "RemoveCacheAndReIndexConfirmation": "Το έγγραφο \"{0}\" θα αφαιρεθεί από την προσωρινή μνήμη και θα αναπροσαρμοστεί εκ νέου. Επιβεβαιώνετε;" + "RemoveCacheAndReIndexConfirmation": "Το έγγραφο \"{0}\" θα αφαιρεθεί από την προσωρινή μνήμη και θα αναπροσαρμοστεί εκ νέου. Επιβεβαιώνετε;", + "GeneratePdf": "Δημιουργία PDF", + "Generating": "Δημιουργία...", + "Language": "Γλώσσα", + "ForceToGenerateNewPdf": "Βάλτε το νέο PDF", + "PdfGeneratedSuccessfully": "Το PDF αναπροσαρμοστεί εκ νέου", + "GenerateAndDownloadPdf": "Δημιουργία και λήψη PDF", + "PdfFileDeletionWarningMessage": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το PDF αρχείο \"{0}\";", + "ManagePdfFiles": "Διαχείρηση PDF αρχείων", + "Permission:ManagePdfFiles": "Διαχείρηση PDF αρχείων", + "PdfDeletedSuccessfully": "Το αρχείο PDF διαγράφηκε με επιτυχία", + "PdfGenerationStarted": "Η δημιουργία PDF ξεκίνησε", + "PdfGenerationStartedInfoMessage": "Η δημιουργία PDF ξεκίνησε. Μόλις ολοκληρωθεί, μπορείτε να ελέγξετε αν το αρχείο έχει προστεθεί στην ενότητα αρχείων PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json index d72c523ef5..2ccbdcf18a 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json @@ -56,6 +56,18 @@ "FileName": "File name", "LastCachedTime": "Cache time", "Project": "Project", - "AdvancedFilters": "Advanced Filters" + "AdvancedFilters": "Advanced Filters", + "GeneratePdf": "Generate PDF", + "Generating": "Generating...", + "Language": "Language", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files", + "PdfDeletedSuccessfully": "PDF file has been deleted successfully", + "PdfGenerationStarted": "PDF generation has started", + "PdfGenerationStartedInfoMessage": "PDF generation has started. Once completed, you can check if the file has been added to the PDF files section." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json index 5302cdcffb..0710e96f2b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json @@ -57,6 +57,18 @@ "LastCachedTime": "Cache time", "Project": "Project", "AdvancedFilters": "Advanced Filters", - "RemoveCacheAndReIndexConfirmation": "The document \"{0}\" will be removed from the cache and re-indexed. Do you confirm?" + "RemoveCacheAndReIndexConfirmation": "The document \"{0}\" will be removed from the cache and re-indexed. Do you confirm?", + "GeneratePdf": "Generate PDF", + "Generating": "Generating...", + "Language": "Language", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files", + "PdfDeletedSuccessfully": "PDF file has been deleted successfully", + "PdfGenerationStarted": "PDF generation started", + "PdfGenerationStartedInfoMessage": "PDF generation has started. Once completed, you can check if the file has been added to the PDF files section." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json index 911fe2745a..9be8d72207 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json @@ -57,6 +57,18 @@ "LastCachedTime": "Última actualización de caché", "Project": "Proyecto", "AdvancedFilters": "Filtros avanzados", - "RemoveCacheAndReIndexConfirmation": "El documento \"{0}\" será eliminado de la caché y reindexado. ¿Lo confirma?" + "RemoveCacheAndReIndexConfirmation": "El documento \"{0}\" será eliminado de la caché y reindexado. ¿Lo confirma?", + "GeneratePdf": "Generar PDF", + "Generating": "Generando...", + "Language": "Idioma", + "ForceToGenerateNewPdf": "Forzar a generar un nuevo PDF", + "PdfGeneratedSuccessfully": "PDF generado correctamente", + "GenerateAndDownloadPdf": "Generar y descargar PDF", + "PdfFileDeletionWarningMessage": "¿Está seguro de querer eliminar el archivo PDF \"{0}\"?", + "ManagePdfFiles": "Administrar archivos PDF", + "Permission:ManagePdfFiles": "Administrar archivos PDF", + "PdfDeletedSuccessfully": "El archivo PDF se ha eliminado correctamente", + "PdfGenerationStarted": "Se inició la generación de PDF", + "PdfGenerationStartedInfoMessage": "La generación del PDF ha comenzado. Una vez completado, puede verificar si el archivo se ha agregado en la sección de archivos PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json index e3e826c1b7..9393234a44 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json @@ -1,7 +1,7 @@ { "culture": "fi", "texts": { - "Permission:DocumentManagement": "Asiakirjojen hallinta", + "Permission:DocumentManagement": "Asiakirjahallinta", "Permission:Projects": "Projektit", "Permission:Edit": "Muokkaus", "Permission:Delete": "Poisto", @@ -57,6 +57,18 @@ "LastCachedTime": "Välimuistin aika", "Project": "Projekti", "AdvancedFilters": "Edistyneet suodattimet", - "RemoveCacheAndReIndexConfirmation": "Dokumentti \"{0}\" poistetaan välimuistista ja indeksoidaan uudelleen. Vahvistatko?" + "RemoveCacheAndReIndexConfirmation": "Dokumentti \"{0}\" poistetaan välimuistista ja indeksoidaan uudelleen. Vahvistatko?", + "GeneratePdf": "Generoi PDF", + "Generating": "Generoiminen...", + "Language": "Kieli", + "ForceToGenerateNewPdf": "Vahvista uusi PDF", + "PdfGeneratedSuccessfully": "PDF generoidaan onnistuneesti", + "GenerateAndDownloadPdf": "Generoi ja lataa PDF", + "PdfFileDeletionWarningMessage": "Oletko varma, että haluat poistaa PDF-tiedoston \"{0}\"?", + "ManagePdfFiles": "Hallitse PDF-tiedostoja", + "Permission:ManagePdfFiles": "Hallitse PDF-tiedostoja", + "PdfDeletedSuccessfully": "PDF-tiedosto poistettu onnistuneesti", + "PdfGenerationStarted": "PDF:n luonti on aloitettu", + "PdfGenerationStartedInfoMessage": "PDF:n luonti on aloitettu. Kun se on valmis, voit tarkistaa, onko tiedosto lisätty PDF-tiedostot-osioon." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json index b2fdef8201..3e7affcaf7 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json @@ -1,7 +1,7 @@ { "culture": "fr", "texts": { - "Permission:DocumentManagement": "Gestion de documents", + "Permission:DocumentManagement": "Gestion des documents", "Permission:Projects": "Projets", "Permission:Edit": "Éditer", "Permission:Delete": "Effacer", @@ -57,6 +57,18 @@ "LastCachedTime": "Temps de cache", "Project": "Projet", "AdvancedFilters": "Filtres avancés", - "RemoveCacheAndReIndexConfirmation": "Le document \"{0}\" sera supprimé du cache et réindexé. Confirmez-vous ?" + "RemoveCacheAndReIndexConfirmation": "Le document \"{0}\" sera supprimé du cache et réindexé. Confirmez-vous ?", + "GeneratePdf": "Générer PDF", + "Generating": "Génération...", + "Language": "Langue", + "ForceToGenerateNewPdf": "Forcer à générer un nouveau PDF", + "PdfGeneratedSuccessfully": "PDF généré avec succès", + "GenerateAndDownloadPdf": "Générer et télécharger PDF", + "PdfFileDeletionWarningMessage": "Êtes-vous sûr de vouloir supprimer le fichier PDF \"{0}\"?", + "ManagePdfFiles": "Gérer les fichiers PDF", + "Permission:ManagePdfFiles": "Gérer les fichiers PDF", + "PdfDeletedSuccessfully": "Le fichier PDF a été supprimé avec succès", + "PdfGenerationStarted": "La génération du PDF a commencé", + "PdfGenerationStartedInfoMessage": "La génération du PDF a commencé. Une fois terminé, vous pouvez vérifier si le fichier a été ajouté dans la section des fichiers PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json index adad5e064f..75e43a2bde 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json @@ -57,6 +57,18 @@ "LastCachedTime": "कैश समय", "Project": "परियोजना", "AdvancedFilters": "उन्नत फ़िल्टर", - "RemoveCacheAndReIndexConfirmation": "दस्u200Dतावेज़ \"{0}\" को संचय से हटा दिया जाएगा और पुन: अनुक्रमित किया जाएगा। क्या आप पुष्टि करते हैं?" + "RemoveCacheAndReIndexConfirmation": "दस्तावेज़ \"{0}\" को संचय से हटा दिया जाएगा और पुन: अनुक्रमित किया जाएगा। क्या आप पुष्टि करते हैं?", + "GeneratePdf": "PDF उत्पन्न करें", + "Generating": "उत्पन्न कर रहा है...", + "Language": "भाषा", + "ForceToGenerateNewPdf": "नया PDF उत्पन्न करें", + "PdfGeneratedSuccessfully": "PDF सफलतापूर्वक उत्पन्न हो गया", + "GenerateAndDownloadPdf": "PDF उत्पन्न और डाउनलोड करें", + "PdfFileDeletionWarningMessage": "क्या आप वाकई \"{0}\" के PDF फ़ाइल को हटाना चाहते हैं?", + "ManagePdfFiles": "PDF फ़ाइलें प्रबंधित करें", + "Permission:ManagePdfFiles": "PDF फ़ाइलें प्रबंधित करें", + "PdfDeletedSuccessfully": "PDF फ़ाइल सफलतापूर्वक हटा दी गई", + "PdfGenerationStarted": "PDF जनरेशन शुरू हो गया है", + "PdfGenerationStartedInfoMessage": "PDF जनरेशन शुरू हो गया है। पूरा होने के बाद, आप जांच सकते हैं कि फ़ाइल PDF फ़ाइल सेक्शन में जोड़ी गई है या नहीं।" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json index cf0a31368f..b58648d7c5 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hr.json @@ -57,6 +57,18 @@ "LastCachedTime": "Vrijeme predmemorije", "Project": "Projekt", "AdvancedFilters": "Napredni filtri", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bit će uklonjen iz predmemorije i ponovno indeksiran. Potvrđujete li?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bit će uklonjen iz predmemorije i ponovno indeksiran. Potvrđujete li?", + "GeneratePdf": "Generiraj PDF", + "Generating": "Generiranje...", + "Language": "Jezik", + "ForceToGenerateNewPdf": "Prisili generiranje novog PDF-a", + "PdfGeneratedSuccessfully": "PDF generiran uspješno", + "GenerateAndDownloadPdf": "Generiraj i preuzmi PDF", + "PdfFileDeletionWarningMessage": "Jeste li sigurni da želite izbrisati PDF datoteku \"{0}\"?", + "ManagePdfFiles": "Upravljanje PDF datotekama", + "Permission:ManagePdfFiles": "Upravljanje PDF datotekama", + "PdfDeletedSuccessfully": "PDF datoteka je uspješno izbrisana", + "PdfGenerationStarted": "Započelo je generiranje PDF-a", + "PdfGenerationStartedInfoMessage": "Započelo je generiranje PDF-a. Nakon završetka možete provjeriti je li datoteka dodana u odjeljak PDF datoteka." } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json index 587f67e72c..581910f9e9 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json @@ -58,6 +58,15 @@ "LastCachedTime": "Cache idő", "Project": "Projekt", "AdvancedFilters": "Speciális szűrők", - "RemoveCacheAndReIndexConfirmation": "A \"{0}\" dokumentumot eltávolítjuk a gyorsítótárból és újraindexeljük. Megerősíti?" + "RemoveCacheAndReIndexConfirmation": "A \"{0}\" dokumentumot eltávolítjuk a gyorsítótárból és újraindexeljük. Megerősíti?", + "GeneratePdf": "PDF generálása", + "Generating": "Generálás...", + "Language": "Nyelv", + "ForceToGenerateNewPdf": "Új PDF generálása", + "PdfGeneratedSuccessfully": "PDF generálás sikeres", + "GenerateAndDownloadPdf": "Generálás és letöltés PDF-ben", + "PdfFileDeletionWarningMessage": "Biztosan törölni szeretné a \"{0}\" PDF fájlt?", + "ManagePdfFiles": "PDF fájlok kezelése", + "Permission:ManagePdfFiles": "PDF fájlok kezelése" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json index c3e8fa957b..e262069bf7 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json @@ -57,6 +57,18 @@ "LastCachedTime": "Tími geymt í skyndiminni", "Project": "Verkefni", "AdvancedFilters": "Ítarlegar síur", - "RemoveCacheAndReIndexConfirmation": "Skjalið \"{0}\" verður fjarlægt úr skyndiminni og endurtryggt. Staðfestir þú?" + "RemoveCacheAndReIndexConfirmation": "Skjalið \"{0}\" verður fjarlægt úr skyndiminni og endurtryggt. Staðfestir þú?", + "GeneratePdf": "Generate PDF", + "Generating": "Generating...", + "Language": "Language", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files", + "PdfDeletedSuccessfully": "PDF skrá var eytt með góðum árangri", + "PdfGenerationStarted": "PDF gerð hefur hafist", + "PdfGenerationStartedInfoMessage": "PDF gerð hefur hafist. Þegar henni er lokið geturðu athugað hvort skráin hafi verið bætt við í PDF skráarhlutanum." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json index 40f94e8077..f253db8eb0 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json @@ -57,6 +57,18 @@ "LastCachedTime": "Tempo di cache", "Project": "Progetto", "AdvancedFilters": "Filtri avanzati", - "RemoveCacheAndReIndexConfirmation": "Il documento \"{0}\" verrà rimosso dalla cache e reindicizzato. Confermate?" + "RemoveCacheAndReIndexConfirmation": "Il documento \"{0}\" verrà rimosso dalla cache e reindicizzato. Confermate?", + "GeneratePdf": "Genera PDF", + "Generating": "Generazione...", + "Language": "Lingua", + "ForceToGenerateNewPdf": "Forza a generare un nuovo PDF", + "PdfGeneratedSuccessfully": "PDF generato con successo", + "GenerateAndDownloadPdf": "Genera e scarica PDF", + "PdfFileDeletionWarningMessage": "Sei sicuro di voler eliminare il file PDF \"{0}\"?", + "ManagePdfFiles": "Gestione file PDF", + "Permission:ManagePdfFiles": "Gestione file PDF", + "PdfDeletedSuccessfully": "Il file PDF è stato eliminato con successo", + "PdfGenerationStarted": "La generazione del PDF è iniziata", + "PdfGenerationStartedInfoMessage": "La generazione del PDF è iniziata. Al termine, puoi verificare se il file è stato aggiunto nella sezione dei file PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json index 201d7c5da0..377d0e3b84 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json @@ -57,6 +57,18 @@ "LastCachedTime": "Cache tijd", "Project": "Project", "AdvancedFilters": "Geavanceerde filters", - "RemoveCacheAndReIndexConfirmation": "Het document \"{0}\" wordt uit de cache verwijderd en opnieuw geïndexeerd. Bevestigt u?" + "RemoveCacheAndReIndexConfirmation": "Het document \"{0}\" wordt uit de cache verwijderd en opnieuw geïndexeerd. Bevestigt u?", + "GeneratePdf": "PDF genereren", + "Generating": "Genereren...", + "Language": "Taal", + "ForceToGenerateNewPdf": "Forceer nieuwe PDF te genereren", + "PdfGeneratedSuccessfully": "PDF succesvol gegenereerd", + "GenerateAndDownloadPdf": "PDF genereren en downloaden", + "PdfFileDeletionWarningMessage": "Weet u zeker dat u het PDF-bestand \"{0}\" wilt verwijderen?", + "ManagePdfFiles": "PDF-bestanden beheren", + "Permission:ManagePdfFiles": "PDF-bestanden beheren", + "PdfDeletedSuccessfully": "PDF-bestand is succesvol verwijderd", + "PdfGenerationStarted": "PDF-generatie is gestart", + "PdfGenerationStartedInfoMessage": "PDF-generatie is gestart. Na voltooiing kunt u controleren of het bestand is toegevoegd in de PDF-bestandssectie." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json index ec9de0de07..d82a792077 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json @@ -1,7 +1,7 @@ { "culture": "pl-PL", "texts": { - "Permission:DocumentManagement": "Zarządzanie dokumentacją", + "Permission:DocumentManagement": "Zarządzanie dokumentami", "Permission:Projects": "Projekty", "Permission:Edit": "Edytuj", "Permission:Delete": "Usuń", @@ -57,6 +57,18 @@ "LastCachedTime": "Czas w pamięci podręcznej", "Project": "Projekt", "AdvancedFilters": "Zaawansowane filtry", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" zostanie usunięty z pamięci podręcznej i ponownie zaindeksowany. Czy potwierdzasz?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" zostanie usunięty z pamięci podręcznej i ponownie zaindeksowany. Czy potwierdzasz?", + "GeneratePdf": "Generuj PDF", + "Generating": "Generowanie...", + "Language": "Język", + "ForceToGenerateNewPdf": "Wymuś generowanie nowego PDF", + "PdfGeneratedSuccessfully": "PDF został pomyślnie wygenerowany", + "GenerateAndDownloadPdf": "Generuj i pobierz PDF", + "PdfFileDeletionWarningMessage": "Czy na pewno chcesz usunąć plik PDF \"{0}\"?", + "ManagePdfFiles": "Zarządzanie plikami PDF", + "Permission:ManagePdfFiles": "Zarządzaj plikami PDF", + "PdfDeletedSuccessfully": "Plik PDF został pomyślnie usunięty", + "PdfGenerationStarted": "Rozpoczęto generowanie PDF", + "PdfGenerationStartedInfoMessage": "Rozpoczęto generowanie PDF. Po zakończeniu możesz sprawdzić, czy plik został dodany w sekcji plików PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json index b34ab4b9ef..b1e0810dee 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json @@ -1,7 +1,7 @@ { "culture": "pt-BR", "texts": { - "Permission:DocumentManagement": "Gerenciar Documentos", + "Permission:DocumentManagement": "Gerenciamento de documentos", "Permission:Projects": "Projetos", "Permission:Edit": "Editar", "Permission:Delete": "Excluir", @@ -57,6 +57,18 @@ "LastCachedTime": "Tempo de cache", "Project": "Projeto", "AdvancedFilters": "Filtros Avançados", - "RemoveCacheAndReIndexConfirmation": "O documento \"{0}\" será removido do cache e indexado novamente. Você confirma?" + "RemoveCacheAndReIndexConfirmation": "O documento \"{0}\" será removido do cache e indexado novamente. Você confirma?", + "GeneratePdf": "Gerar PDF", + "Generating": "Gerando...", + "Language": "Idioma", + "ForceToGenerateNewPdf": "Forçar para gerar um novo PDF", + "PdfGeneratedSuccessfully": "PDF gerado com sucesso", + "GenerateAndDownloadPdf": "Gerar e baixar PDF", + "PdfFileDeletionWarningMessage": "Tem certeza de que deseja excluir o arquivo PDF \"{0}\"?", + "ManagePdfFiles": "Gerenciar arquivos PDF", + "Permission:ManagePdfFiles": "Gerenciar arquivos PDF", + "PdfDeletedSuccessfully": "Arquivo PDF foi excluído com sucesso", + "PdfGenerationStarted": "A geração do PDF foi iniciada", + "PdfGenerationStartedInfoMessage": "A geração do PDF foi iniciada. Após a conclusão, você pode verificar se o arquivo foi adicionado na seção de arquivos PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json index f055110a2f..2da365c7c5 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json @@ -1,7 +1,7 @@ { "culture": "ro-RO", "texts": { - "Permission:DocumentManagement": "Administrarea documentelor", + "Permission:DocumentManagement": "Gestionare documente", "Permission:Projects": "Proiecte", "Permission:Edit": "Editează", "Permission:Delete": "Şterge", @@ -57,6 +57,18 @@ "LastCachedTime": "Durată cache", "Project": "Proiect", "AdvancedFilters": "Filtre avansate", - "RemoveCacheAndReIndexConfirmation": "Documentul \"{0}\" va fi eliminat din memoria cache și va fi reindexat. Confirmați?" + "RemoveCacheAndReIndexConfirmation": "Documentul \"{0}\" va fi eliminat din memoria cache și va fi reindexat. Confirmați?", + "GeneratePdf": "Generare PDF", + "Generating": "Generare...", + "Language": "Limba", + "ForceToGenerateNewPdf": "Forțați generarea unui nou PDF", + "PdfGeneratedSuccessfully": "PDF generat cu succes", + "GenerateAndDownloadPdf": "Generare și descărcare PDF", + "PdfFileDeletionWarningMessage": "Sunteți sigur(ă) că doriți să ștergeți fișierul PDF \"{0}\"?", + "ManagePdfFiles": "Gestionare fișiere PDF", + "Permission:ManagePdfFiles": "Gestionare fișiere PDF", + "PdfDeletedSuccessfully": "Fișierul PDF a fost șters cu succes", + "PdfGenerationStarted": "Generarea PDF-ului a început", + "PdfGenerationStartedInfoMessage": "Generarea PDF-ului a început. După finalizare, puteți verifica dacă fișierul a fost adăugat în secțiunea de fișiere PDF." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json index 5f9836d957..5f05e906bc 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json @@ -1,7 +1,7 @@ { "culture": "ru", "texts": { - "Permission:DocumentManagement": "Управление документацией", + "Permission:DocumentManagement": "Управление документами", "Permission:Projects": "Проекты", "Permission:Edit": "Редактировать", "Permission:Delete": "Удалить", @@ -57,6 +57,18 @@ "LastCachedTime": "Время кеширования", "Project": "Проект", "AdvancedFilters": "Расширенные фильтры", - "RemoveCacheAndReIndexConfirmation": "Документ \"{0}\" будет удален из кэша и переиндексирован. Вы подтверждаете?" + "RemoveCacheAndReIndexConfirmation": "Документ \"{0}\" будет удален из кэша и переиндексирован. Вы подтверждаете?", + "GeneratePdf": "Генерировать PDF", + "Generating": "Генерация...", + "Language": "Язык", + "ForceToGenerateNewPdf": "Принудительное создание нового PDF", + "PdfGeneratedSuccessfully": "PDF успешно сгенерирован", + "GenerateAndDownloadPdf": "Сгенерировать и скачать PDF", + "PdfFileDeletionWarningMessage": "Вы уверены, что хотите удалить файл PDF \"{0}\"?", + "ManagePdfFiles": "Управление PDF файлами", + "Permission:ManagePdfFiles": "Управление PDF файлами", + "PdfDeletedSuccessfully": "PDF файл успешно удален", + "PdfGenerationStarted": "Началась генерация PDF", + "PdfGenerationStartedInfoMessage": "Началась генерация PDF. После завершения вы можете проверить, добавлен ли файл в раздел PDF файлов." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json index 53578e22dd..8ba521bb71 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json @@ -57,6 +57,18 @@ "LastCachedTime": "Čas vyrovnávacej pamäte", "Project": "Projekt", "AdvancedFilters": "Pokročilé filtre", - "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" sa odstráni z vyrovnávacej pamäte a znovu sa zaindexuje. Potvrdzujete?" + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" sa odstráni z vyrovnávacej pamäte a znovu sa zaindexuje. Potvrdzujete?", + "GeneratePdf": "Generovať PDF", + "Generating": "Generovanie...", + "Language": "Jazyk", + "ForceToGenerateNewPdf": "Vynútiť generovanie nového PDF", + "PdfGeneratedSuccessfully": "PDF generovaný úspešne", + "GenerateAndDownloadPdf": "Generovať a stiahnuť PDF", + "PdfFileDeletionWarningMessage": "Ste si istý, že chcete odstrániť súbor PDF \"{0}\"?", + "ManagePdfFiles": "Správa PDF súborov", + "Permission:ManagePdfFiles": "Správa PDF súborov", + "PdfDeletedSuccessfully": "PDF súbor bol úspešne odstránený", + "PdfGenerationStarted": "Začala sa generácia PDF", + "PdfGenerationStartedInfoMessage": "Začala sa generácia PDF. Po dokončení môžete skontrolovať, či bol súbor pridaný v sekcii PDF súborov." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json index 3bcfcd4e85..dbf648bed2 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json @@ -57,6 +57,18 @@ "LastCachedTime": "Čas pred pomnilnika", "Project": "Projekt", "AdvancedFilters": "Napredni filtri", - "RemoveCacheAndReIndexConfirmation": "Dokument »{0}« bo odstranjen iz predpomnilnika in ponovno indeksiran. Ali potrjuješ?" + "RemoveCacheAndReIndexConfirmation": "Dokument »{0}« bo odstranjen iz predpomnilnika in ponovno indeksiran. Ali potrjuješ?", + "GeneratePdf": "Generiraj PDF", + "Generating": "Generiranje...", + "Language": "Jezik", + "ForceToGenerateNewPdf": "Prisili generiranje novega PDF", + "PdfGeneratedSuccessfully": "PDF generiran uspešno", + "GenerateAndDownloadPdf": "Generiraj in prenesi PDF", + "PdfFileDeletionWarningMessage": "Ali ste prepričani, da želite izbrisati datoteko PDF »{0}«?", + "ManagePdfFiles": "Upravljanje datotek PDF", + "Permission:ManagePdfFiles": "Upravljanje datotek PDF", + "PdfDeletedSuccessfully": "PDF datoteka je bila uspešno izbrisana", + "PdfGenerationStarted": "Začelo se je ustvarjanje PDF-ja", + "PdfGenerationStartedInfoMessage": "Začelo se je ustvarjanje PDF-ja. Ko bo končano, lahko preverite, ali je bila datoteka dodana v razdelek PDF datotek." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json index cbde97c756..08571922d8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sv.json @@ -57,6 +57,18 @@ "LastCachedTime": "Cache-tid", "Project": "Projekt", "AdvancedFilters": "Avancerade filter", - "RemoveCacheAndReIndexConfirmation": "Dokumentet \"{0}\" kommer att tas bort från cacheminnet och indexeras på nytt. Kan du bekräfta detta?" + "RemoveCacheAndReIndexConfirmation": "Dokumentet \"{0}\" kommer att tas bort från cacheminnet och indexeras på nytt. Kan du bekräfta detta?", + "GeneratePdf": "Generera PDF", + "Generating": "Genererar...", + "Language": "Språk", + "ForceToGenerateNewPdf": "Force to generate new PDF", + "PdfGeneratedSuccessfully": "PDF generated successfully", + "GenerateAndDownloadPdf": "Generate and download PDF", + "PdfFileDeletionWarningMessage": "Are you sure you want to delete the PDF file \"{0}\"?", + "ManagePdfFiles": "Manage PDF files", + "Permission:ManagePdfFiles": "Manage PDF files", + "PdfDeletedSuccessfully": "PDF-filen har tagits bort", + "PdfGenerationStarted": "PDF-generering har påbörjats", + "PdfGenerationStartedInfoMessage": "PDF-generering har påbörjats. När den är klar kan du kontrollera om filen har lagts till i PDF-filsektionen." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json index ab600c1db5..6f2989cf2c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -1,7 +1,7 @@ { "culture": "tr", "texts": { - "Permission:DocumentManagement": "Döküman yönetimi", + "Permission:DocumentManagement": "Belge Yönetimi", "Permission:Projects": "Projeler", "Permission:Edit": "Düzenle", "Permission:Delete": "Sil", @@ -57,6 +57,18 @@ "LastCachedTime": "Önbellek süresi", "Project": "Proje", "AdvancedFilters": "Gelişmiş Filtre", - "RemoveCacheAndReIndexConfirmation": "\"{0}\" belgesi önbellekten kaldırılacak ve yeniden indekslenecektir. Onaylıyor musunuz?" + "RemoveCacheAndReIndexConfirmation": "\"{0}\" belgesi önbellekten kaldırılacak ve yeniden indekslenecektir. Onaylıyor musunuz?", + "GeneratePdf": "PDF oluştur", + "Generating": "Oluşturuluyor...", + "Language": "Dil", + "ForceToGenerateNewPdf": "Yeni bir PDF oluştur", + "PdfGeneratedSuccessfully": "PDF başarıyla oluşturuldu", + "GenerateAndDownloadPdf": "PDF oluştur ve indir", + "PdfFileDeletionWarningMessage": "{0} PDF dosyasını silmek istediğinizden emin misiniz?", + "ManagePdfFiles": "PDF dosyalarını yönet", + "Permission:ManagePdfFiles": "PDF dosyalarını yönet", + "PdfDeletedSuccessfully": "PDF dosyası başarıyla silindi", + "PdfGenerationStarted": "PDF oluşturma başladı", + "PdfGenerationStartedInfoMessage": "PDF oluşturma işlemi başlatıldı. İşlem tamamlandığında, dosyanın PDF dosyaları bölümüne eklenip eklenmediğini kontrol edebilirsiniz." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json index 9b47a049a9..1b716f20f2 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json @@ -57,6 +57,18 @@ "LastCachedTime": "Thời gian lưu vào bộ nhớ đệm", "Project": "Dự án", "AdvancedFilters": "Bộ lọc nâng cao", - "RemoveCacheAndReIndexConfirmation": "Tài liệu "{0}" sẽ bị xóa khỏi bộ đệm và được lập chỉ mục lại. Bạn có xác nhận không?" + "RemoveCacheAndReIndexConfirmation": "Tài liệu "{0}" sẽ bị xóa khỏi bộ đệm và được lập chỉ mục lại. Bạn có xác nhận không?", + "GeneratePdf": "Tạo PDF", + "Generating": "Đang tạo...", + "Language": "Ngôn ngữ", + "ForceToGenerateNewPdf": "Tạo PDF mới", + "PdfGeneratedSuccessfully": "PDF đã được tạo thành công", + "GenerateAndDownloadPdf": "Tạo và tải xuống PDF", + "PdfFileDeletionWarningMessage": "Bạn có chắc chắn muốn xóa tệp PDF \"{0}\" không?", + "ManagePdfFiles": "Quản lý tệp PDF", + "Permission:ManagePdfFiles": "Quản lý tệp PDF", + "PdfDeletedSuccessfully": "Tệp PDF đã được xóa thành công", + "PdfGenerationStarted": "Bắt đầu tạo PDF", + "PdfGenerationStartedInfoMessage": "Quá trình tạo PDF đã bắt đầu. Sau khi hoàn thành, bạn có thể kiểm tra xem tệp đã được thêm vào phần tệp PDF chưa." } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json index e5bb9f15b6..a7af969a12 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json @@ -57,6 +57,18 @@ "LastCachedTime": "缓存项", "Project": "项目", "AdvancedFilters": "高级过滤器", - "RemoveCacheAndReIndexConfirmation": "文档“{0}”将从缓存中删除并重新编制索引。 你确认吗?" + "RemoveCacheAndReIndexConfirmation": "文档“{0}”将从缓存中删除并重新编制索引。 你确认吗?", + "GeneratePdf": "生成PDF", + "Generating": "生成中...", + "Language": "语言", + "ForceToGenerateNewPdf": "强制生成新PDF", + "PdfGeneratedSuccessfully": "PDF生成成功", + "GenerateAndDownloadPdf": "生成并下载PDF", + "PdfFileDeletionWarningMessage": "你确定要删除PDF文件“{0}”吗?", + "ManagePdfFiles": "管理PDF文件", + "Permission:ManagePdfFiles": "管理PDF文件", + "PdfDeletedSuccessfully": "PDF文件已成功删除", + "PdfGenerationStarted": "PDF生成已开始", + "PdfGenerationStartedInfoMessage": "PDF生成已开始。完成后,您可以在PDF文件部分检查文件是否已添加。" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json index c246a74646..99cc9cec27 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -55,8 +55,20 @@ "LanguageCode": "語言代碼", "FileName": "文檔名稱", "LastCachedTime": "緩存時間", - "Project": "项目", + "Project": "專案", "AdvancedFilters": "進階過濾器", - "RemoveCacheAndReIndexConfirmation": "文檔“{0}”將從緩存中刪除並重新編制索引。 你確認嗎?" + "RemoveCacheAndReIndexConfirmation": "文檔“{0}”將從緩存中刪除並重新編制索引。 你確認嗎?", + "GeneratePdf": "生成PDF", + "Generating": "生成中...", + "Language": "語言", + "ForceToGenerateNewPdf": "强制生成新PDF", + "PdfGeneratedSuccessfully": "PDF生成成功", + "GenerateAndDownloadPdf": "生成并下载PDF", + "PdfFileDeletionWarningMessage": "你確定要刪除PDF文件“{0}”嗎?", + "ManagePdfFiles": "管理PDF文件", + "Permission:ManagePdfFiles": "管理PDF文件", + "PdfDeletedSuccessfully": "PDF文件已成功刪除", + "PdfGenerationStarted": "PDF生成已開始", + "PdfGenerationStartedInfoMessage": "PDF生成已開始。完成後,您可以在PDF文件部分檢查文件是否已添加。" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs new file mode 100644 index 0000000000..6e8e30e57c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/DeletePdfFileInput.cs @@ -0,0 +1,12 @@ +using System; + +namespace Volo.Docs.Admin.Projects; + +public class DeletePdfFileInput +{ + public Guid ProjectId { get; set; } + + public string Version { get; set; } + + public string LanguageCode { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs new file mode 100644 index 0000000000..f8a371dd57 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/GetPdfFilesInput.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Volo.Docs.Admin.Projects; + +public class GetPdfFilesInput : PagedAndSortedResultRequestDto +{ + public Guid ProjectId { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs new file mode 100644 index 0000000000..4f2d012475 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectPdfFileDto.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Docs.Admin.Projects; + +[Serializable] +public class ProjectPdfFileDto +{ + public virtual Guid ProjectId { get; set; } + public virtual string FileName { get; set; } + public virtual string Version { get; set; } + public virtual string LanguageCode { get; set; } + public virtual DateTime CreationTime { get; set; } + public virtual DateTime? LastModificationTime { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj b/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj index 3d947ead5e..725c70bc2b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo.Docs.Admin.Application.csproj @@ -12,10 +12,12 @@ + + diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/BackgroundJobs/DocumentPdfGenerateJob.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/BackgroundJobs/DocumentPdfGenerateJob.cs new file mode 100644 index 0000000000..2921039a91 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/BackgroundJobs/DocumentPdfGenerateJob.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Uow; +using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf; + +namespace Volo.Docs.Admin.BackgroundJobs; + +public class DocumentPdfGenerateJob : AsyncBackgroundJob, ITransientDependency +{ + protected IProjectPdfGenerator ProjectPdfGenerator { get; } + protected IProjectRepository ProjectRepository { get; } + + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + public DocumentPdfGenerateJob(IProjectPdfGenerator projectPdfGenerator, IProjectRepository projectRepository, IUnitOfWorkManager unitOfWorkManager) + { + ProjectPdfGenerator = projectPdfGenerator; + ProjectRepository = projectRepository; + UnitOfWorkManager = unitOfWorkManager; + } + + public async override Task ExecuteAsync(DocumentPdfGenerateJobArgs args) + { + try + { + Logger.LogInformation("Generating PDF for project {ProjectId}, version {Version}, language {LanguageCode}", args.ProjectId, args.Version, args.LanguageCode); + using var uow = UnitOfWorkManager.Begin(requiresNew: true); + var project = await ProjectRepository.GetAsync(args.ProjectId, includeDetails: true); + await ProjectPdfGenerator.GenerateAsync(project, args.Version, args.LanguageCode); + await uow.CompleteAsync(); + } + catch (Exception e) + { + Logger.LogError(e, "Error while generating PDF for project {ProjectId}, version {Version}, language {LanguageCode}", args.ProjectId, args.Version, args.LanguageCode); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/BackgroundJobs/DocumentPdfGenerateJobArgs.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/BackgroundJobs/DocumentPdfGenerateJobArgs.cs new file mode 100644 index 0000000000..ce8b734f2c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/BackgroundJobs/DocumentPdfGenerateJobArgs.cs @@ -0,0 +1,13 @@ +using System; +using Volo.Abp.BackgroundJobs; + +namespace Volo.Docs.Admin.BackgroundJobs; + +public class DocumentPdfGenerateJobArgs +{ + public Guid ProjectId { get; set; } + + public string Version { get; set; } + + public string LanguageCode { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs index 01a7250ce5..366c0ab27b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs @@ -16,6 +16,7 @@ namespace Volo.Docs.Admin CreateMap(); CreateMap(); CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs index 0b78c53973..2491bf5fb6 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationModule.cs @@ -3,15 +3,19 @@ using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Modularity; +using Volo.Docs.Common; +using Volo.Abp.BackgroundJobs; namespace Volo.Docs.Admin { [DependsOn( typeof(DocsDomainModule), typeof(DocsAdminApplicationContractsModule), + typeof(DocsCommonApplicationModule), typeof(AbpCachingModule), typeof(AbpAutoMapperModule), - typeof(AbpDddApplicationModule) + typeof(AbpDddApplicationModule), + typeof(AbpBackgroundJobsAbstractionsModule) )] public class DocsAdminApplicationModule : AbpModule { diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentPdfAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentPdfAdminAppService.cs new file mode 100644 index 0000000000..9d10d0d99a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentPdfAdminAppService.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Volo.Abp.Application.Dtos; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DistributedLocking; +using Volo.Docs.Admin.BackgroundJobs; +using Volo.Docs.Admin.Projects; +using Volo.Docs.Common.Documents; +using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf; + +namespace Volo.Docs.Admin.Documents; + +[Authorize(DocsAdminPermissions.Projects.ManagePdfFiles)] +public class DocumentPdfAdminAppService : DocumentPdfAppService, IDocumentPdfAdminAppService +{ + protected IBackgroundJobManager BackgroundJobManager { get; } + protected IAbpDistributedLock DistributedLock { get; } + + public DocumentPdfAdminAppService( + IProjectPdfGenerator projectPdfGenerator, + IProjectRepository projectRepository, + IProjectPdfFileStore projectPdfFileStore, + IOptions options, + IBackgroundJobManager backgroundJobManager, + IAbpDistributedLock distributedLock) : + base(projectPdfGenerator, projectRepository, projectPdfFileStore, options) + { + BackgroundJobManager = backgroundJobManager; + DistributedLock = distributedLock; + } + + public virtual async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + { + var project = await ProjectRepository.GetAsync(input.ProjectId, includeDetails: true); + await BackgroundJobManager.EnqueueAsync(new DocumentPdfGenerateJobArgs + { + Version = project.GetFullVersion(input.Version), + LanguageCode = input.LanguageCode, + ProjectId = input.ProjectId, + }); + } + + public virtual async Task> GetPdfFilesAsync(GetPdfFilesInput input) + { + var project = await ProjectRepository.GetAsync(input.ProjectId, includeDetails: true); + + var pdfFiles = project.PdfFiles.Skip(input.SkipCount).Take(input.MaxResultCount).ToList(); + + return new PagedResultDto( + project.PdfFiles.Count, + ObjectMapper.Map, List>(pdfFiles) + ); + } + + public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) + { + var project = await ProjectRepository.GetAsync(input.ProjectId, includeDetails: true); + await ProjectPdfFileStore.DeleteAsync(project, input.Version, input.LanguageCode); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs index 3142b821d2..af4ca2230b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Data; @@ -11,6 +12,7 @@ using Volo.Docs.Documents; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Docs.Localization; using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf; namespace Volo.Docs.Admin.Projects { @@ -21,12 +23,14 @@ namespace Volo.Docs.Admin.Projects private readonly IDocumentRepository _documentRepository; private readonly IDocumentFullSearch _elasticSearchService; private readonly IGuidGenerator _guidGenerator; + private readonly IProjectPdfFileStore _projectPdfFileStore; public ProjectAdminAppService( IProjectRepository projectRepository, IDocumentRepository documentRepository, IDocumentFullSearch elasticSearchService, - IGuidGenerator guidGenerator) + IGuidGenerator guidGenerator, + IProjectPdfFileStore projectPdfFileStore) { ObjectMapperContext = typeof(DocsAdminApplicationModule); LocalizationResource = typeof(DocsResource); @@ -35,6 +39,7 @@ namespace Volo.Docs.Admin.Projects _documentRepository = documentRepository; _elasticSearchService = elasticSearchService; _guidGenerator = guidGenerator; + _projectPdfFileStore = projectPdfFileStore; } public virtual async Task> GetListAsync(PagedAndSortedResultRequestDto input) diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/DocumentPdfAdminClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/DocumentPdfAdminClientProxy.Generated.cs new file mode 100644 index 0000000000..8c14d65460 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/DocumentPdfAdminClientProxy.Generated.cs @@ -0,0 +1,61 @@ +// This file is automatically generated by ABP framework to use MVC Controllers from CSharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Modeling; +using Volo.Docs.Admin.Projects; +using Volo.Docs.Common.Documents; + +// ReSharper disable once CheckNamespace +namespace Volo.Docs.Admin; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(IDocumentPdfAppService), typeof(DocumentPdfAdminClientProxy))] +public partial class DocumentPdfAdminClientProxy : ClientProxyBase, IDocumentPdfAppService +{ + public virtual async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + { + await RequestAsync(nameof(GeneratePdfAsync), new ClientProxyRequestTypeValue + { + { typeof(DocumentPdfGeneratorInput), input } + }); + } + + public virtual async Task> GetPdfFilesAsync(GetPdfFilesInput input) + { + return await RequestAsync>(nameof(GetPdfFilesAsync), new ClientProxyRequestTypeValue + { + { typeof(GetPdfFilesInput), input } + }); + } + + public virtual async Task DeletePdfFileAsync(DeletePdfFileInput input) + { + await RequestAsync(nameof(DeletePdfFileAsync), new ClientProxyRequestTypeValue + { + { typeof(DeletePdfFileInput), input } + }); + } + + public virtual async Task DownloadPdfAsync(DocumentPdfGeneratorInput input) + { + return await RequestAsync(nameof(DownloadPdfAsync), new ClientProxyRequestTypeValue + { + { typeof(DocumentPdfGeneratorInput), input } + }); + } + + public virtual async Task ExistsAsync(DocumentPdfGeneratorInput input) + { + return await RequestAsync(nameof(ExistsAsync), new ClientProxyRequestTypeValue + { + { typeof(DocumentPdfGeneratorInput), input } + }); + } +} diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/DocumentPdfAdminClientProxy.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/DocumentPdfAdminClientProxy.cs new file mode 100644 index 0000000000..a8d5f82116 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/DocumentPdfAdminClientProxy.cs @@ -0,0 +1,7 @@ +// This file is part of DocumentPdfAdminClientProxy, you can customize it here +// ReSharper disable once CheckNamespace +namespace Volo.Docs.Admin; + +public partial class DocumentPdfAdminClientProxy +{ +} diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/docs-admin-generate-proxy.json b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/docs-admin-generate-proxy.json index e433e06ef9..0b3e9f9445 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/docs-admin-generate-proxy.json +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/Volo/Docs/Admin/docs-admin-generate-proxy.json @@ -4,6 +4,466 @@ "rootPath": "docs-admin", "remoteServiceName": "AbpDocsAdmin", "controllers": { + "Volo.Docs.Admin.DocumentPdfAdminController": { + "controllerName": "DocumentPdfAdmin", + "controllerGroupName": "DocumentsPdfAdmin", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Admin.DocumentPdfAdminController", + "interfaces": [ + { + "type": "Volo.Docs.Admin.Documents.IDocumentPdfAdminAppService", + "name": "IDocumentPdfAdminAppService", + "methods": [ + { + "name": "GeneratePdfAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "GetPdfFilesAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.GetPdfFilesInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "typeSimple": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + } + }, + { + "name": "DeletePdfFileAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.DeletePdfFileInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "typeSimple": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "DownloadPdfAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + } + }, + { + "name": "ExistsAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Boolean", + "typeSimple": "boolean" + } + } + ] + }, + { + "type": "Volo.Docs.Common.Documents.IDocumentPdfAppService", + "name": "IDocumentPdfAppService", + "methods": [ + { + "name": "DownloadPdfAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + } + }, + { + "name": "ExistsAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Boolean", + "typeSimple": "boolean" + } + } + ] + } + ], + "actions": { + "GeneratePdfAsyncByInput": { + "uniqueName": "GeneratePdfAsyncByInput", + "name": "GeneratePdfAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/pdf/generate", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentPdfAdminAppService" + }, + "GetPdfFilesAsyncByInput": { + "uniqueName": "GetPdfFilesAsyncByInput", + "name": "GetPdfFilesAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/pdf/files", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.GetPdfFilesInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "typeSimple": "Volo.Docs.Admin.Projects.GetPdfFilesInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Sorting", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "SkipCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "MaxResultCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentPdfAdminAppService" + }, + "DeletePdfFileAsyncByInput": { + "uniqueName": "DeletePdfFileAsyncByInput", + "name": "DeletePdfFileAsync", + "httpMethod": "DELETE", + "url": "api/docs/admin/documents/pdf/delete-file", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Admin.Projects.DeletePdfFileInput, Volo.Docs.Admin.Application.Contracts", + "type": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "typeSimple": "Volo.Docs.Admin.Projects.DeletePdfFileInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentPdfAdminAppService" + }, + "DownloadPdfAsyncByInput": { + "uniqueName": "DownloadPdfAsyncByInput", + "name": "DownloadPdfAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/pdf/download", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Documents.IDocumentPdfAppService" + }, + "ExistsAsyncByInput": { + "uniqueName": "ExistsAsyncByInput", + "name": "ExistsAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/pdf/exists", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "System.Boolean", + "typeSimple": "boolean" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Documents.IDocumentPdfAppService" + } + } + }, "Volo.Docs.Admin.DocumentsAdminController": { "controllerName": "DocumentsAdmin", "controllerGroupName": "DocumentsAdmin", diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj index 6d718f03bb..25a0be0294 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo.Docs.Admin.HttpApi.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs index ed62f35e6f..ba7f1f7fbb 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocsAdminHttpApiModule.cs @@ -4,12 +4,14 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Docs.Localization; using Microsoft.Extensions.DependencyInjection; +using Volo.Docs.Common; namespace Volo.Docs.Admin { [DependsOn( typeof(DocsAdminApplicationContractsModule), - typeof(AbpAspNetCoreMvcModule) + typeof(AbpAspNetCoreMvcModule), + typeof(DocsCommonHttpApiModule) )] public class DocsAdminHttpApiModule : AbpModule { diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentPdfAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentPdfAdminController.cs new file mode 100644 index 0000000000..4cc49efc79 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentPdfAdminController.cs @@ -0,0 +1,60 @@ +using System.Threading.Tasks; +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Content; +using Volo.Docs.Admin.Documents; +using Volo.Docs.Admin.Projects; +using Volo.Docs.Common.Documents; + +namespace Volo.Docs.Admin; +[RemoteService(Name = DocsAdminRemoteServiceConsts.RemoteServiceName)] +[Area(DocsAdminRemoteServiceConsts.ModuleName)] +[ControllerName("DocumentsPdfAdmin")] +[Route("api/docs/admin/documents/pdf")] +public class DocumentPdfAdminController : AbpControllerBase, IDocumentPdfAdminAppService +{ + private readonly IDocumentPdfAdminAppService _documentPdfAdminAppService; + + public DocumentPdfAdminController(IDocumentPdfAdminAppService documentPdfAdminAppService) + { + _documentPdfAdminAppService = documentPdfAdminAppService; + } + + [HttpGet] + [Route("generate")] + public Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + { + return _documentPdfAdminAppService.GeneratePdfAsync(input); + } + + [HttpGet] + [Route("files")] + public Task> GetPdfFilesAsync(GetPdfFilesInput input) + { + return _documentPdfAdminAppService.GetPdfFilesAsync(input); + } + + [HttpDelete] + [Route("delete-file")] + public Task DeletePdfFileAsync(DeletePdfFileInput input) + { + return _documentPdfAdminAppService.DeletePdfFileAsync(input); + } + + [HttpGet] + [Route("download")] + public Task DownloadPdfAsync(DocumentPdfGeneratorInput input) + { + return _documentPdfAdminAppService.DownloadPdfAsync(input); + } + + [HttpGet] + [Route("exists")] + public Task ExistsAsync(DocumentPdfGeneratorInput input) + { + return _documentPdfAdminAppService.ExistsAsync(input); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml new file mode 100644 index 0000000000..64cb3d3b01 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml @@ -0,0 +1,41 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Docs.Admin.Pages.Docs.Admin.Projects; +@using Volo.Docs.Localization +@model GeneratePdfModal +@inject IHtmlLocalizer L +@{ + Layout = null; +} +
+ + + + + +
+ + +
+
+ + +
+
+ + + + +
+
\ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs new file mode 100644 index 0000000000..3396f3335c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/GeneratePdf.cshtml.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using Volo.Docs.Admin.Documents; +using Volo.Docs.Admin.Projects; +using Volo.Docs.Common.Documents; +using Volo.Docs.Common.Projects; +using Volo.Docs.Projects; + +namespace Volo.Docs.Admin.Pages.Docs.Admin.Projects; + +public class GeneratePdfModal : DocsAdminPageModel +{ + protected IProjectAppService ProjectAppService { get; } + protected IProjectAdminAppService ProjectAdminAppService { get; } + protected IDocumentPdfAdminAppService DocumentPdfAdminAppService { get; } + + public GeneratePdfViewModel ViewModel { get; set; } + + [BindProperty(SupportsGet = true)] + public Guid ProjectId { get; set; } + + [BindProperty(SupportsGet = true)] + public string Version { get; set; } + + [BindProperty(SupportsGet = true)] + public string Language { get; set; } + + public GeneratePdfModal( + IProjectAppService projectAppService, + IProjectAdminAppService projectAdminAppService, + IDocumentPdfAdminAppService documentPdfAdminAppService) + { + ProjectAppService = projectAppService; + ProjectAdminAppService = projectAdminAppService; + DocumentPdfAdminAppService = documentPdfAdminAppService; + } + + public virtual async Task OnGetAsync() + { + var project = await ProjectAdminAppService.GetAsync(ProjectId); + var versions = await ProjectAppService.GetVersionsAsync(project.ShortName); + if(versions.Items.Count == 0) + { + versions.Items = + [ + new VersionInfoDto { Name = ProjectConsts.Latest, DisplayName = ProjectConsts.Latest } + ]; + } + var languages = await ProjectAppService.GetLanguageListAsync(project.ShortName, versions.Items.FirstOrDefault()?.Name); + ViewModel = new GeneratePdfViewModel + { + ShortName = project.ShortName, + Versions = versions.Items.Select(x => new SelectListItem(x.DisplayName, x.Name)).ToList(), + Languages = languages.Languages.Select(x => new SelectListItem(x.DisplayName, x.Code)).ToList() + }; + + return Page(); + } + + public virtual async Task OnPostAsync() + { + await DocumentPdfAdminAppService.GeneratePdfAsync(new DocumentPdfGeneratorInput + { + ProjectId = ProjectId, + Version = Version, + LanguageCode = Language + }); + + return NoContent(); + } + + public class GeneratePdfViewModel + { + public string ShortName { get; set; } + public List Versions { get; set; } + public List Languages { get; set; } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml index 07582a45dd..1bdbf7467e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/Index.cshtml @@ -20,10 +20,13 @@ @section scripts { + + + } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml new file mode 100644 index 0000000000..895f876fe5 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml @@ -0,0 +1,41 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Docs.Localization +@model Volo.Docs.Admin.Pages.Docs.Admin.Projects.ManagePdfFiles +@inject IHtmlLocalizer L + +@{ + Layout = null; +} + + + + + + + + + + + + + + + + + @L["Actions"] + @L["FileName"] + @L["Version"] + @L["LanguageCode"] + @L["CreationTime"] + @L["LastUpdateTime"] + + + + + + + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs new file mode 100644 index 0000000000..bb5218419b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/ManagePdfFiles.cshtml.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Docs.Admin.Pages.Docs.Admin.Projects; + +[Authorize(DocsAdminPermissions.Projects.Default)] +public class ManagePdfFiles : DocsAdminPageModel +{ + public virtual Task OnGet() + { + return Task.FromResult(Page()); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js new file mode 100644 index 0000000000..42883088b8 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/generatePdf.js @@ -0,0 +1,27 @@ +var abp = abp || {}; +$(function () { + abp.modals.projectGeneratePdf = function () { + + var l = abp.localization.getResource('Docs'); + var projectAppService = volo.docs.projects.docsProject; + + var initModal = function (publicApi, args) { + + }; + + $("#Versions").change(function () { + var shortname = $("#ShortName").val(); + var version = $("#Version").val(); + projectAppService.getLanguageList(shortname, version).done(function (result) { + $("#Language").empty(); + $.each(result.languages, function (index, item) { + $("#Language").append($(``)); + }); + }); + }) + + return { + initModal: initModal, + }; + }; +}); diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js index cf11d50603..12ad8f2d95 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/index.js @@ -16,6 +16,11 @@ $(function () { modalClass: 'projectPull', }); + var _managePdfFilesModal = new abp.ModalManager({ + viewUrl: abp.appPath + 'Docs/Admin/Projects/ManagePdfFiles', + modalClass: 'projectManagePdfFiles', + }); + var _dataTable = $('#ProjectsTable').DataTable( abp.libs.datatables.normalizeConfiguration({ processing: true, @@ -117,6 +122,17 @@ $(function () { }); }, }, + { + text: l('ManagePdfFiles'), + visible: abp.auth.isGranted( + 'Docs.Admin.Projects.ManagePdfFiles' + ), + action: function (data) { + _managePdfFilesModal.open({ + projectId: data.record.id, + }); + } + } ], }, }, diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js new file mode 100644 index 0000000000..de71403878 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Projects/managePdfFiles.js @@ -0,0 +1,105 @@ +var abp = abp || {}; +$(function () { + abp.modals.projectManagePdfFiles = function () { + + var l = abp.localization.getResource('Docs'); + var documentPdfAdminAppService = volo.docs.admin.documentPdfAdmin; + + var _generatePdfModal = new abp.ModalManager({ + viewUrl: abp.appPath + 'Docs/Admin/Projects/GeneratePdf', + modalClass: 'projectGeneratePdf', + }); + + var initModal = function (publicApi, args) { + var _dataTable = $('#ProjectPdfFilesTable').DataTable( + abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + scrollX: true, + paging: true, + searching: false, + autoWidth: false, + scrollCollapse: true, + order: [[2, 'desc']], + ajax: abp.libs.datatables.createAjax( + documentPdfAdminAppService.getPdfFiles, + { + projectId : args.projectId + } + ), + columnDefs: [ + { + rowAction: { + items: [ + { + text: l('Delete'), + confirmMessage: function (data) { + return l('PdfFileDeletionWarningMessage', data.record.fileName); + }, + action: function (data) { + documentPdfAdminAppService.deletePdfFile({ + projectId: data.record.projectId, + version: data.record.version, + languageCode: data.record.languageCode + }).then(() => { + _dataTable.ajax.reloadEx(); + abp.notify.success(l('PdfDeletedSuccessfully')); + }) + }, + }, + { + text: l('Download'), + action: function (data) { + var url = abp.appPath + 'api/docs/admin/documents/pdf/download?projectId=' + data.record.projectId + '&version=' + data.record.version + '&languageCode=' + data.record.languageCode; + window.open(url, '_blank'); + }, + }, + ], + }, + }, + { + target: 1, + data: 'fileName', + }, + { + target: 2, + data: 'version', + }, + { + target: 3, + data: 'languageCode', + }, + { + target: 4, + data: `creationTime`, + dataFormat: "datetime" + }, + { + target: 5, + data: `lastModificationTime`, + dataFormat: "datetime" + } + ], + }) + ); + + $('#GeneratePdfBtn').click(function () { + _generatePdfModal.open({ + ProjectId: args.projectId, + }); + }); + + _generatePdfModal.onClose(function () { + _dataTable.ajax.reloadEx(); + }); + + _generatePdfModal.onResult(function (){ + abp.message.info(l('PdfGenerationStartedInfoMessage')); + }); + }; + + return { + initModal: initModal, + }; + }; +}); diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.abppkg b/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.abppkg index 4e12d28da1..1c2d273971 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.abppkg +++ b/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.abppkg @@ -6,7 +6,7 @@ "applicationName": "VoloDocs.Web", "module": "docs-admin", "url": "https://localhost:5001", - "output": "wwwroot/client-proxies", + "output": "wwwroot/client-proxies/", "serviceType": "application" } } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js index 3a1c6930cf..2551021a80 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-admin-proxy.js @@ -5,6 +5,51 @@ (function(){ + // controller volo.docs.admin.documentPdfAdmin + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.admin.documentPdfAdmin'); + + volo.docs.admin.documentPdfAdmin.generatePdf = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/documents/pdf/generate' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET', + dataType: null + }, ajaxParams)); + }; + + volo.docs.admin.documentPdfAdmin.getPdfFiles = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/documents/pdf/files' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.admin.documentPdfAdmin.deletePdfFile = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/documents/pdf/delete-file' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'DELETE', + dataType: null + }, ajaxParams)); + }; + + volo.docs.admin.documentPdfAdmin.downloadPdf = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/documents/pdf/download' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.admin.documentPdfAdmin.exists = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/admin/documents/pdf/exists' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + })(); + // controller volo.docs.admin.documentsAdmin (function(){ diff --git a/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js new file mode 100644 index 0000000000..014e357cba --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/wwwroot/client-proxies/docs-common-proxy.js @@ -0,0 +1,68 @@ +/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */ + + +// module docs-common + +(function(){ + + // controller volo.docs.documents.docsDocumentPdfGenerator + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.documents.docsDocumentPdfGenerator'); + + volo.docs.documents.docsDocumentPdfGenerator.generatePdf = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + })(); + + // controller volo.docs.projects.docsProject + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.projects.docsProject'); + + volo.docs.projects.docsProject.getList = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.get = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getDefaultLanguageCode = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/defaultLanguage' + abp.utils.buildQueryString([{ name: 'version', value: version }]) + '', + type: 'GET' + }, { dataType: 'text' }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getVersions = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/versions', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getLanguageList = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/' + version + '/languageList', + type: 'GET' + }, ajaxParams)); + }; + + })(); + +})(); + + diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj b/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj index d6d7c37d07..d7bb3b17b1 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo.Docs.Application.Contracts.csproj @@ -11,6 +11,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs index 7a3b9e9ec2..ce00f1a75a 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/DocsApplicationContractsModule.cs @@ -1,10 +1,12 @@ using Volo.Abp.Application; using Volo.Abp.Modularity; +using Volo.Docs.Common; namespace Volo.Docs { [DependsOn( typeof(DocsDomainSharedModule), + typeof(DocsCommonApplicationContractsModule), typeof(AbpDddApplicationContractsModule) )] public class DocsApplicationContractsModule : AbpModule diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs index 0364a2e26f..5f559c83e5 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Volo.Docs.Common.Projects; using Volo.Docs.Projects; namespace Volo.Docs.Documents diff --git a/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj b/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj index 0bbf42da7e..b7530d7fe8 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj +++ b/modules/docs/src/Volo.Docs.Application/Volo.Docs.Application.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs index fc2eec1759..f2cb5476f7 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs @@ -1,7 +1,8 @@ using AutoMapper; using Volo.Docs.Documents; -using Volo.Docs.Projects; using Volo.Abp.AutoMapper; +using Volo.Docs.Common.Projects; +using Volo.Docs.Projects; namespace Volo.Docs { diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs index e6826d54e6..f6d60099ad 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationModule.cs @@ -4,6 +4,7 @@ using Volo.Abp.Application; using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Modularity; +using Volo.Docs.Common; using Volo.Docs.Documents; namespace Volo.Docs @@ -13,6 +14,7 @@ namespace Volo.Docs typeof(DocsApplicationContractsModule), typeof(AbpCachingModule), typeof(AbpAutoMapperModule), + typeof(DocsCommonApplicationModule), typeof(AbpDddApplicationModule) )] public class DocsApplicationModule : AbpModule diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index c426afacbd..e5bbca3f5a 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -14,8 +14,10 @@ using Volo.Abp.Application.Dtos; using Volo.Abp.Caching; using Volo.Abp.Data; using Volo.Docs.Caching; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Docs.Projects; +using Volo.Docs.Utils; using Volo.Extensions; namespace Volo.Docs.Documents @@ -281,7 +283,7 @@ namespace Volo.Docs.Documents private List GetDocumentLinks(NavigationNode node, List documentUrls, string prefix, string shortName, DocumentWithoutDetails document) { - if (!IsExternalLink(node.Path)) + if (!UrlHelper.IsExternalLink(node.Path)) { documentUrls.AddIfNotContains( NormalizePath(prefix, node.Path, shortName, document) @@ -319,17 +321,6 @@ namespace Volo.Docs.Documents : path; } - private static bool IsExternalLink(string path) - { - if (path.IsNullOrEmpty()) - { - return false; - } - - return path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || - path.StartsWith("https://", StringComparison.OrdinalIgnoreCase); - } - public virtual async Task GetParametersAsync(GetParametersDocumentInput input) { var project = await _projectRepository.GetAsync(input.ProjectId); diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/FodyWeavers.xml b/modules/docs/src/Volo.Docs.Common.Application.Contracts/FodyWeavers.xml new file mode 100644 index 0000000000..00e1d9a1c1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/FodyWeavers.xsd b/modules/docs/src/Volo.Docs.Common.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.abppkg b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.abppkg new file mode 100644 index 0000000000..5ae23d89fc --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.abppkg @@ -0,0 +1,3 @@ +{ + "role": "Volo.Docs.Application.Contracts" +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj new file mode 100644 index 0000000000..acde6b2a6c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo.Docs.Common.Application.Contracts.csproj @@ -0,0 +1,33 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + Volo.Docs.Common.Application.Contracts + Volo.Docs.Common.Application.Contracts + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs new file mode 100644 index 0000000000..8e11262d3d --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonApplicationContractsModule.cs @@ -0,0 +1,31 @@ +using Volo.Abp.Application; +using Volo.Abp.Authorization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common; + +[DependsOn( + typeof(DocsDomainSharedModule), + typeof(AbpDddApplicationContractsModule), + typeof(AbpAuthorizationAbstractionsModule) +)] +public class DocsCommonApplicationContractsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts"); + }); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..4007cb2598 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissionDefinitionProvider.cs @@ -0,0 +1,21 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common +{ + public class DocsCommonPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup(DocsCommonPermissions.GroupName, L("Permission:DocumentManagement.Common")); + + group.AddPermission(DocsCommonPermissions.Projects.PdfDownload, L("Permission:PdfDownload")); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs new file mode 100644 index 0000000000..e07d950110 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonPermissions.cs @@ -0,0 +1,19 @@ +using Volo.Abp.Reflection; + +namespace Volo.Docs.Common +{ + public class DocsCommonPermissions + { + public const string GroupName = "Docs.Common"; + + public static class Projects + { + public const string PdfDownload = GroupName + ".PdfDownload"; + } + + public static string[] GetAll() + { + return ReflectionHelper.GetPublicConstantsRecursively(typeof(DocsCommonPermissions)); + } + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs new file mode 100644 index 0000000000..6faa6d18fd --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/DocsCommonRemoteServiceConsts.cs @@ -0,0 +1,9 @@ +namespace Volo.Docs.Common +{ + public static class DocsCommonRemoteServiceConsts + { + public const string RemoteServiceName = "AbpDocsCommon"; + + public const string ModuleName = "docs-common"; + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs new file mode 100644 index 0000000000..989a0e9c40 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/DocumentPdfGeneratorInput.cs @@ -0,0 +1,12 @@ +using System; + +namespace Volo.Docs.Common.Documents; + +public class DocumentPdfGeneratorInput +{ + public Guid ProjectId { get; set; } + + public string Version { get; set; } + + public string LanguageCode { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfAppService.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfAppService.cs new file mode 100644 index 0000000000..f5ab523b1f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Documents/IDocumentPdfAppService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Content; + +namespace Volo.Docs.Common.Documents; + +public interface IDocumentPdfAppService : IApplicationService +{ + Task DownloadPdfAsync(DocumentPdfGeneratorInput input); + + Task ExistsAsync(DocumentPdfGeneratorInput input); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json new file mode 100644 index 0000000000..71e129fa64 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ar.json @@ -0,0 +1,7 @@ +{ + "culture": "ar", + "texts": { + "Permission:DocumentManagement.Common": "إدارة المستندات العامة", + "Permission:PdfDownload": "تحميل ملفات PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json new file mode 100644 index 0000000000..213dddc37d --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/cs.json @@ -0,0 +1,7 @@ +{ + "culture": "cs", + "texts": { + "Permission:DocumentManagement.Common": "Správa dokumentů", + "Permission:PdfDownload": "Stahování PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json new file mode 100644 index 0000000000..3310b5e4a3 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de-DE.json @@ -0,0 +1,7 @@ +{ + "culture": "de-DE", + "texts": { + "Permission:DocumentManagement.Common": "Dokumentenverwaltung", + "Permission:PdfDownload": "PDF-Herunterladen" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json new file mode 100644 index 0000000000..0b8d5986b1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/de.json @@ -0,0 +1,7 @@ +{ + "culture": "de", + "texts": { + "Permission:DocumentManagement.Common": "Dokumentenverwaltung", + "Permission:PdfDownload": "PDF-Herunterladen" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json new file mode 100644 index 0000000000..176c9fed46 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/el.json @@ -0,0 +1,7 @@ +{ + "culture": "el", + "texts": { + "Permission:DocumentManagement.Common": "Διαχείριση Εγγράφων", + "Permission:PdfDownload": "Λήψη PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json new file mode 100644 index 0000000000..ffe3694967 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en-GB.json @@ -0,0 +1,7 @@ +{ + "culture": "en-GB", + "texts": { + "Permission:DocumentManagement.Common": "Document Management Common", + "Permission:PdfDownload": "PDF Download" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json new file mode 100644 index 0000000000..1113f1909f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/en.json @@ -0,0 +1,7 @@ +{ + "culture": "en", + "texts": { + "Permission:DocumentManagement.Common": "Document Management Common", + "Permission:PdfDownload": "PDF Download" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json new file mode 100644 index 0000000000..4d96926a28 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/es.json @@ -0,0 +1,7 @@ +{ + "culture": "es", + "texts": { + "Permission:DocumentManagement.Common": "Gestión de documentos comunes", + "Permission:PdfDownload": "Descarga de PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json new file mode 100644 index 0000000000..f9791278f6 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fi.json @@ -0,0 +1,7 @@ +{ + "culture": "fi", + "texts": { + "Permission:DocumentManagement.Common": "Tiedostonhallinta", + "Permission:PdfDownload": "PDF-lataaminen" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json new file mode 100644 index 0000000000..6cf85a2294 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/fr.json @@ -0,0 +1,7 @@ +{ + "culture": "fr", + "texts": { + "Permission:DocumentManagement.Common": "Gestion des documents communs", + "Permission:PdfDownload": "Téléchargement de PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json new file mode 100644 index 0000000000..80485999b5 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hi.json @@ -0,0 +1,7 @@ +{ + "culture": "hi", + "texts": { + "Permission:DocumentManagement.Common": "सामान्य दस्तावेज़ प्रबंधन", + "Permission:PdfDownload": "PDF डाउनलोड करना" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json new file mode 100644 index 0000000000..ae3e2b219a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hr.json @@ -0,0 +1,7 @@ +{ + "culture": "hr", + "texts": { + "Permission:DocumentManagement.Common": "Upravljanje zajedničkih dokumenata", + "Permission:PdfDownload": "Preuzimanje PDF-a" + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json new file mode 100644 index 0000000000..32868a4c7c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/hu.json @@ -0,0 +1,7 @@ +{ + "culture": "hu", + "texts": { + "Permission:DocumentManagement.Common": "Általános dokumentumkezelés", + "Permission:PdfDownload": "PDF letöltése" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json new file mode 100644 index 0000000000..7f39fb6170 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/is.json @@ -0,0 +1,7 @@ +{ + "culture": "is", + "texts": { + "Permission:DocumentManagement.Common": "Almennir skjöl", + "Permission:PdfDownload": "Breyta í PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json new file mode 100644 index 0000000000..fd586ae4a0 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/it.json @@ -0,0 +1,7 @@ +{ + "culture": "it", + "texts": { + "Permission:DocumentManagement.Common": "Gestione documenti comuni", + "Permission:PdfDownload": "Download PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json new file mode 100644 index 0000000000..29e5bf8a9c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/nl.json @@ -0,0 +1,7 @@ +{ + "culture": "nl", + "texts": { + "Permission:DocumentManagement.Common": "Algemene documentbeheer", + "Permission:PdfDownload": "PDF downloaden" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json new file mode 100644 index 0000000000..8268413768 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pl-PL.json @@ -0,0 +1,7 @@ +{ + "culture": "pl-PL", + "texts": { + "Permission:DocumentManagement.Common": "Zarządzanie dokumentami", + "Permission:PdfDownload": "Pobieranie PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json new file mode 100644 index 0000000000..a84f075202 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/pt-BR.json @@ -0,0 +1,7 @@ +{ + "culture": "pt-BR", + "texts": { + "Permission:DocumentManagement.Common": "Gerenciamento de documentos comuns", + "Permission:PdfDownload": "Download de PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json new file mode 100644 index 0000000000..8c037ebff5 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ro-RO.json @@ -0,0 +1,7 @@ +{ + "culture": "ro-RO", + "texts": { + "Permission:DocumentManagement.Common": "Gestionarea documentelor comune", + "Permission:PdfDownload": "Descărcare PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json new file mode 100644 index 0000000000..950217d67c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/ru.json @@ -0,0 +1,7 @@ +{ + "culture": "ru", + "texts": { + "Permission:DocumentManagement.Common": "Общее управление документами", + "Permission:PdfDownload": "Скачивание PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json new file mode 100644 index 0000000000..d6a97d88f8 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sk.json @@ -0,0 +1,7 @@ +{ + "culture": "sk", + "texts": { + "Permission:DocumentManagement.Common": "Správa dokumentov", + "Permission:PdfDownload": "Generovanie PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json new file mode 100644 index 0000000000..0f8d8bd2ae --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sl.json @@ -0,0 +1,7 @@ +{ + "culture": "sl", + "texts": { + "Permission:DocumentManagement.Common": "Skupna dokumentna upravljanja", + "Permission:PdfDownload": "Prenos PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json new file mode 100644 index 0000000000..4a8e23575b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/sv.json @@ -0,0 +1,7 @@ +{ + "culture": "sv", + "texts": { + "Permission:DocumentManagement.Common": "Dokumenthantering", + "Permission:PdfDownload": "PDF-generering" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json new file mode 100644 index 0000000000..1b40bdb92a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -0,0 +1,7 @@ +{ + "culture": "tr", + "texts": { + "Permission:DocumentManagement.Common": "Genel Belge Yönetimi", + "Permission:PdfDownload": "PDF İndirme" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json new file mode 100644 index 0000000000..53b86e5ce3 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/vi.json @@ -0,0 +1,7 @@ +{ + "culture": "vi", + "texts": { + "Permission:DocumentManagement.Common": "Quản lý tài liệu chung", + "Permission:PdfDownload": "Tải xuống PDF" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json new file mode 100644 index 0000000000..70f0eaab4d --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hans", + "texts": { + "Permission:DocumentManagement.Common": "通用文档管理", + "Permission:PdfDownload": "PDF下载" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json new file mode 100644 index 0000000000..d37a0ff67a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "Permission:DocumentManagement.Common": "通用文件管理", + "Permission:PdfDownload": "PDF下載" + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/IProjectAppService.cs similarity index 90% rename from modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs rename to modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/IProjectAppService.cs index b93fb09e77..b81637c25f 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/IProjectAppService.cs +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/IProjectAppService.cs @@ -2,8 +2,9 @@ using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Docs.Documents; +using Volo.Docs.Projects; -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { public interface IProjectAppService : IApplicationService { diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/ProjectDto.cs similarity index 95% rename from modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs rename to modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/ProjectDto.cs index 2861e60307..5e0890cbe5 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/ProjectDto.cs +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/ProjectDto.cs @@ -2,7 +2,7 @@ using System; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { [Serializable] public class ProjectDto : EntityDto, IHasExtraProperties diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/VersionInfoDto.cs b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/VersionInfoDto.cs similarity index 77% rename from modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/VersionInfoDto.cs rename to modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/VersionInfoDto.cs index 32ac7bb1c4..59db11e3fa 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Projects/VersionInfoDto.cs +++ b/modules/docs/src/Volo.Docs.Common.Application.Contracts/Volo/Docs/Common/Projects/VersionInfoDto.cs @@ -1,4 +1,4 @@ -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { public class VersionInfoDto { diff --git a/modules/docs/src/Volo.Docs.Common.Application/FodyWeavers.xml b/modules/docs/src/Volo.Docs.Common.Application/FodyWeavers.xml new file mode 100644 index 0000000000..00e1d9a1c1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/FodyWeavers.xsd b/modules/docs/src/Volo.Docs.Common.Application/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.abppkg b/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.abppkg new file mode 100644 index 0000000000..d8358a94f1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.abppkg @@ -0,0 +1,3 @@ +{ + "role": "Volo.Docs.Application" +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj b/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj new file mode 100644 index 0000000000..545995b902 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo.Docs.Common.Application.csproj @@ -0,0 +1,20 @@ + + + + + + + net9.0 + Volo.Docs.Common.Application + Volo.Docs.Common.Application + + + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs new file mode 100644 index 0000000000..280a0c7c82 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonAppServiceBase.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Application.Services; +using Volo.Docs.Localization; + +namespace Volo.Docs.Common +{ + public abstract class DocsCommonAppServiceBase : ApplicationService + { + protected DocsCommonAppServiceBase() + { + ObjectMapperContext = typeof(DocsCommonApplicationModule); + LocalizationResource = typeof(DocsResource); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs new file mode 100644 index 0000000000..8175654743 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationAutoMapperProfile.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using Volo.Docs.Common.Projects; +using Volo.Docs.Projects; + +namespace Volo.Docs.Common +{ + public class DocsCommonApplicationAutoMapperProfile : Profile + { + public DocsCommonApplicationAutoMapperProfile() + { + CreateMap(); + CreateMap(); + } + } +} diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs new file mode 100644 index 0000000000..b7eb350930 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/DocsCommonApplicationModule.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; + +namespace Volo.Docs.Common; + +[DependsOn( + typeof(DocsDomainModule), + typeof(DocsCommonApplicationContractsModule), + typeof(AbpAutoMapperModule), + typeof(AbpDddApplicationModule) +)] +public class DocsCommonApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfAppService.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfAppService.cs new file mode 100644 index 0000000000..0cfdf48bd7 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Documents/DocumentPdfAppService.cs @@ -0,0 +1,55 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Volo.Abp.Content; +using Volo.Abp.Http; +using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf; + +namespace Volo.Docs.Common.Documents; + +[Authorize(DocsCommonPermissions.Projects.PdfDownload)] +public class DocumentPdfAppService : DocsCommonAppServiceBase, IDocumentPdfAppService +{ + protected IProjectPdfGenerator ProjectPdfGenerator { get; } + protected IProjectRepository ProjectRepository { get; } + protected IProjectPdfFileStore ProjectPdfFileStore { get; } + protected IOptions Options { get; } + + public DocumentPdfAppService( + IProjectPdfGenerator projectPdfGenerator, + IProjectRepository projectRepository, + IProjectPdfFileStore projectPdfFileStore, + IOptions options) + { + ProjectPdfGenerator = projectPdfGenerator; + ProjectRepository = projectRepository; + ProjectPdfFileStore = projectPdfFileStore; + Options = options; + } + + public virtual async Task DownloadPdfAsync(DocumentPdfGeneratorInput input) + { + var project = await ProjectRepository.GetAsync(input.ProjectId); + var version = project.GetFullVersion(input.Version); + var languageCode = input.LanguageCode; + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + var fileStream = await ProjectPdfFileStore.GetOrNullAsync(project, version, languageCode); + + if (fileStream != null) + { + return new RemoteStreamContent(fileStream, fileName, MimeTypes.Application.Zip); + } + + return null; + } + + public virtual async Task ExistsAsync(DocumentPdfGeneratorInput input) + { + var project = await ProjectRepository.GetAsync(input.ProjectId); + var version = project.GetFullVersion(input.Version); + var languageCode = input.LanguageCode; + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + return project.FindPdfFile(fileName) != null; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Projects/ProjectAppService.cs similarity index 97% rename from modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs rename to modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Projects/ProjectAppService.cs index 1cca1a102a..96634a300e 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Projects/ProjectAppService.cs +++ b/modules/docs/src/Volo.Docs.Common.Application/Volo/Docs/Common/Projects/ProjectAppService.cs @@ -4,16 +4,15 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; using Volo.Abp.Caching; using Volo.Abp.Data; -using Volo.Abp.Guids; using Volo.Docs.Caching; using Volo.Docs.Documents; +using Volo.Docs.Projects; -namespace Volo.Docs.Projects +namespace Volo.Docs.Common.Projects { - public class ProjectAppService : DocsAppServiceBase, IProjectAppService + public class ProjectAppService : DocsCommonAppServiceBase, IProjectAppService { private readonly IProjectRepository _projectRepository; private readonly IDistributedCache> _versionCache; diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsDocumentPdfClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsDocumentPdfClientProxy.Generated.cs new file mode 100644 index 0000000000..e40ce0d1ec --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsDocumentPdfClientProxy.Generated.cs @@ -0,0 +1,36 @@ +// This file is automatically generated by ABP framework to use MVC Controllers from CSharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Modeling; +using Volo.Docs.Common.Documents; + +// ReSharper disable once CheckNamespace +namespace Volo.Docs.Documents; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(IDocumentPdfAppService), typeof(DocsDocumentPdfClientProxy))] +public partial class DocsDocumentPdfClientProxy : ClientProxyBase, IDocumentPdfAppService +{ + public virtual async Task DownloadPdfAsync(DocumentPdfGeneratorInput input) + { + return await RequestAsync(nameof(DownloadPdfAsync), new ClientProxyRequestTypeValue + { + { typeof(DocumentPdfGeneratorInput), input } + }); + } + + public virtual async Task ExistsAsync(DocumentPdfGeneratorInput input) + { + return await RequestAsync(nameof(ExistsAsync), new ClientProxyRequestTypeValue + { + { typeof(DocumentPdfGeneratorInput), input } + }); + } +} diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsDocumentPdfClientProxy.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsDocumentPdfClientProxy.cs new file mode 100644 index 0000000000..e692a1a0ee --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsDocumentPdfClientProxy.cs @@ -0,0 +1,7 @@ +// This file is part of DocsDocumentPdfClientProxy, you can customize it here +// ReSharper disable once CheckNamespace +namespace Volo.Docs.Documents; + +public partial class DocsDocumentPdfClientProxy +{ +} diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsProjectClientProxy.Generated.cs similarity index 98% rename from modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs rename to modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsProjectClientProxy.Generated.cs index 2caa2e3e93..19170e497e 100644 --- a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.Generated.cs +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsProjectClientProxy.Generated.cs @@ -8,8 +8,8 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client; using Volo.Abp.Http.Client.ClientProxying; using Volo.Abp.Http.Modeling; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; -using Volo.Docs.Projects; // ReSharper disable once CheckNamespace namespace Volo.Docs.Projects; diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsProjectClientProxy.cs similarity index 100% rename from modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Projects/DocsProjectClientProxy.cs rename to modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/DocsProjectClientProxy.cs diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json new file mode 100644 index 0000000000..16b7c6d4b0 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/ClientProxies/docs-common-generate-proxy.json @@ -0,0 +1,498 @@ +{ + "modules": { + "docs-common": { + "rootPath": "docs-common", + "remoteServiceName": "AbpDocsCommon", + "controllers": { + "Volo.Docs.Documents.DocsDocumentPdfController": { + "controllerName": "DocsDocumentPdf", + "controllerGroupName": "DocumentPdf", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Documents.DocsDocumentPdfController", + "interfaces": [ + { + "type": "Volo.Docs.Common.Documents.IDocumentPdfAppService", + "name": "IDocumentPdfAppService", + "methods": [ + { + "name": "DownloadPdfAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + } + }, + { + "name": "ExistsAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Boolean", + "typeSimple": "boolean" + } + } + ] + } + ], + "actions": { + "DownloadPdfAsyncByInput": { + "uniqueName": "DownloadPdfAsyncByInput", + "name": "DownloadPdfAsync", + "httpMethod": "GET", + "url": "api/docs/documents/pdf/download", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Content.IRemoteStreamContent", + "typeSimple": "Volo.Abp.Content.IRemoteStreamContent" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Documents.IDocumentPdfAppService" + }, + "ExistsAsyncByInput": { + "uniqueName": "ExistsAsyncByInput", + "name": "ExistsAsync", + "httpMethod": "GET", + "url": "api/docs/documents/pdf/exists", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput, Volo.Docs.Common.Application.Contracts", + "type": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "typeSimple": "Volo.Docs.Common.Documents.DocumentPdfGeneratorInput", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "System.Boolean", + "typeSimple": "boolean" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Documents.IDocumentPdfAppService" + } + } + }, + "Volo.Docs.Projects.DocsProjectController": { + "controllerName": "DocsProject", + "controllerGroupName": "Project", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Projects.DocsProjectController", + "interfaces": [ + { + "type": "Volo.Docs.Common.Projects.IProjectAppService", + "name": "IProjectAppService", + "methods": [ + { + "name": "GetListAsync", + "parametersOnMethod": [], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, + { + "name": "GetAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Common.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Common.Projects.ProjectDto" + } + }, + { + "name": "GetVersionsAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, + { + "name": "GetDefaultLanguageCodeAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.String", + "typeSimple": "string" + } + }, + { + "name": "GetLanguageListAsync", + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Docs.Documents.LanguageConfig", + "typeSimple": "Volo.Docs.Documents.LanguageConfig" + } + } + ] + } + ], + "actions": { + "GetListAsync": { + "uniqueName": "GetListAsync", + "name": "GetListAsync", + "httpMethod": "GET", + "url": "api/docs/projects", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetAsyncByShortName": { + "uniqueName": "GetAsyncByShortName", + "name": "GetAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Common.Projects.ProjectDto", + "typeSimple": "Volo.Docs.Common.Projects.ProjectDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetDefaultLanguageCodeAsyncByShortNameAndVersion": { + "uniqueName": "GetDefaultLanguageCodeAsyncByShortNameAndVersion", + "name": "GetDefaultLanguageCodeAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}/defaultLanguage", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + }, + { + "nameOnMethod": "version", + "name": "version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.String", + "typeSimple": "string" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetVersionsAsyncByShortName": { + "uniqueName": "GetVersionsAsyncByShortName", + "name": "GetVersionsAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}/versions", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + }, + "GetLanguageListAsyncByShortNameAndVersion": { + "uniqueName": "GetLanguageListAsyncByShortNameAndVersion", + "name": "GetLanguageListAsync", + "httpMethod": "GET", + "url": "api/docs/projects/{shortName}/{version}/languageList", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "shortName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "version", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "shortName", + "name": "shortName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + }, + { + "nameOnMethod": "version", + "name": "version", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Docs.Documents.LanguageConfig", + "typeSimple": "Volo.Docs.Documents.LanguageConfig" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Common.Projects.IProjectAppService" + } + } + } + } + } + }, + "types": {} +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/FodyWeavers.xml b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/FodyWeavers.xml new file mode 100644 index 0000000000..00e1d9a1c1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/FodyWeavers.xsd b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.abppkg b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.abppkg new file mode 100644 index 0000000000..a4939ea991 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.abppkg @@ -0,0 +1,15 @@ +{ + "role": "Volo.Docs.HttpApi.Client", + "proxies": { + "csharp": { + "VoloDocs.Web-docs-common": { + "applicationName": "VoloDocs.Web", + "module": "docs-common", + "url": "https://localhost:5001", + "folder": "ClientProxies", + "serviceType": "all", + "withoutContracts": true + } + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj new file mode 100644 index 0000000000..ff4c3301fc --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo.Docs.Common.HttpApi.Client.csproj @@ -0,0 +1,19 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + Volo.Docs.Common.HttpApi.Client + Volo.Docs.Common.HttpApi.Client + + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs new file mode 100644 index 0000000000..a139d29ac2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi.Client/Volo/Docs/DocsCommonHttpApiClientModule.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; +using Volo.Docs.Common; + +namespace Volo.Docs +{ + [DependsOn( + typeof(DocsCommonApplicationContractsModule), + typeof(AbpHttpClientModule) + )] + public class DocsCommonHttpApiClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddStaticHttpClientProxies(typeof(DocsCommonApplicationContractsModule).Assembly, DocsCommonRemoteServiceConsts.RemoteServiceName); + + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } + } +} diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/FodyWeavers.xml b/modules/docs/src/Volo.Docs.Common.HttpApi/FodyWeavers.xml new file mode 100644 index 0000000000..00e1d9a1c1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/FodyWeavers.xsd b/modules/docs/src/Volo.Docs.Common.HttpApi/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.abppkg b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.abppkg new file mode 100644 index 0000000000..bbc082c681 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.abppkg @@ -0,0 +1,3 @@ +{ + "role": "Volo.Docs.HttpApi" +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj new file mode 100644 index 0000000000..001778b838 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo.Docs.Common.HttpApi.csproj @@ -0,0 +1,18 @@ + + + + + + + net9.0 + Volo.Docs.Common.HttpApi + Volo.Docs.Common.HttpApi + + + + + + + + + diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs new file mode 100644 index 0000000000..09ff45507b --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsCommonHttpApiModule.cs @@ -0,0 +1,35 @@ +using Localization.Resources.AbpUi; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Docs.Common; +using Volo.Docs.Localization; + +namespace Volo.Docs +{ + [DependsOn( + typeof(DocsCommonApplicationContractsModule), + typeof(AbpAspNetCoreMvcModule) + )] + public class DocsCommonHttpApiModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(DocsCommonHttpApiModule).Assembly); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Resources + .Get() + .AddBaseTypes(typeof(AbpUiResource)); + }); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs new file mode 100644 index 0000000000..8d730acd4f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/DocsControllerBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.AspNetCore.Mvc; +using Volo.Docs.Localization; + +namespace Volo.Docs; + +public abstract class DocsControllerBase : AbpControllerBase +{ + protected DocsControllerBase() + { + LocalizationResource = typeof(DocsResource); + } +} diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfController.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfController.cs new file mode 100644 index 0000000000..040373269e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfController.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; +using Volo.Abp.Content; +using Volo.Docs.Common; +using Volo.Docs.Common.Documents; + +namespace Volo.Docs.Documents; + +[RemoteService(Name = DocsCommonRemoteServiceConsts.RemoteServiceName)] +[Area(DocsCommonRemoteServiceConsts.ModuleName)] +[ControllerName("DocumentPdf")] +[Route("api/docs/documents/pdf")] +public class DocsDocumentPdfController : DocsControllerBase, IDocumentPdfAppService +{ + protected IDocumentPdfAppService DocumentPdfAppService { get; } + + public DocsDocumentPdfController(IDocumentPdfAppService documentPdfAppService) + { + DocumentPdfAppService = documentPdfAppService; + } + + [HttpGet] + [Route("download")] + public virtual Task DownloadPdfAsync(DocumentPdfGeneratorInput input) + { + return DocumentPdfAppService.DownloadPdfAsync(input); + } + + [HttpGet] + [Route("exists")] + public virtual Task ExistsAsync(DocumentPdfGeneratorInput input) + { + return DocumentPdfAppService.ExistsAsync(input); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Projects/DocsProjectController.cs similarity index 90% rename from modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs rename to modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Projects/DocsProjectController.cs index 3a23d379ef..440a215187 100644 --- a/modules/docs/src/Volo.Docs.HttpApi/Volo/Docs/Projects/DocsProjectController.cs +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Projects/DocsProjectController.cs @@ -5,12 +5,14 @@ using Asp.Versioning; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; +using Volo.Docs.Common; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; namespace Volo.Docs.Projects { - [RemoteService(Name = DocsRemoteServiceConsts.RemoteServiceName)] - [Area(DocsRemoteServiceConsts.ModuleName)] + [RemoteService(Name = DocsCommonRemoteServiceConsts.RemoteServiceName)] + [Area(DocsCommonRemoteServiceConsts.ModuleName)] [ControllerName("Project")] [Route("api/docs/projects")] public class DocsProjectController : AbpControllerBase, IProjectAppService diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj b/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj index 8a4911b9b9..2ce827d009 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj @@ -11,6 +11,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs new file mode 100644 index 0000000000..0bcdfdb8d1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentParams.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Volo.Docs.Documents; + +public class DocumentParams +{ + [JsonPropertyName("parameters")] + public List Parameters { get; set; } = new(); + + + public class DocumentParameter + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } + + [JsonPropertyName("values")] + public Dictionary Values { get; set; } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs index 015f711850..43ebfa9a76 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs @@ -24,6 +24,12 @@ namespace Volo.Docs.Documents [JsonPropertyName("keywords")] public string[] Keywords { get; set; } + + [JsonPropertyName("ignoreOnDownload")] + public bool IgnoreOnDownload { get; set; } + + [JsonPropertyName("isInSeries")] + public bool IsInSeries { get; set; } public bool IsLeaf => !HasChildItems; diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateContent.cs similarity index 77% rename from modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs rename to modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateContent.cs index 5db9fc8164..66a5d27a16 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateContent.cs @@ -1,4 +1,4 @@ -namespace Volo.Docs.HtmlConverting +namespace Volo.Docs.Documents.Rendering { public class DocumentPartialTemplateContent { diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs new file mode 100644 index 0000000000..4ae900256e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentPartialTemplateWithValues.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Volo.Docs.Documents.Rendering; + +public class DocumentPartialTemplateWithValues +{ + public string Path { get; set; } + + public Dictionary Parameters { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs new file mode 100644 index 0000000000..dc7bf95e62 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/DocumentRenderParameters.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace Volo.Docs.Documents.Rendering +{ + public class DocumentRenderParameters : Dictionary + { + public DocumentRenderParameters() + { + + } + + public DocumentRenderParameters(DocumentRenderParameters renderParameters) + { + foreach (var parameter in renderParameters) + { + Add(parameter.Key, parameter.Value); + } + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs new file mode 100644 index 0000000000..9179601545 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/IDocumentSectionRenderer.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Docs.Documents.Rendering; + +public interface IDocumentSectionRenderer : ITransientDependency +{ + Task RenderAsync(string document, DocumentRenderParameters parameters = null, List partialTemplates = null); + + Task>> GetAvailableParametersAsync(string document); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs new file mode 100644 index 0000000000..02881c5a67 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Scriban; +using Volo.Abp; +using Volo.Extensions; + +namespace Volo.Docs.Documents.Rendering; + +public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer +{ + protected readonly static List DocsJsonSections = + [ + new("````json", "````"), + new("```json", "```") + ]; + + protected const string DocsParam = "//[doc-params]"; + protected const string DocsTemplates = "//[doc-template]"; + protected const string DocsNav = "//[doc-nav]"; + + public ILogger Logger { get; set; } + + public ScribanDocumentSectionRenderer() + { + Logger = NullLogger.Instance; + } + + public async Task RenderAsync( + string document, + DocumentRenderParameters parameters = null, + List partialTemplates = null) + { + if (partialTemplates != null && partialTemplates.Any()) + { + document = SetPartialTemplates(document, partialTemplates); + } + + var scribanTemplate = Template.Parse(document); + + if (parameters == null) + { + return await scribanTemplate.RenderAsync(); + } + + var result = await scribanTemplate.RenderAsync(parameters); + + return RemoveOptionsJson(result, DocsParam, DocsNav); + } + + public Task>> GetAvailableParametersAsync(string document) + { + return GetSectionAsync>>(document, DocsParam); + } + + protected virtual async Task GetSectionAsync(string document, string sectionName) where T : new() + { + try + { + if (!HasJsonSection(document) || !document.Contains(sectionName)) + { + return new T(); + } + + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, _) = + GetJsonBeginEndIndexesAndPureJson(document, sectionName); + + if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + { + return new T(); + } + + var pureJson = insideJsonSection.Replace(sectionName, "").Trim(); + + if (!DocsJsonSerializerHelper.TryDeserialize(pureJson, out var section)) + { + throw new UserFriendlyException($"ERROR-20200327: Cannot validate JSON content for `{sectionName}`!"); + } + + return await Task.FromResult(section); + } + catch (Exception) + { + Logger.LogWarning("Unable to parse parameters of document."); + return new T(); + } + } + + protected static string RemoveOptionsJson(string document, params string[] sectionNames) + { + foreach (var sectionName in sectionNames) + { + var orgDocument = document; + + try + { + if (!HasJsonSection(document) || !document.Contains(sectionName)) + { + continue; + } + + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, jsonSection) = + GetJsonBeginEndIndexesAndPureJson(document, sectionName); + + if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + { + continue; + } + + document = document.Remove( + jsonBeginningIndex - jsonSection.Opener.Length, + (jsonEndingIndex + jsonSection.Closer.Length) - (jsonBeginningIndex - jsonSection.Opener.Length) + ); + } + catch (Exception) + { + document = orgDocument; + } + } + + return document; + } + + protected static bool HasJsonSection(string document) + { + return DocsJsonSections.Any(section => document.Contains(section.Opener) && document.Contains(section.Closer)); + } + + protected static (int, int, string, DocsJsonSection) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + { + foreach (var section in DocsJsonSections) + { + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = + section.GetJsonBeginEndIndexesAndPureJson(document, sectionName); + + if (jsonBeginningIndex >= 0 && jsonEndingIndex > 0 && !string.IsNullOrWhiteSpace(insideJsonSection)) + { + return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, section); + } + } + + return (-1, -1, "", null); + } + + protected static string SetPartialTemplates(string document, IReadOnlyCollection templates) + { + foreach (var section in DocsJsonSections) + { + document = section.SetPartialTemplates(document, templates); + } + + return document; + } + + protected class DocsJsonSection + { + public string Opener { get; } + public string Closer { get; } + + public DocsJsonSection(string opener, string closer) + { + Opener = opener; + Closer = closer; + } + + public (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) + { + var searchedIndex = 0; + + while (searchedIndex < document.Length) + { + var jsonBeginningIndex = document.Substring(searchedIndex).IndexOf(Opener, StringComparison.Ordinal); + + if (jsonBeginningIndex < 0) + { + return (-1, -1, ""); + } + + jsonBeginningIndex += Opener.Length + searchedIndex; + + var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(Closer, StringComparison.Ordinal); + if (jsonEndingIndex < 0) + { + return (-1, -1, ""); + } + + jsonEndingIndex += jsonBeginningIndex; + var insideJsonSection = document.Substring(jsonBeginningIndex, jsonEndingIndex - jsonBeginningIndex); + + if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) + { + searchedIndex = jsonEndingIndex + Closer.Length; + continue; + } + + return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection); + } + + return (-1, -1, ""); + } + + public async Task> GetPartialTemplatesInDocumentAsync(string documentContent) + { + var templates = new List(); + + while (documentContent.Contains(Opener)) + { + var afterJsonOpener = documentContent.Substring( + documentContent.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); + + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + ); + + documentContent = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + + if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + { + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring( + betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + + DocsTemplates.Length); + + if (!DocsJsonSerializerHelper.TryDeserialize(json, + out var template)) + { + throw new UserFriendlyException( + $"ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); + } + + templates.Add(template); + } + + return await Task.FromResult(templates); + } + + public string SetPartialTemplates(string document, IReadOnlyCollection templates) + { + var newDocument = new StringBuilder(); + + while (document.Contains(Opener)) + { + var beforeJson = document.Substring(0, + document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); + + var afterJsonOpener = document.Substring( + document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length + ); + + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + ); + + if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) + { + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + + newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + Closer); + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring( + betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + + DocsTemplates.Length + ); + + if (DocsJsonSerializerHelper.TryDeserialize(json, + out var documentPartialTemplateWithValuesDto)) + { + var template = + templates.FirstOrDefault(t => t.Path == documentPartialTemplateWithValuesDto.Path); + + var beforeTemplate = document.Substring(0, + document.IndexOf(Opener, StringComparison.Ordinal) + ); + + newDocument.Append(beforeTemplate + template?.Content + Closer); + + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length + ); + } + } + + newDocument.Append(document); + + return newDocument.ToString(); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterFactory.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterFactory.cs similarity index 82% rename from modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterFactory.cs rename to modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterFactory.cs index a6a7978eee..43a239b297 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterFactory.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterFactory.cs @@ -19,7 +19,7 @@ namespace Volo.Docs.HtmlConverting Options = options.Value; } - public virtual IDocumentToHtmlConverter Create(string format) + public virtual IDocumentToHtmlConverter Create(string format) { var serviceType = Options.Converters.GetOrDefault(format); if (serviceType == null) @@ -27,7 +27,7 @@ namespace Volo.Docs.HtmlConverting throw new ApplicationException($"Unknown document format: {format}"); } - return (IDocumentToHtmlConverter)ServiceProvider.GetRequiredService(serviceType); + return (IDocumentToHtmlConverter)ServiceProvider.GetRequiredService(serviceType); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs new file mode 100644 index 0000000000..a658140d08 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/DocumentToHtmlConverterOptions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Docs.HtmlConverting; + +public class DocumentToHtmlConverterOptions +{ + public Dictionary Converters { get; set; } + + public DocumentToHtmlConverterOptions() + { + Converters = new Dictionary(); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs new file mode 100644 index 0000000000..351e34feba --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverter.cs @@ -0,0 +1,9 @@ +using Volo.Docs.Documents; +using Volo.Docs.HtmlConverting; + +namespace Volo.Docs.HtmlConverting; + +public interface IDocumentToHtmlConverter +{ + string Convert(TContext context); +} diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs new file mode 100644 index 0000000000..0be9f79187 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/HtmlConverting/IDocumentToHtmlConverterFactory.cs @@ -0,0 +1,6 @@ +namespace Volo.Docs.HtmlConverting; + +public interface IDocumentToHtmlConverterFactory +{ + IDocumentToHtmlConverter Create(string format); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs index 3322fb7732..b421cfc631 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs @@ -36,5 +36,7 @@ /// Default value: 128 ///
public static int MaxVersionNameLength { get; set; } = 128; + + public static string Latest = "latest"; } } diff --git a/modules/docs/src/Volo.Docs.Web/Utils/UrlHelper.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Utils/UrlHelper.cs similarity index 100% rename from modules/docs/src/Volo.Docs.Web/Utils/UrlHelper.cs rename to modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Utils/UrlHelper.cs diff --git a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj index 5f2c9b6206..e57312e16b 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj +++ b/modules/docs/src/Volo.Docs.Domain/Volo.Docs.Domain.csproj @@ -20,7 +20,11 @@ - + + + + + @@ -28,6 +32,7 @@ + diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs index ff6bd56ee4..1e8463fe6c 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainConsts.cs @@ -3,5 +3,6 @@ public class DocsDomainConsts { public static string LanguageConfigFileName = "docs-langs.json"; + public static string PdfDocumentToHtmlConverterPrefix = "pdf-"; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs index 6e6b222351..502b2f9065 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs @@ -1,10 +1,11 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.AutoMapper; +using Volo.Abp.BlobStoring; +using Volo.Abp.Caching; using Volo.Abp.Domain; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Localization; @@ -16,15 +17,19 @@ using Volo.Docs.Documents.FullSearch.Elastic; using Volo.Docs.FileSystem.Documents; using Volo.Docs.GitHub; using Volo.Docs.GitHub.Documents; +using Volo.Docs.HtmlConverting; using Volo.Docs.Localization; using Volo.Docs.Projects; +using Volo.Docs.Projects.Pdf.Markdig; namespace Volo.Docs { [DependsOn( typeof(DocsDomainSharedModule), typeof(AbpDddDomainModule), - typeof(AbpAutoMapperModule) + typeof(AbpAutoMapperModule), + typeof(AbpBlobStoringModule), + typeof(AbpCachingModule) )] public class DocsDomainModule : AbpModule { @@ -76,6 +81,11 @@ namespace Volo.Docs { client.Timeout = TimeSpan.FromMilliseconds(15000); }); + + Configure(options => + { + options.Converters[DocsDomainConsts.PdfDocumentToHtmlConverterPrefix + MarkdigPdfDocumentToHtmlConverter.Type] = typeof(MarkdigPdfDocumentToHtmlConverter); + }); } public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs index e16f81d2c9..ca5c1221ad 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs @@ -32,7 +32,8 @@ namespace Volo.Docs.FileSystem.Documents localDirectory = documentName.Substring(0, documentName.LastIndexOf('/')); } - version = File.GetLastWriteTime(path).ToString("yyyyMMddHHmmss"); + // The version is intentionally set to "1.0.0" as part of the versioning strategy for file system documents. + version = "1.0.0"; return new Document(GuidGenerator.Create(), project.Id, diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json index 6e01a9af72..f7d3533653 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ar.json @@ -38,6 +38,7 @@ "Search": "بحث", "SearchResults": "نتائج البحث", "SearchInTheAllDocuments": "البحث في جميع الوثائق", - "GoogleTranslate": "ترجمة جوجل" + "GoogleTranslate": "ترجمة جوجل", + "DownloadPDF": "تحميل PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json index c8e6d3d19b..ed6c8767b8 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/cs.json @@ -38,6 +38,7 @@ "Search": "Vyhledávání", "SearchResults": "Výsledky vyhledávání", "SearchInTheAllDocuments": "Hledejte ve všech dokumentech", - "GoogleTranslate": "Přeložit do češtiny" + "GoogleTranslate": "Přeložit do češtiny", + "DownloadPDF": "Stáhnout PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json index 343db45f12..6a614441eb 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/de.json @@ -38,6 +38,7 @@ "Search": "Suchen", "SearchResults": "Suchergebnisse", "SearchInTheAllDocuments": "Durchsuchen Sie alle Dokumente", - "GoogleTranslate": "Ins Deutsche übersetzen" + "GoogleTranslate": "Ins Deutsche übersetzen", + "DownloadPDF": "PDF herunterladen" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json index 21bc61b7e5..2a1a72dca2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/el.json @@ -37,6 +37,7 @@ "Preview": "προεπισκόπηση", "Search": "Αναζήτηση", "SearchResults": "Αποτελέσματα αναζήτησης", - "GoogleTranslate": "Μετάφραση στα ελληνικά" + "GoogleTranslate": "Μετάφραση στα ελληνικά", + "DownloadPDF": "Κατέβασμα PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json index ba33bd31d6..d56e8da6df 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en-GB.json @@ -35,6 +35,7 @@ "UpdatedExplanation": "Updated in the last two weeks.", "Volo.Docs.Domain:010002": "ShortName {ShortName} already exists.", "Preview": "preview", - "GoogleTranslate": "Google Translate" + "GoogleTranslate": "Google Translate", + "DownloadPDF": "Download PDF" } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json index b4414be0ea..6715146b50 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json @@ -43,6 +43,8 @@ "ProjectDeletionWarningMessage": "Project will be deleted.", "Docs_Page_Title": "ABP Documentation", "Docs_Page_Description": "Access comprehensive guides and API references in the ABP Documentation, aiding in development and troubleshooting.", - "GoogleTranslate": "Google Translate" + "GoogleTranslate": "Google Translate", + "DownloadPDF": "Download PDF", + "PdfFileGeneratedSuccessfully": "The PDF file is generated successfully." } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json index 624d56d631..3dcd97e7fe 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/es.json @@ -38,6 +38,7 @@ "Search": "Buscar", "SearchResults": "Resultados de la búsqueda", "SearchInTheAllDocuments": "Buscar en todos los documentos", - "GoogleTranslate": "Traducir con Google" + "GoogleTranslate": "Traducir con Google", + "DownloadPDF": "Descargar PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json index 543803bec4..db74d481a0 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fi.json @@ -38,6 +38,7 @@ "Search": "Hae", "SearchResults": "Hakutulokset", "SearchInTheAllDocuments": "Hae kaikista asiakirjoista", - "GoogleTranslate": "Google-käännös" + "GoogleTranslate": "Google-käännös", + "DownloadPDF": "Lataa PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json index 6e8ccfffab..1bab402f73 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/fr.json @@ -38,6 +38,7 @@ "Search": "Rechercher", "SearchResults": "Résultats de recherche", "SearchInTheAllDocuments": "Rechercher dans tous les documents", - "GoogleTranslate": "Google Traduction" + "GoogleTranslate": "Google Traduction", + "DownloadPDF": "Télécharger PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json index b79c38b9b8..2ba78ec460 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hi.json @@ -38,6 +38,7 @@ "Search": "खोज", "SearchResults": "खोज परिणाम", "SearchInTheAllDocuments": "सभी दस्तावेज़ों में खोजें", - "GoogleTranslate": "गूगल अनुवाद" + "GoogleTranslate": "गूगल अनुवाद", + "DownloadPDF": "PDF डाउनलोड करें" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json index bf71b7faed..1061dee7ab 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hr.json @@ -38,6 +38,7 @@ "Search": "Pretraga", "SearchResults": "Rezultati pretrage", "SearchInTheAllDocuments": "Traži u svim dokumentima", - "GoogleTranslate": "Google prevoditelj" + "GoogleTranslate": "Google prevoditelj", + "DownloadPDF": "Preuzmi PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json index 1624b1b2d1..b8dee63ca4 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/hu.json @@ -38,6 +38,7 @@ "Search": "Keresés", "SearchResults": "Keresési eredmények", "SearchInTheAllDocuments": "Keressen az összes dokumentumban", - "GoogleTranslate": "Google Fordító" + "GoogleTranslate": "Google Fordító", + "DownloadPDF": "PDF letöltése" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json index 5d96a2fac5..62235d3f62 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/is.json @@ -38,6 +38,7 @@ "Search": "Leit", "SearchResults": "Leitar niðurstöður", "SearchInTheAllDocuments": "Leitaðu í öllum skjölum", - "GoogleTranslate": "Google þýðing" + "GoogleTranslate": "Google þýðing", + "DownloadPDF": "Sækja PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json index 3983154519..91ef732c01 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/it.json @@ -38,6 +38,7 @@ "Search": "Ricerca", "SearchResults": "Risultati della ricerca", "SearchInTheAllDocuments": "Cerca in tutti i documenti", - "GoogleTranslate": "Traduci con Google" + "GoogleTranslate": "Traduci con Google", + "DownloadPDF": "Scarica PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json index f126886009..48a82699d7 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/nl.json @@ -38,6 +38,7 @@ "Search": "Zoeken", "SearchResults": "Zoekresultaten", "SearchInTheAllDocuments": "Zoek in alle documenten", - "GoogleTranslate": "Google Vertalen" + "GoogleTranslate": "Google Vertalen", + "DownloadPDF": "PDF downloaden" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json index 5d5c58ea3f..35ae3e6801 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pl-PL.json @@ -38,6 +38,7 @@ "Search": "Szukaj", "SearchResults": "Wyniki wyszukiwania", "SearchInTheAllDocuments": "Szukaj we wszystkich dokumentach", - "GoogleTranslate": "Tłumaczenie na polski" + "GoogleTranslate": "Tłumaczenie na polski", + "DownloadPDF": "Pobierz PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json index 0e4143f9ac..497f0c93e2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/pt-BR.json @@ -38,6 +38,7 @@ "Search": "Procurar", "SearchResults": "Procurar Resultados", "SearchInTheAllDocuments": "Pesquise em todos os documentos", - "GoogleTranslate": "Traduzir com Google" + "GoogleTranslate": "Traduzir com Google", + "DownloadPDF": "Baixar PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json index eaf9016463..155dad0754 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ro-RO.json @@ -38,6 +38,7 @@ "Search": "Caută", "SearchResults": "Rezultatele căutării", "SearchInTheAllDocuments": "Căutați în toate documentele", - "GoogleTranslate": "Traducere Google" + "GoogleTranslate": "Traducere Google", + "DownloadPDF": "Descărcare PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json index ae4b2a564d..2b5a200187 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/ru.json @@ -38,6 +38,7 @@ "Search": "Поиск", "SearchResults": "результаты поиска", "SearchInTheAllDocuments": "Искать во всех документах", - "GoogleTranslate": "Google Translate" + "GoogleTranslate": "Google Translate", + "DownloadPDF": "Скачать PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json index 54f981e98f..8f0f246a16 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sk.json @@ -38,6 +38,7 @@ "Search": "Vyhľadať", "SearchResults": "Výsledky vyhľadávania", "SearchInTheAllDocuments": "Vyhľadajte vo všetkých dokumentoch", - "GoogleTranslate": "Google preklad" + "GoogleTranslate": "Google preklad", + "DownloadPDF": "Stiahnuť PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json index 3d326a5127..c182e66b3e 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sl.json @@ -38,6 +38,7 @@ "Search": "Iskanje", "SearchResults": "Rezultati iskanja", "SearchInTheAllDocuments": "Poiščite v vseh dokumentih", - "GoogleTranslate": "Google prevajalnik" + "GoogleTranslate": "Google prevajalnik", + "DownloadPDF": "Prenesi PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json index 2ec28362f0..29db42be57 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/sv.json @@ -43,6 +43,7 @@ "ProjectDeletionWarningMessage": "Projektet kommer att raderas.", "Docs_Page_Title": "ABP-dokumentation", "Docs_Page_Description": "Få tillgång till omfattande guider och API-referenser i ABP Documentation, vilket underlättar utveckling och felsökning.", - "GoogleTranslate": "Google Översätt" + "GoogleTranslate": "Google Översätt", + "DownloadPDF": "Ladda ner PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json index 0e9619ce4d..35b08c6a62 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/tr.json @@ -37,6 +37,7 @@ "Preview": "ön izleme", "Search": "Arama", "SearchResults": "Arama Sonuçları", - "GoogleTranslate": "Google Çeviri" + "GoogleTranslate": "Google Çeviri", + "DownloadPDF": "PDF İndir" } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json index 612bcad36a..d6916d05ad 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/vi.json @@ -38,6 +38,7 @@ "Search": "Tìm kiếm", "SearchResults": "kết quả tìm kiếm", "SearchInTheAllDocuments": "Tìm kiếm trong tất cả các tài liệu", - "GoogleTranslate": "Dịch Google" + "GoogleTranslate": "Dịch Google", + "DownloadPDF": "Tải xuống PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json index 4aaac66120..d214b9b4a6 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hans.json @@ -38,6 +38,7 @@ "Search": "搜索", "SearchResults": "搜索结果", "SearchInTheAllDocuments": "在所有文档中搜索", - "GoogleTranslate": "谷歌翻译" + "GoogleTranslate": "谷歌翻译", + "DownloadPDF": "下载PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json index 8f2a6ea86e..ee4a291b61 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json @@ -38,6 +38,7 @@ "Search": "搜索", "SearchResults": "搜索結果", "SearchInTheAllDocuments": "在所有文件中搜尋", - "GoogleTranslate": "谷歌翻譯" + "GoogleTranslate": "谷歌翻譯", + "DownloadPDF": "下載PDF" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs index db13ea2c8a..9d7443c5b2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/IProjectRepository.cs @@ -8,7 +8,7 @@ namespace Volo.Docs.Projects { public interface IProjectRepository : IBasicRepository { - Task> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default); + Task> GetListAsync(string sorting, int maxResultCount, int skipCount,bool includeDetails = false, CancellationToken cancellationToken = default); Task> GetListWithoutDetailsAsync(CancellationToken cancellationToken = default); Task GetByShortNameAsync(string shortName, CancellationToken cancellationToken = default); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs new file mode 100644 index 0000000000..9d12923325 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/BlobProjectPdfFileStore.cs @@ -0,0 +1,68 @@ +using System.IO; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Timing; + +namespace Volo.Docs.Projects.Pdf; + +public class BlobProjectPdfFileStore : IProjectPdfFileStore, ITransientDependency +{ + protected IBlobContainer BlobContainer { get; } + protected IOptions Options { get; } + protected IProjectRepository ProjectRepository { get; } + protected IClock Clock { get; } + + public BlobProjectPdfFileStore( + IBlobContainer blobContainer, + IOptions options, + IClock clock, IProjectRepository projectRepository) + { + BlobContainer = blobContainer; + Options = options; + Clock = clock; + ProjectRepository = projectRepository; + } + + public virtual async Task SetAsync(Project project, string version, string languageCode, Stream stream) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + await BlobContainer.SaveAsync(fileName, stream, true); + + var pdfFile = project.FindPdfFile(fileName); + if(pdfFile == null) + { + project.AddPdfFile(project.Id, fileName, version, languageCode); + } + else + { + pdfFile.LastModificationTime = Clock.Now; + } + + await ProjectRepository.UpdateAsync(project); + } + + public virtual async Task GetOrNullAsync(Project project, string version, string languageCode) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + + var pdfFile = project.FindPdfFile(fileName); + if (pdfFile == null) + { + return null; + } + + return await BlobContainer.GetOrNullAsync(Options.Value.CalculatePdfFileName(project, version, languageCode)); + } + + public virtual async Task DeleteAsync(Project project, string version, string languageCode) + { + var fileName = Options.Value.CalculatePdfFileName(project, version, languageCode); + + await BlobContainer.DeleteAsync(fileName); + project.RemovePdfFile(fileName); + await ProjectRepository.UpdateAsync(project); + + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfContainer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfContainer.cs new file mode 100644 index 0000000000..554ed42601 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfContainer.cs @@ -0,0 +1,9 @@ +using Volo.Abp.BlobStoring; + +namespace Volo.Docs.Projects.Pdf; + +[BlobContainerName("docs-document-pdf")] +public class DocsProjectPdfContainer +{ + +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs new file mode 100644 index 0000000000..8b8678930d --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/DocsProjectPdfGeneratorOptions.cs @@ -0,0 +1,113 @@ +using System; + +namespace Volo.Docs.Projects.Pdf; + +public class DocsProjectPdfGeneratorOptions +{ + public const string StylePlaceholder = "{{style-placeholder}}"; + public const string ContentPlaceholder = "{{content-placeholder}}"; + + /// + /// The HTML layout for the PDF document. + /// + public string HtmlLayout { get; set; } + + /// + /// The HTML style for the PDF document. + /// + public string HtmlStyle { get; set; } + + /// + /// The base URL for the PDF document. + /// Used for resolving relative links and images. + /// + public string BaseUrl { get; set; } + + /// + /// The path to the index page of the documentation. + /// + public string IndexPagePath { get; set; } + + /// + /// The function to calculate the PDF file name. + /// Default is "{project.ShortName}-{version}-{languageCode}.zip". + /// + public Func CalculatePdfFileName { get; set; } + + /// + /// The function to calculate the PDF file title. + /// + public Func CalculatePdfFileTitle { get; set; } + + public Func HtmlContentNormalizer { get; set; } + + public Func DocumentContentNormalizer { get; set; } + + public DocsProjectPdfGeneratorOptions() + { + HtmlLayout = $@" + + + + + + + {ContentPlaceholder} + + "; + + HtmlStyle = @" + body { margin: 15px; line-height: 1.5; font-family: Arial, sans-serif;} + a { text-decoration: none; word-break: break-all; overflow-wrap: break-word;} + li { word-break: break-all; overflow-wrap: break-word; } + .page { + page-break-after: always; + margin-bottom: 30px; + padding: 15px; + } + img { + max-width: 100%; + max-height: 850px; + object-fit: contain; + display: block; + } + code, pre { + background: #f8fafc; + white-space: pre-wrap; + word-wrap: break-word; + } + pre code { padding: 0; border: none; } + code { + padding: 2px 6px; + border-radius: 4px; + border: 1px solid #e2e8f0; + font-family: Consolas, monospace; + } + pre { + position: relative; + padding: 16px; + border-radius: 8px; + border: 1px solid #e2e8f0; + } + blockquote { + border-left: 4px solid #e2e8f0; + margin: 20px 0; + padding: 10px 20px; + background: #f8fafc; + } + table { width: 100%; border-collapse: collapse; table-layout: fixed; } + table img { width: 100% !important; height: auto; display: block; } + th { font-weight: bold; background-color: #f5f5f5; } + th, td { + border: 1px solid #333; + padding: 6px 10px; + word-break: break-all; + overflow-wrap: break-word; + width: 100%; + }"; + + CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}-{version}-{languageCode}.zip"; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs new file mode 100644 index 0000000000..56fdc2f995 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IHtmlToPdfRenderer.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Volo.Docs.Projects.Pdf; + +public interface IHtmlToPdfRenderer +{ + Task RenderAsync(string title, string html, List documents); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs new file mode 100644 index 0000000000..4f11d9cad2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfFileStore.cs @@ -0,0 +1,13 @@ +using System.IO; +using System.Threading.Tasks; + +namespace Volo.Docs.Projects.Pdf; + +public interface IProjectPdfFileStore +{ + Task SetAsync(Project project, string version, string languageCode, Stream stream); + + Task GetOrNullAsync(Project project, string version, string languageCode); + + Task DeleteAsync(Project project, string version, string languageCode); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfGenerator.cs new file mode 100644 index 0000000000..dad173bc19 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IProjectPdfGenerator.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace Volo.Docs.Projects.Pdf; + +public interface IProjectPdfGenerator +{ + Task GenerateAsync(Project project, string version, string languageCode); +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/HtmlIdTagWorkerFactory.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/HtmlIdTagWorkerFactory.cs new file mode 100644 index 0000000000..17483a7605 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/HtmlIdTagWorkerFactory.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using iText.Html2pdf.Attach; +using iText.Html2pdf.Attach.Impl; +using iText.Kernel.Pdf.Navigation; +using iText.StyledXmlParser.Node; + +namespace Volo.Docs.Projects.Pdf.IText; + +public class HtmlIdTagWorkerFactory : DefaultTagWorkerFactory +{ + private readonly iText.Kernel.Pdf.PdfDocument _pdfDocument; + private readonly Dictionary _pageDestinations = new(); + + public HtmlIdTagWorkerFactory(iText.Kernel.Pdf.PdfDocument pdfDocument) + { + _pdfDocument = pdfDocument; + } + + public override ITagWorker GetCustomTagWorker(IElementNode tag, ProcessorContext context) + { + var tagClass = tag.GetAttribute("class"); + if (tag.Name().Equals("div") && tagClass =="page") + { + var id = tag.GetAttribute("id"); + _pageDestinations[id] = _pdfDocument.GetNumberOfPages() + 1; + } + + return base.GetCustomTagWorker(tag, context); + } + + public void AddNamedDestinations() + { + foreach (var pageDestination in _pageDestinations) + { + var page = _pdfDocument.GetPage(pageDestination.Value); + var destination = PdfExplicitDestination.CreateFit(page); + _pdfDocument.AddNamedDestination(pageDestination.Key, destination.GetPdfObject()); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs new file mode 100644 index 0000000000..cd83333495 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/IText/ITextHtmlToPdfRenderer.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using iText.Html2pdf; +using iText.Kernel.Pdf; +using iText.Kernel.Pdf.Action; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Utils; + +namespace Volo.Docs.Projects.Pdf.IText; + +public class ITextHtmlToPdfRenderer : IHtmlToPdfRenderer, ITransientDependency +{ + protected IOptions Options { get; } + + public ITextHtmlToPdfRenderer(IOptions options) + { + Options = options; + } + + public virtual Task RenderAsync(string title, string html, List documents) + { + var pdfStream = new MemoryStream(); + using (var pdfWriter = new PdfWriter(pdfStream)) + { + pdfWriter.SetCloseStream(false); + using (var pdfDocument = new iText.Kernel.Pdf.PdfDocument(pdfWriter)) + { + pdfDocument.GetDocumentInfo().SetTitle(title); + CreatePdfFromHtml(html, pdfDocument); + AddOutlinesToPdf(pdfDocument, documents); + } + } + + pdfStream.Position = 0; + return Task.FromResult(pdfStream); + } + + private void CreatePdfFromHtml(string html, iText.Kernel.Pdf.PdfDocument pdfDocument) + { + var converter = new ConverterProperties(); + var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); + converter.SetTagWorkerFactory(tagWorkerFactory); + + HtmlConverter.ConvertToDocument(html, pdfDocument, converter); + + tagWorkerFactory.AddNamedDestinations(); + } + + private void AddOutlinesToPdf(iText.Kernel.Pdf.PdfDocument pdfDocument, List documents) + { + var pdfOutlines = pdfDocument.GetOutlines(false); + BuildPdfOutlines(pdfOutlines, documents); + } + + private void BuildPdfOutlines(PdfOutline parentOutline, List pdfDocumentNodes) + { + foreach (var pdfDocumentNode in pdfDocumentNodes) + { + if (pdfDocumentNode.IgnoreOnOutline) + { + continue; + } + + var outline = parentOutline.AddOutline(pdfDocumentNode.Title); + if (!pdfDocumentNode.Id.IsNullOrWhiteSpace()) + { + outline.AddAction(UrlHelper.IsExternalLink(pdfDocumentNode.Id) ? PdfAction.CreateURI(pdfDocumentNode.Id) : PdfAction.CreateGoTo(pdfDocumentNode.Id)); + } + + if (pdfDocumentNode.HasChildren) + { + BuildPdfOutlines(outline, pdfDocumentNode.Children); + } + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkRenderer.cs new file mode 100644 index 0000000000..881b2915e3 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkRenderer.cs @@ -0,0 +1,59 @@ +using System; +using System.Linq; +using Markdig.Renderers; +using Markdig.Renderers.Html.Inlines; +using Markdig.Syntax.Inlines; +using Volo.Docs.Utils; + +namespace Volo.Docs.Projects.Pdf.Markdig; + +public class AnchorLinkRenderer : LinkInlineRenderer +{ + private readonly PdfDocument _document; + + public AnchorLinkRenderer(PdfDocument document) + { + _document = document; + } + + protected override void Write(HtmlRenderer renderer, LinkInline link) + { + if (UrlHelper.IsExternalLink(link.Url) || link.Url.IsNullOrWhiteSpace() || link.IsImage) + { + base.Write(renderer, link); + return; + } + + link.GetDynamicUrl = () => "#" + ResolveRelativeMarkdownPath(_document.Document.Name, link.Url) + .Replace(".md", string.Empty).Replace("/", "-").Replace(" ", "-").ToLower(); + base.Write(renderer, link); + } + + private string ResolveRelativeMarkdownPath(string currentPath, string relativePath) + { + currentPath = currentPath.EnsureStartsWith('/'); + relativePath = relativePath.EnsureStartsWith('/'); + + var currentDir = currentPath.Substring(0, currentPath.LastIndexOf('/')); + + var baseParts = currentDir.Split('/', StringSplitOptions.RemoveEmptyEntries).ToList(); + var relativeParts = relativePath.Split('/', StringSplitOptions.RemoveEmptyEntries); + + foreach (var part in relativeParts) + { + if (part == "..") + { + if (baseParts.Count > 0) + { + baseParts.RemoveAt(baseParts.Count - 1); + } + } + else if (part != ".") + { + baseParts.Add(part); + } + } + + return string.Join("/", baseParts); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkResolverExtension.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkResolverExtension.cs new file mode 100644 index 0000000000..38405da4d7 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/AnchorLinkResolverExtension.cs @@ -0,0 +1,27 @@ +using Markdig; +using Markdig.Renderers; +using Markdig.Renderers.Html.Inlines; + +namespace Volo.Docs.Projects.Pdf.Markdig; + +public class AnchorLinkResolverExtension : IMarkdownExtension +{ + private readonly PdfDocument _document; + + public AnchorLinkResolverExtension(PdfDocument document) + { + _document = document; + } + + public void Setup(MarkdownPipelineBuilder pipeline) + { + } + + public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) + { + if (renderer is HtmlRenderer htmlRenderer) + { + htmlRenderer.ObjectRenderers.Replace(new AnchorLinkRenderer(_document)); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs new file mode 100644 index 0000000000..22c94b5930 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/Markdig/MarkdigPdfDocumentToHtmlConverter.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web; +using Markdig; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Documents; +using Volo.Docs.HtmlConverting; +using Volo.Docs.Utils; + +namespace Volo.Docs.Projects.Pdf.Markdig; + +public class MarkdigPdfDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency +{ + public const string Type = "md"; + protected IOptions Options { get; } + + public MarkdigPdfDocumentToHtmlConverter(IOptions options) + { + Options = options; + } + + public virtual string Convert(PdfDocumentToHtmlConverterContext converterContext) + { + var htmlContent = Markdown.ToHtml(NormalizeContent( + converterContext.Content, + converterContext.PdfDocument, + converterContext.DocumentParams), + GetPipeline(converterContext.PdfDocument)); + return NormalizeHtmlContent(htmlContent, converterContext.PdfDocument); + } + + protected virtual MarkdownPipeline GetPipeline(PdfDocument pdfDocument) + { + return new MarkdownPipelineBuilder() + .UseAdvancedExtensions() + .UseBootstrap() + .Use(new AnchorLinkResolverExtension(pdfDocument)) + .Build(); + } + + protected virtual string NormalizeContent(string content, PdfDocument pdfDocument, DocumentParams documentParams) + { + content = Regex.Replace(content, @"`{3,4}json\s*//\[doc-nav\][\s\S]*?`{3,4}", string.Empty, RegexOptions.IgnoreCase); + content = SetContentTitle(content, pdfDocument, documentParams); + if (Options.Value.DocumentContentNormalizer == null) + { + return content; + } + + return Options.Value.DocumentContentNormalizer(content); + } + + protected virtual string NormalizeHtmlContent(string htmlContent, PdfDocument pdfDocument) + { + htmlContent = WrapHtmlWithPageDiv(htmlContent, pdfDocument); + htmlContent = ReplaceRelativeImageUrls(htmlContent, pdfDocument); + if (Options.Value.HtmlContentNormalizer == null) + { + return htmlContent; + } + + return Options.Value.HtmlContentNormalizer(htmlContent); + } + + private string WrapHtmlWithPageDiv(string htmlContent, PdfDocument pdfDocument) + { + return $"
{htmlContent}
"; + } + + private string ReplaceRelativeImageUrls(string htmlContent, PdfDocument pdfDocument) + { + return Regex.Replace(htmlContent, @"(]*)src=""([^""]*)""([^>]*>)", delegate (Match match) + { + if (UrlHelper.IsExternalLink(match.Groups[2].Value)) + { + return match.Value; + } + + var rootUrl = UrlHelper.IsExternalLink(pdfDocument.Document.RawRootUrl) + ? pdfDocument.Document.RawRootUrl.EnsureEndsWith('/') + : Options.Value.BaseUrl.EnsureEndsWith('/') + pdfDocument.Document.RawRootUrl.TrimStart('/').EnsureEndsWith('/'); + var newImageSource = rootUrl + + (pdfDocument.Document.LocalDirectory.IsNullOrEmpty() ? "" : pdfDocument.Document.LocalDirectory.TrimStart('/').EnsureEndsWith('/')) + + match.Groups[2].Value.TrimStart('/'); + + return match.Groups[1] + " src=\"" + HttpUtility.HtmlEncode(newImageSource) + "\" " + match.Groups[3]; + + }, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline); + } + + private static string SetContentTitle(string content, PdfDocument pdfDocument, DocumentParams documentParams) + { + if (pdfDocument.RenderParameters.IsNullOrEmpty()) + { + return content; + } + + var titleLine = content.Split(Environment.NewLine).FirstOrDefault(x => x.TrimStart().StartsWith("#")); + if (titleLine == null) + { + return content; + } + + var paramValues = pdfDocument.RenderParameters.Select(x => + { + var documentParam = documentParams.Parameters.FirstOrDefault(p => p.Name == x.Key); + return $"{documentParam?.Values[x.Value] ?? x.Value}"; + }); + + var newTitle = $"{titleLine.Trim()} ({string.Join(", ", paramValues)})"; + return content.Replace(titleLine, newTitle); + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocument.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocument.cs new file mode 100644 index 0000000000..a0aca0c710 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocument.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; +using Volo.Docs.Documents; +using Volo.Docs.Documents.Rendering; + +namespace Volo.Docs.Projects.Pdf; + +public class PdfDocument +{ + public Document Document { get; set; } + public string Title { get; set; } + public string Id { get; set; } + public List Children { get; set; } = []; + public DocumentRenderParameters RenderParameters { get; set; } + public bool HasChildren => Children.Any(); + public bool IgnoreOnOutline { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs new file mode 100644 index 0000000000..5a99d46634 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/PdfDocumentToHtmlConverterContext.cs @@ -0,0 +1,18 @@ +using Volo.Docs.Documents; + +namespace Volo.Docs.Projects.Pdf; + +public class PdfDocumentToHtmlConverterContext +{ + public string Content { get; set; } + public PdfDocument PdfDocument { get; set; } + + public DocumentParams DocumentParams { get; set; } + + public PdfDocumentToHtmlConverterContext(string content, PdfDocument pdfDocument, DocumentParams documentParams) + { + Content = content; + PdfDocument = pdfDocument; + DocumentParams = documentParams; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs new file mode 100644 index 0000000000..f91e341d6f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Pdf/ProjectPdfGenerator.cs @@ -0,0 +1,555 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Documents; +using Volo.Docs.Documents.Rendering; +using Volo.Docs.HtmlConverting; +using Volo.Docs.Utils; +using Volo.Extensions; + +namespace Volo.Docs.Projects.Pdf; + +public class ProjectPdfGenerator : IProjectPdfGenerator, ITransientDependency +{ + protected IDocumentSourceFactory DocumentStoreFactory { get; } + protected IDocumentToHtmlConverterFactory DocumentToHtmlConverterFactory { get; } + protected IDocumentRepository DocumentRepository { get; } + protected IDocumentSectionRenderer DocumentSectionRenderer { get; } + protected IOptions Options { get; } + protected IProjectPdfFileStore ProjectPdfFileStore { get; } + protected IHtmlToPdfRenderer HtmlToPdfRenderer { get; } + protected ILogger Logger { get; set; } + protected IDocumentSource DocumentSource { get; set; } + protected DocumentParams DocumentParams { get; set; } + protected Project Project { get; set; } + protected List AllPdfDocuments { get; } = []; + + public ProjectPdfGenerator( + IDocumentSourceFactory documentStoreFactory, + IDocumentRepository documentRepository, + IOptions options, + IDocumentSectionRenderer documentSectionRenderer, + IProjectPdfFileStore projectPdfFileStore, + IHtmlToPdfRenderer htmlToPdfRenderer, + IDocumentToHtmlConverterFactory documentToHtmlConverterFactory, + ILogger logger) + { + DocumentStoreFactory = documentStoreFactory; + DocumentRepository = documentRepository; + Options = options; + DocumentSectionRenderer = documentSectionRenderer; + ProjectPdfFileStore = projectPdfFileStore; + HtmlToPdfRenderer = htmlToPdfRenderer; + DocumentToHtmlConverterFactory = documentToHtmlConverterFactory; + Logger = logger; + } + + public virtual async Task GenerateAsync(Project project, string version, string languageCode) + { + Project = project; + DocumentSource = DocumentStoreFactory.Create(project.DocumentStoreType); + DocumentParams = await GetDocumentParamsAsync(project, version, languageCode); + + var navigation = await GetNavigationAsync(project, version, languageCode); + await SetAllPdfDocumentsAsync(navigation.Items, project, version, languageCode); + + var title = Options.Value.CalculatePdfFileTitle?.Invoke(project) ?? project.Name; + var tempFiles = new List<(PdfDocument pdfDocument, Stream stream)>(); + + try + { + for (var i = 0; i < AllPdfDocuments.Count; i++) + { + var document = AllPdfDocuments[i]; + Logger.LogInformation("Processing chunk {Index}/{Total}", i + 1, AllPdfDocuments.Count); + + var chunkHtml = await BuildHtmlAsync([document]); + + var pdfStream = await HtmlToPdfRenderer.RenderAsync($"{title} - Part {document.Title}", chunkHtml, [document]); + + Logger.LogInformation("Chunk {Index} rendered to PDF", i + 1); + + tempFiles.Add((document, pdfStream)); + } + + Logger.LogInformation("All chunks processed, merging PDF files"); + + var mergedPdfStream = await MergePdfFilesAsync(tempFiles); + await ProjectPdfFileStore.SetAsync(project, version, languageCode, mergedPdfStream); + } + catch (Exception e) + { + Logger.LogError(e, "An error occurred while generating the PDF for project {ProjectName}", project.Name); + foreach (var tempStream in tempFiles) + { + try + { + await tempStream.stream.DisposeAsync(); + } + catch + { + // ignore any exceptions during disposal + } + } + } + finally + { + AllPdfDocuments.Clear(); + } + } + + protected virtual async Task BuildHtmlAsync(List pdfDocuments) + { + var htmlContent = await ConvertDocumentsToHtmlAsync(pdfDocuments); + + var htmlBuilder = new StringBuilder(); + htmlBuilder.Append(Options.Value.HtmlLayout); + htmlBuilder.Replace(DocsProjectPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyle); + htmlBuilder.Replace(DocsProjectPdfGeneratorOptions.ContentPlaceholder, htmlContent); + + return htmlBuilder.ToString(); + } + + protected virtual async Task ConvertDocumentsToHtmlAsync(List pdfDocuments) + { + var contentBuilder = new StringBuilder(); + + foreach (var pdfDocument in pdfDocuments) + { + if (pdfDocument.Document != null) + { + var renderedDocument = await RenderDocumentAsync(pdfDocument); + var documentToHtmlConverter = GetDocumentToHtmlConverter(Project, pdfDocument); + var htmlContent = + documentToHtmlConverter.Convert( + new PdfDocumentToHtmlConverterContext(renderedDocument, pdfDocument, DocumentParams)); + contentBuilder.AppendLine(htmlContent); + } + + if (pdfDocument.HasChildren) + { + contentBuilder.AppendLine(await ConvertDocumentsToHtmlAsync(pdfDocument.Children)); + } + } + + return contentBuilder.ToString(); + } + + protected virtual async Task MergePdfFilesAsync( + List<(PdfDocument pdfDocument, Stream stream)> pdfFiles) + { + if (pdfFiles.Count == 0) + { + throw new ArgumentException("No PDF files to merge", nameof(pdfFiles)); + } + + var zipStream = new MemoryStream(); + + + using (var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Create, true)) + { + for (var index = 0; index < pdfFiles.Count; index++) + { + var (doc, pdfFile) = pdfFiles[index]; + var entry = zipArchive.CreateEntry($"{index + 1}_{doc.Title}.pdf", CompressionLevel.Fastest); + await using var entryStream = entry.Open(); + await pdfFile.CopyToAsync(entryStream); + + try + { + await pdfFile.DisposeAsync(); + } + catch (Exception e) + { + Logger.LogWarning(e, "Error disposing PDF file stream for document {DocumentTitle}", doc.Title); + } + } + } + + + zipStream.Position = 0; + return zipStream; + } + + + protected virtual IDocumentToHtmlConverter GetDocumentToHtmlConverter( + Project project, PdfDocument pdfDocument) + { + return DocumentToHtmlConverterFactory.Create( + DocsDomainConsts.PdfDocumentToHtmlConverterPrefix + (pdfDocument.Document.Format ?? project.Format)); + } + + protected virtual async Task RenderDocumentAsync(PdfDocument pdfDocument) + { + var parameters = new DocumentRenderParameters(); + if (pdfDocument.RenderParameters == null) + { + return await DocumentSectionRenderer.RenderAsync(pdfDocument.Document.Content, parameters); + } + + foreach (var renderParameter in pdfDocument.RenderParameters) + { + var documentParam = DocumentParams.Parameters.FirstOrDefault(p => p.Name == renderParameter.Key); + parameters.Add(renderParameter.Key, renderParameter.Value); + parameters.Add(renderParameter.Key + "_Value", + documentParam?.Values[renderParameter.Value] ?? renderParameter.Value); + } + + return await DocumentSectionRenderer.RenderAsync(pdfDocument.Document.Content, parameters); + } + + protected virtual async Task SetAllPdfDocumentsAsync( + List navigations, + Project project, + string version, + string languageCode, + PdfDocument parentPdfDocument = null) + { + var groupedCombinationsDocuments = new Dictionary>(); + + foreach (var navigation in navigations) + { + if (navigation.IgnoreOnDownload) + { + continue; + } + + try + { + var pdfDocument = new PdfDocument + { + Title = navigation.Text, + IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath, + Id = UrlHelper.IsExternalLink(navigation.Path) ? navigation.Path : null + }; + + if (!navigation.Path.IsNullOrWhiteSpace() && !UrlHelper.IsExternalLink(navigation.Path) && + !navigation.HasChildItems) + { + await HandleLeafDocumentAsync( + navigation, + project, + version, + languageCode, + parentPdfDocument, + groupedCombinationsDocuments, + pdfDocument + ); + } + + if (!navigation.IsInSeries) + { + if (parentPdfDocument == null) + { + AllPdfDocuments.AddIfNotContains(pdfDocument); + } + else + { + parentPdfDocument.Children.AddIfNotContains(pdfDocument); + } + } + + if (navigation.HasChildItems) + { + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); + await SetAllPdfDocumentsAsync(navigation.Items, project, version, languageCode, pdfDocument); + } + + if (!navigation.IsInSeries || navigation == navigations.Last()) + { + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); + } + } + catch (Exception e) + { + Logger.LogWarning(e, + $"Cannot get document for the path '{navigation.Path}' in the project {project.Name}."); + } + } + } + + private async Task HandleLeafDocumentAsync( + NavigationNode navigation, + Project project, + string version, + string languageCode, + PdfDocument parentPdfDocument, + Dictionary> groupedCombinationsDocuments, + PdfDocument leafDocument) + { + var document = await GetDocumentAsync(project, navigation.Path, version, languageCode); + var parameters = await DocumentSectionRenderer.GetAvailableParametersAsync(document.Content); + var parameterCombinations = GenerateAllParameterCombinations(parameters.Keys.ToList(), parameters); + var firstCombination = parameterCombinations.FirstOrDefault(); + + leafDocument.Document = document; + leafDocument.RenderParameters = firstCombination; + leafDocument.Id = GetDocumentId(document.Name, document.Format ?? project.Format, firstCombination, true); + leafDocument.Title = GetDocumentTitle(navigation.Text, firstCombination, DocumentParams); + + if (parameterCombinations.Count <= 1) + { + AddParameterCombinationsDocuments(parentPdfDocument, groupedCombinationsDocuments); + return; + } + + for (var i = 0; i < parameterCombinations.Count; i++) + { + var combination = parameterCombinations[i]; + var key = string.Join("-", combination.Select(x => $"{x.Key}_{x.Value}")); + + if (!groupedCombinationsDocuments.ContainsKey(key)) + { + groupedCombinationsDocuments[key] = []; + } + + var combinationDocument = i == 0 + ? leafDocument + : new PdfDocument + { + Document = document, + Id = GetDocumentId(document.Name, document.Format ?? project.Format, combination, false), + Title = GetDocumentTitle(navigation.Text, combination, DocumentParams), + RenderParameters = combination + }; + + groupedCombinationsDocuments[key].Add(combinationDocument); + } + } + + private void AddParameterCombinationsDocuments(PdfDocument parentPdfDocument, + Dictionary> groupedCombinationsDocuments) + { + foreach (var combinations in groupedCombinationsDocuments) + { + if (parentPdfDocument == null) + { + AllPdfDocuments.AddIfNotContains(combinations.Value); + } + else + { + parentPdfDocument.Children.AddIfNotContains(combinations.Value); + } + } + + groupedCombinationsDocuments.Clear(); + } + + private async Task GetNavigationAsync( + Project project, + string version, + string languageCode) + { + var navigationDocument = await GetDocumentAsync(project, project.NavigationDocumentName, version, languageCode); + + if (!DocsJsonSerializerHelper.TryDeserialize(navigationDocument.Content, out var navigation)) + { + throw new UserFriendlyException( + $"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}."); + } + + if (!Options.Value.IndexPagePath.IsNullOrWhiteSpace()) + { + navigation.Items.Insert(0, new NavigationNode { Path = Options.Value.IndexPagePath }); + } + + return navigation; + } + + private async Task GetDocumentParamsAsync( + Project project, + string version, + string languageCode) + { + if (project.ParametersDocumentName.IsNullOrWhiteSpace()) + { + return new DocumentParams(); + } + + try + { + var documentParamsDocument = + await GetDocumentAsync(project, project.ParametersDocumentName, version, languageCode); + + if (!DocsJsonSerializerHelper.TryDeserialize(documentParamsDocument.Content, + out var documentParams)) + { + throw new UserFriendlyException( + $"Cannot validate document params file '{project.ParametersDocumentName}' for the project {project.Name}."); + } + + return documentParams; + } + catch (Exception e) + { + Logger.LogError(e, $"Cannot get document params for the project {project.Name}.", e); + return new DocumentParams(); + } + } + + private async Task GetDocumentAsync( + Project project, + string documentName, + string version, + string languageCode) + { + version = string.IsNullOrWhiteSpace(version) ? project.LatestVersionBranchName : version; + + Document document = null; + Exception firstException = null; + + var possibleNames = GetPossibleNames(documentName, project.Format); + document = await DocumentRepository.FindAsync(project.Id, possibleNames, languageCode, version); + if (document != null) + { + return document; + } + + foreach (var name in possibleNames) + { + try + { + document = await DocumentSource.GetDocumentAsync(project, name, languageCode, version); + await DocumentRepository.InsertAsync(document, true); + break; + } + catch (Exception ex) + { + firstException ??= ex; + } + } + + if (document == null) + { + throw firstException!; + } + + return document; + } + + private static List GenerateAllParameterCombinations(List parameterKeys, + Dictionary> parameters) + { + var parameterCombinations = new List(); + + if (parameters.Count <= 0) + { + return parameterCombinations; + } + + GenerateCombinations(0, new DocumentRenderParameters()); + return parameterCombinations; + + void GenerateCombinations(int keyIndex, DocumentRenderParameters currentCombination) + { + if (keyIndex == parameterKeys.Count) + { + parameterCombinations.Add(new DocumentRenderParameters(currentCombination)); + return; + } + + var currentKey = parameterKeys[keyIndex]; + foreach (var value in parameters[currentKey]) + { + currentCombination[currentKey] = value; + GenerateCombinations(keyIndex + 1, currentCombination); + } + } + } + + private static string GetDocumentId(string documentName, string format, DocumentRenderParameters parameters, + bool isFirstCombinationDocument) + { + var id = documentName.Replace("." + format, string.Empty).Replace("/", "-").Replace(" ", "-").ToLower(); + if (parameters != null && !isFirstCombinationDocument) + { + id = $"{id}{parameters.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-")}"; + } + + return id; + } + + private static string GetDocumentTitle(string title, DocumentRenderParameters parameters, + DocumentParams documentParams) + { + if (parameters == null || parameters.Count <= 0) + { + return title; + } + + var paramValues = parameters.Select(x => + { + var documentParam = documentParams.Parameters.FirstOrDefault(p => p.Name == x.Key); + return $"{documentParam?.DisplayName ?? x.Key} : {documentParam?.Values[x.Value] ?? x.Value}"; + }); + + return title.Trim() + $" ({string.Join(", ", paramValues)})"; + } + + private static List GetPossibleNames(string originalDocumentName, string format) + { + var extension = Path.GetExtension(originalDocumentName); + if (extension.IsNullOrWhiteSpace()) + { + extension = "." + format; + } + + if (!extension.Equals("." + format, StringComparison.OrdinalIgnoreCase)) + { + return [originalDocumentName]; + } + + var lowerCaseIndex = "index." + format; + var titleCaseIndex = "Index." + format; + var indexLength = lowerCaseIndex.Length; + + var possibleNames = new List { originalDocumentName }; + if (originalDocumentName.EndsWith("/" + lowerCaseIndex, StringComparison.OrdinalIgnoreCase) || + originalDocumentName.Equals(lowerCaseIndex, StringComparison.OrdinalIgnoreCase)) + { + var indexPart = originalDocumentName.Right(indexLength); + + var documentNameWithoutIndex = + originalDocumentName.Left(originalDocumentName.Length - lowerCaseIndex.Length); + + if (indexPart != lowerCaseIndex) + { + possibleNames.Add(documentNameWithoutIndex + lowerCaseIndex); + } + + if (indexPart != titleCaseIndex) + { + possibleNames.Add(documentNameWithoutIndex + titleCaseIndex); + } + } + else + { + var documentNameWithoutExtension = + RemoveFileExtensionFromPath(originalDocumentName, format).EnsureEndsWith('/'); + possibleNames.Add(documentNameWithoutExtension + lowerCaseIndex); + possibleNames.Add(documentNameWithoutExtension + titleCaseIndex); + } + + return possibleNames; + } + + private static string RemoveFileExtensionFromPath(string path, string format) + { + if (path == null) + { + return null; + } + + return path.EndsWith("." + format) + ? path.Left(path.Length - format.Length - 1) + : path; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs index 48eb93d19e..03020494d8 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/Project.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; +using System.Text; using JetBrains.Annotations; using Volo.Abp; +using Volo.Abp.Data; using Volo.Abp.Domain.Entities; namespace Volo.Docs.Projects @@ -47,9 +50,12 @@ namespace Volo.Docs.Projects public virtual string MainWebsiteUrl { get; set; } public virtual string LatestVersionBranchName { get; set; } + + public virtual List PdfFiles { get; set; } protected Project() { + PdfFiles = new List(); } public Project( @@ -103,5 +109,53 @@ namespace Volo.Docs.Projects { ShortName = ShortName.ToLower(); } + + public virtual ProjectPdfFile FindPdfFile(string fileName) + { + return PdfFiles.Find(x => x.FileName == fileName); + } + + public virtual void AddPdfFile(Guid projectId, string fileName, string version, string languageCode) + { + PdfFiles.Add(new ProjectPdfFile(projectId, fileName, version, languageCode)); + } + + public virtual void RemovePdfFile(string fileName) + { + var pdfFile = FindPdfFile(fileName); + if (pdfFile != null) + { + PdfFiles.Remove(pdfFile); + } + } + + public virtual string GetFullVersion(string version) + { + var prefix = GetProjectVersionPrefixIfExist(this); + if (string.IsNullOrWhiteSpace(prefix) || version.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + return version; + } + + var inputVersionStringBuilder = new StringBuilder(); + return inputVersionStringBuilder.Append(prefix).Append(version).ToString(); + } + + protected virtual string GetProjectVersionPrefixIfExist(Project project) + { + if (GetGithubVersionProviderSource(project) != GithubVersionProviderSource.Branches) + { + return string.Empty; + } + + return project.GetProperty("VersionBranchPrefix"); + } + + protected virtual GithubVersionProviderSource GetGithubVersionProviderSource(Project project) + { + return project.HasProperty("GithubVersionProviderSource") + ? project.GetProperty("GithubVersionProviderSource") + : GithubVersionProviderSource.Releases; + } } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs new file mode 100644 index 0000000000..135ca3b01e --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Projects/ProjectPdfFile.cs @@ -0,0 +1,38 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; + +namespace Volo.Docs.Projects; + +public class ProjectPdfFile : Entity, IHasCreationTime, IHasModificationTime +{ + public virtual Guid ProjectId { get; set; } + public virtual string FileName { get; set; } + public virtual string Version { get; set; } + public virtual string LanguageCode { get; set; } + public virtual DateTime CreationTime { get; set; } + public virtual DateTime? LastModificationTime { get; set; } + + protected ProjectPdfFile() + { + + } + + public ProjectPdfFile(Guid projectId, string fileName, string version, string languageCode) + { + ProjectId = projectId; + FileName = fileName; + Version = version; + LanguageCode = languageCode; + } + + public override object[] GetKeys() + { + return [ProjectId, FileName]; + } + + public virtual bool Equals(Guid projectId, string fileName) + { + return ProjectId == projectId && FileName == fileName; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs index 9ce0c59dc3..56b2204bc5 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContext.cs @@ -16,6 +16,8 @@ namespace Volo.Docs.EntityFrameworkCore public DbSet Documents { get; set; } public DbSet DocumentContributors { get; set; } + + public DbSet ProjectPdfFiles { get; set; } public DocsDbContext(DbContextOptions options) : base(options) diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs index 745b822f17..86f230164f 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs @@ -31,6 +31,10 @@ namespace Volo.Docs.EntityFrameworkCore b.Property(x => x.NavigationDocumentName).IsRequired().HasMaxLength(ProjectConsts.MaxNavigationDocumentNameLength); b.Property(x => x.ParametersDocumentName).IsRequired().HasMaxLength(ProjectConsts.MaxParametersDocumentNameLength); b.Property(x => x.LatestVersionBranchName).HasMaxLength(ProjectConsts.MaxLatestVersionBranchNameLength); + + b.HasMany(x => x.PdfFiles).WithOne() + .HasForeignKey(x => new { x.ProjectId }) + .IsRequired(); b.ApplyObjectExtensionMappings(); }); @@ -69,6 +73,17 @@ namespace Volo.Docs.EntityFrameworkCore b.ApplyObjectExtensionMappings(); }); + + builder.Entity(b => + { + b.ToTable(AbpDocsDbProperties.DbTablePrefix + "ProjectPdfFiles", AbpDocsDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.HasKey(x => new { x.ProjectId, x.FileName }); + + b.ApplyObjectExtensionMappings(); + }); builder.TryConfigureObjectExtensions(); } diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs index 0bd2e4fff8..89aff2cf3c 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsEfCoreQueryableExtensions.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Volo.Docs.Documents; +using Volo.Docs.Projects; namespace Volo.Docs.EntityFrameworkCore { @@ -10,5 +11,10 @@ namespace Volo.Docs.EntityFrameworkCore { return !include ? queryable : queryable.Include(x => x.Contributors); } + + public static IQueryable IncludeDetails(this IQueryable queryable, bool include = true) + { + return !include ? queryable : queryable.Include(x => x.PdfFiles); + } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs index e85f9b4aa5..69ab6f7b1d 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/IDocsDbContext.cs @@ -16,5 +16,7 @@ namespace Volo.Docs.EntityFrameworkCore DbSet Documents { get; } DbSet DocumentContributors { get; } + + DbSet ProjectPdfFiles { get; set; } } } diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs index cbdf4cec06..e7db47335c 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs @@ -19,9 +19,14 @@ namespace Volo.Docs.Projects { } - public virtual async Task> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync( + string sorting, + int maxResultCount, + int skipCount, + bool includeDetails = false, + CancellationToken cancellationToken = default) { - var projects = await (await GetDbSetAsync()).OrderBy(sorting.IsNullOrEmpty() ? "Id desc" : sorting) + var projects = await (await GetDbSetAsync()).IncludeDetails(includeDetails).OrderBy(sorting.IsNullOrEmpty() ? "Id desc" : sorting) .PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -64,5 +69,10 @@ namespace Volo.Docs.Projects { return shortName.ToLower(); } + + public async override Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/DocsDocumentClientProxy.Generated.cs similarity index 100% rename from modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentClientProxy.Generated.cs rename to modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/DocsDocumentClientProxy.Generated.cs diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentClientProxy.cs b/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/DocsDocumentClientProxy.cs similarity index 100% rename from modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/Volo/Docs/Documents/DocsDocumentClientProxy.cs rename to modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/DocsDocumentClientProxy.cs diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json b/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json index 13e9ebffb2..717e94c04f 100644 --- a/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json +++ b/modules/docs/src/Volo.Docs.HttpApi.Client/ClientProxies/docs-generate-proxy.json @@ -4,206 +4,95 @@ "rootPath": "docs", "remoteServiceName": "AbpDocs", "controllers": { - "Volo.Docs.Projects.DocsProjectController": { - "controllerName": "DocsProject", - "controllerGroupName": "Project", + "Volo.Docs.Areas.Documents.DocumentNavigationController": { + "controllerName": "DocumentNavigation", + "controllerGroupName": "DocumentNavigation", "isRemoteService": true, "isIntegrationService": false, "apiVersion": null, - "type": "Volo.Docs.Projects.DocsProjectController", - "interfaces": [ - { - "type": "Volo.Docs.Projects.IProjectAppService", - "name": "IProjectAppService", - "methods": [ - { - "name": "GetListAsync", - "parametersOnMethod": [], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - } - }, - { - "name": "GetAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Docs.Projects.ProjectDto", - "typeSimple": "Volo.Docs.Projects.ProjectDto" - } - }, - { - "name": "GetVersionsAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - } - }, - { - "name": "GetDefaultLanguageCodeAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - }, - { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "System.String", - "typeSimple": "string" - } - }, - { - "name": "GetLanguageListAsync", - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - }, - { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Docs.Documents.LanguageConfig", - "typeSimple": "Volo.Docs.Documents.LanguageConfig" - } - } - ] - } - ], + "type": "Volo.Docs.Areas.Documents.DocumentNavigationController", + "interfaces": [], "actions": { - "GetListAsync": { - "uniqueName": "GetListAsync", - "name": "GetListAsync", - "httpMethod": "GET", - "url": "api/docs/projects", - "supportedVersions": [], - "parametersOnMethod": [], - "parameters": [], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - }, - "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetAsyncByShortName": { - "uniqueName": "GetAsyncByShortName", - "name": "GetAsync", + "GetNavigationAsyncByInput": { + "uniqueName": "GetNavigationAsyncByInput", + "name": "GetNavigationAsync", "httpMethod": "GET", - "url": "api/docs/projects/{shortName}", + "url": "docs/document-navigation", "supportedVersions": [], "parametersOnMethod": [ { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", + "name": "input", + "typeAsString": "Volo.Docs.Areas.Models.DocumentNavigation.GetNavigationNodeWithLinkModel, Volo.Docs.Web", + "type": "Volo.Docs.Areas.Models.DocumentNavigation.GetNavigationNodeWithLinkModel", + "typeSimple": "Volo.Docs.Areas.Models.DocumentNavigation.GetNavigationNodeWithLinkModel", "isOptional": false, "defaultValue": null } ], "parameters": [ { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "ProjectId", + "jsonName": null, + "type": "System.Guid", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Version", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" - } - ], - "returnValue": { - "type": "Volo.Docs.Projects.ProjectDto", - "typeSimple": "Volo.Docs.Projects.ProjectDto" - }, - "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetDefaultLanguageCodeAsyncByShortNameAndVersion": { - "uniqueName": "GetDefaultLanguageCodeAsyncByShortNameAndVersion", - "name": "GetDefaultLanguageCodeAsync", - "httpMethod": "GET", - "url": "api/docs/projects/{shortName}/defaultLanguage", - "supportedVersions": [], - "parametersOnMethod": [ + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", + "nameOnMethod": "input", + "name": "LanguageCode", + "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, - "defaultValue": null + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", + "nameOnMethod": "input", + "name": "ProjectName", + "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, - "defaultValue": null - } - ], - "parameters": [ + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "ProjectFormat", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "nameOnMethod": "version", - "name": "version", + "nameOnMethod": "input", + "name": "RouteVersion", "jsonName": null, "type": "System.String", "typeSimple": "string", @@ -211,109 +100,99 @@ "defaultValue": null, "constraintTypes": null, "bindingSourceId": "ModelBinding", - "descriptorName": "" + "descriptorName": "input" } ], "returnValue": { - "type": "System.String", - "typeSimple": "string" + "type": "Volo.Docs.Documents.NavigationNode", + "typeSimple": "Volo.Docs.Documents.NavigationNode" }, "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetVersionsAsyncByShortName": { - "uniqueName": "GetVersionsAsyncByShortName", - "name": "GetVersionsAsync", + "implementFrom": "Volo.Docs.Areas.Documents.DocumentNavigationController" + } + } + }, + "Volo.Docs.Areas.Documents.DocumentResourceController": { + "controllerName": "DocumentResource", + "controllerGroupName": "DocumentResource", + "isRemoteService": true, + "isIntegrationService": false, + "apiVersion": null, + "type": "Volo.Docs.Areas.Documents.DocumentResourceController", + "interfaces": [], + "actions": { + "GetResourceByInput": { + "uniqueName": "GetResourceByInput", + "name": "GetResource", "httpMethod": "GET", - "url": "api/docs/projects/{shortName}/versions", + "url": "document-resources", "supportedVersions": [], "parametersOnMethod": [ { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", + "name": "input", + "typeAsString": "Volo.Docs.Documents.GetDocumentResourceInput, Volo.Docs.Application.Contracts", + "type": "Volo.Docs.Documents.GetDocumentResourceInput", + "typeSimple": "Volo.Docs.Documents.GetDocumentResourceInput", "isOptional": false, "defaultValue": null } ], "parameters": [ { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "ProjectId", "jsonName": null, - "type": "System.String", + "type": "System.Guid", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" - } - ], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - }, - "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" - }, - "GetLanguageListAsyncByShortNameAndVersion": { - "uniqueName": "GetLanguageListAsyncByShortNameAndVersion", - "name": "GetLanguageListAsync", - "httpMethod": "GET", - "url": "api/docs/projects/{shortName}/{version}/languageList", - "supportedVersions": [], - "parametersOnMethod": [ - { - "name": "shortName", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "name": "version", - "typeAsString": "System.String, System.Private.CoreLib", + "nameOnMethod": "input", + "name": "Name", + "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, - "defaultValue": null - } - ], - "parameters": [ + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, { - "nameOnMethod": "shortName", - "name": "shortName", + "nameOnMethod": "input", + "name": "Version", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" }, { - "nameOnMethod": "version", - "name": "version", + "nameOnMethod": "input", + "name": "LanguageCode", "jsonName": null, "type": "System.String", "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { - "type": "Volo.Docs.Documents.LanguageConfig", - "typeSimple": "Volo.Docs.Documents.LanguageConfig" + "type": "Microsoft.AspNetCore.Mvc.FileResult", + "typeSimple": "Microsoft.AspNetCore.Mvc.FileResult" }, "allowAnonymous": null, - "implementFrom": "Volo.Docs.Projects.IProjectAppService" + "implementFrom": "Volo.Docs.Areas.Documents.DocumentResourceController" } } }, diff --git a/modules/docs/src/Volo.Docs.HttpApi.Client/Volo.Docs.HttpApi.Client.abppkg b/modules/docs/src/Volo.Docs.HttpApi.Client/Volo.Docs.HttpApi.Client.abppkg index 7deef5e383..f32651686a 100644 --- a/modules/docs/src/Volo.Docs.HttpApi.Client/Volo.Docs.HttpApi.Client.abppkg +++ b/modules/docs/src/Volo.Docs.HttpApi.Client/Volo.Docs.HttpApi.Client.abppkg @@ -1,3 +1,15 @@ { - "role": "lib.http-api-client" + "role": "lib.http-api-client", + "proxies": { + "csharp": { + "VoloDocs.Web-docs": { + "applicationName": "VoloDocs.Web", + "module": "docs", + "url": "https://localhost:5001", + "folder": "ClientProxies", + "serviceType": "all", + "withoutContracts": true + } + } + } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs index af54bd6bc5..95b2ed0244 100644 --- a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs @@ -20,7 +20,12 @@ namespace Volo.Docs.Projects { } - public virtual async Task> GetListAsync(string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync( + string sorting, + int maxResultCount, + int skipCount, + bool includeDetails = false, + CancellationToken cancellationToken = default) { var projects = await (await GetQueryableAsync(cancellationToken)).OrderBy(sorting.IsNullOrEmpty() ? "Id desc" : sorting).PageBy(skipCount, maxResultCount) .ToListAsync(GetCancellationToken(cancellationToken)); diff --git a/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs index a4c4c7647e..e0a383e691 100644 --- a/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Web/DocsWebAutoMapperProfile.cs @@ -1,6 +1,4 @@ using AutoMapper; -using Volo.Abp.AutoMapper; -using Volo.Docs.Documents; namespace Volo.Docs { @@ -8,7 +6,6 @@ namespace Volo.Docs { public DocsWebAutoMapperProfile() { - } } } diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs deleted file mode 100644 index d3ea14921c..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Docs.HtmlConverting -{ - public class DocumentPartialTemplateWithValuesDto - { - public string Path { get; set; } - - public Dictionary Parameters { get; set; } - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs deleted file mode 100644 index 7d9f26832f..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentRenderParameters.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Docs.HtmlConverting -{ - public class DocumentRenderParameters : Dictionary - { - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs new file mode 100644 index 0000000000..53a5c4d631 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterContext.cs @@ -0,0 +1,26 @@ +using Volo.Docs.Common.Projects; +using Volo.Docs.Documents; + +namespace Volo.Docs.HtmlConverting; + +public class DocumentToHtmlConverterContext +{ + public ProjectDto Project { get; set; } + public DocumentWithDetailsDto Document { get; set; } + public string Version { get; set; } + public string LanguageCode { get; set; } + public string ProjectShortName { get; set; } + + public DocumentToHtmlConverterContext(ProjectDto project, + DocumentWithDetailsDto document, + string version, + string languageCode, + string projectShortName = null) + { + Project = project; + Document = document; + Version = version; + LanguageCode = languageCode; + ProjectShortName = projectShortName; + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs deleted file mode 100644 index f332f6f58a..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentToHtmlConverterOptions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Volo.Docs.HtmlConverting -{ - public class DocumentToHtmlConverterOptions - { - public Dictionary Converters { get; set; } - - public DocumentToHtmlConverterOptions() - { - Converters = new Dictionary(); - } - } -} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs deleted file mode 100644 index 73560a7273..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace Volo.Docs.HtmlConverting -{ - public interface IDocumentSectionRenderer: ITransientDependency - { - Task RenderAsync(string doucment, DocumentRenderParameters parameters = null, List partialTemplates = null); - - Task>> GetAvailableParametersAsync(string document); - - Task> GetPartialTemplatesInDocumentAsync(string documentContent); - - Task GetDocumentNavigationsAsync(string documentContent); - } -} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs deleted file mode 100644 index efe145cac2..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverter.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Volo.Docs.Documents; -using Volo.Docs.Projects; - -namespace Volo.Docs.HtmlConverting -{ - public interface IDocumentToHtmlConverter - { - string Convert(ProjectDto project, DocumentWithDetailsDto document, string version, string languageCode, string projectShortName = null); - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs deleted file mode 100644 index 9cdca43a8f..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentToHtmlConverterFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.Docs.HtmlConverting -{ - public interface IDocumentToHtmlConverterFactory - { - IDocumentToHtmlConverter Create(string format); - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs new file mode 100644 index 0000000000..b485c7b132 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Documents.Rendering; + +namespace Volo.Docs.HtmlConverting +{ + public interface IWebDocumentSectionRenderer: IDocumentSectionRenderer + { + Task> GetPartialTemplatesInDocumentAsync(string documentContent); + + Task GetDocumentNavigationsAsync(string documentContent); + } +} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs deleted file mode 100644 index e8d0149cf8..0000000000 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Scriban; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Volo.Abp; -using Volo.Extensions; - -namespace Volo.Docs.HtmlConverting -{ - public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer - { - private readonly static List DocsJsonSections = new List - { - new DocsJsonSection("````json", "````"), - new DocsJsonSection("```json", "```") - }; - private const string DocsParam = "//[doc-params]"; - private const string DocsTemplates = "//[doc-template]"; - private const string DocsNav = "//[doc-nav]"; - - public ILogger Logger { get; set; } - - public ScribanDocumentSectionRenderer() - { - Logger = NullLogger.Instance; - } - - public async Task RenderAsync(string document, DocumentRenderParameters parameters = null, List partialTemplates = null) - { - if (partialTemplates != null && partialTemplates.Any()) - { - document = SetPartialTemplates(document, partialTemplates); - } - - var scribanTemplate = Template.Parse(document); - - if (parameters == null) - { - return await scribanTemplate.RenderAsync(); - } - - var result = await scribanTemplate.RenderAsync(parameters); - - return RemoveOptionsJson(result, DocsParam, DocsNav); - } - - public Task>> GetAvailableParametersAsync(string document) - { - return GetSectionAsync>>(document, DocsParam); - } - - public Task GetDocumentNavigationsAsync(string documentContent) - { - return GetSectionAsync(documentContent, DocsNav); - } - - protected virtual async Task GetSectionAsync(string document, string sectionName) where T : new() - { - try - { - if (!HasJsonSection(document) || !document.Contains(sectionName)) - { - return new T(); - } - - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, _) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); - - if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) - { - return new T(); - } - - var pureJson = insideJsonSection.Replace(sectionName, "").Trim(); - - if (!DocsJsonSerializerHelper.TryDeserialize(pureJson, out var section)) - { - throw new UserFriendlyException($"ERROR-20200327: Cannot validate JSON content for `{sectionName}`!"); - } - - return await Task.FromResult(section); - } - catch (Exception) - { - Logger.LogWarning("Unable to parse parameters of document."); - return new T(); - } - } - - private static string RemoveOptionsJson(string document, params string[] sectionNames) - { - - foreach (var sectionName in sectionNames) - { - var orgDocument = document; - - try - { - if (!HasJsonSection(document) || !document.Contains(sectionName)) - { - continue; - } - - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, jsonSection) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); - - if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) - { - continue; - } - - document = document.Remove( - jsonBeginningIndex - jsonSection.Opener.Length, - (jsonEndingIndex + jsonSection.Closer.Length) - (jsonBeginningIndex - jsonSection.Opener.Length) - ); - } - catch (Exception) - { - document = orgDocument; - } - } - - return document; - } - - private static bool HasJsonSection(string document) - { - return DocsJsonSections.Any(section => document.Contains(section.Opener) && document.Contains(section.Closer)); - } - - private static (int, int, string, DocsJsonSection) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) - { - foreach (var section in DocsJsonSections) - { - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = section.GetJsonBeginEndIndexesAndPureJson(document, sectionName); - - if (jsonBeginningIndex >= 0 && jsonEndingIndex > 0 && !string.IsNullOrWhiteSpace(insideJsonSection)) - { - return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection, section); - } - } - - return (-1, -1, "", null); - } - - public async Task> GetPartialTemplatesInDocumentAsync(string documentContent) - { - var templates = new List(); - - foreach (var section in DocsJsonSections) - { - templates.AddRange(await section.GetPartialTemplatesInDocumentAsync(documentContent)); - } - - return templates; - } - - private static string SetPartialTemplates(string document, IReadOnlyCollection templates) - { - foreach (var section in DocsJsonSections) - { - document = section.SetPartialTemplates(document, templates); - } - - return document; - } - - private class DocsJsonSection - { - public string Opener { get; } - public string Closer { get; } - - public DocsJsonSection(string opener, string closer) - { - Opener = opener; - Closer = closer; - } - - public (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) - { - var searchedIndex = 0; - - while (searchedIndex < document.Length) - { - var jsonBeginningIndex = document.Substring(searchedIndex).IndexOf(Opener, StringComparison.Ordinal); - - if (jsonBeginningIndex < 0) - { - return (-1, -1, ""); - } - - jsonBeginningIndex += Opener.Length + searchedIndex; - - var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(Closer, StringComparison.Ordinal); - if (jsonEndingIndex < 0) - { - return (-1, -1, ""); - } - - jsonEndingIndex += jsonBeginningIndex; - var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex]; - - if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) - { - searchedIndex = jsonEndingIndex + Closer.Length; - continue; - } - - return (jsonBeginningIndex, jsonEndingIndex, insideJsonSection); - } - - return (-1, -1, ""); - } - - public async Task> GetPartialTemplatesInDocumentAsync( - string documentContent) - { - var templates = new List(); - - while (documentContent.Contains(Opener)) - { - var afterJsonOpener = documentContent.Substring( - documentContent.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length - ); - - var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) - ); - - documentContent = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length - ); - - if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) - { - continue; - } - - var json = betweenJsonOpenerAndCloser.Substring( - betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + - DocsTemplates.Length); - - if (!DocsJsonSerializerHelper.TryDeserialize(json, - out var template)) - { - throw new UserFriendlyException( - $"ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); - } - - templates.Add(template); - } - - return await Task.FromResult(templates); - } - - public string SetPartialTemplates(string document, - IReadOnlyCollection templates) - { - var newDocument = new StringBuilder(); - - while (document.Contains(Opener)) - { - var beforeJson = document.Substring(0, - document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length - ); - - var afterJsonOpener = document.Substring( - document.IndexOf(Opener, StringComparison.Ordinal) + Opener.Length - ); - - var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) - ); - - if (!betweenJsonOpenerAndCloser.Contains(DocsTemplates)) - { - document = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length - ); - - newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + Closer); - continue; - } - - var json = betweenJsonOpenerAndCloser.Substring( - betweenJsonOpenerAndCloser.IndexOf(DocsTemplates, StringComparison.Ordinal) + - DocsTemplates.Length - ); - - if (DocsJsonSerializerHelper.TryDeserialize(json, - out var documentPartialTemplateWithValuesDto)) - { - var template = - templates.FirstOrDefault(t => t.Path == documentPartialTemplateWithValuesDto.Path); - - var beforeTemplate = document.Substring(0, - document.IndexOf(Opener, StringComparison.Ordinal) - ); - - newDocument.Append(beforeTemplate + template?.Content + Closer); - - document = afterJsonOpener.Substring( - afterJsonOpener.IndexOf(Closer, StringComparison.Ordinal) + Closer.Length - ); - } - } - - newDocument.Append(document); - - return newDocument.ToString(); - } - } - } -} diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs new file mode 100644 index 0000000000..e4a26b2df6 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Scriban; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp; +using Volo.Abp.ObjectMapping; +using Volo.Docs.Documents.Rendering; +using Volo.Extensions; + +namespace Volo.Docs.HtmlConverting +{ + public class ScribanWebDocumentSectionRenderer : ScribanDocumentSectionRenderer, IWebDocumentSectionRenderer + { + private IObjectMapper ObjectMapper { get; set; } + + public Task GetDocumentNavigationsAsync(string documentContent) + { + return GetSectionAsync(documentContent, DocsNav); + } + + public async Task> GetPartialTemplatesInDocumentAsync( + string documentContent) + { + var templates = new List(); + + foreach (var section in DocsJsonSections) + { + templates.AddRange(await section.GetPartialTemplatesInDocumentAsync(documentContent)); + } + + return templates; + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs index 55a9eacb37..54df0c4440 100644 --- a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs @@ -1,20 +1,16 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Net; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; using Volo.Docs.HtmlConverting; -using Volo.Docs.Pages.Documents.Project; -using Volo.Docs.Projects; using Volo.Docs.Utils; namespace Volo.Docs.Markdown { - public class MarkdownDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency + public class MarkdownDocumentToHtmlConverter : IDocumentToHtmlConverter, ITransientDependency { public const string Type = "md"; @@ -34,20 +30,19 @@ namespace Volo.Docs.Markdown private const string MarkdownLinkRegExp = @"\[(.*?)\]\(((.*?)(\?(.*?))*?)\)"; private const string AnchorLinkRegExp = @"]+href=\""(.*?)\""[^>]*>(.*)?"; - public virtual string Convert(ProjectDto project, DocumentWithDetailsDto document, string version, - string languageCode, string projectShortName = null) + public virtual string Convert(DocumentToHtmlConverterContext context) { - if (document.Content.IsNullOrEmpty()) + if (context.Document.Content.IsNullOrEmpty()) { - return document.Content; + return context.Document.Content; } var content = NormalizeLinks( - document.Content, - _uiOptions.SingleProjectMode.Enable ? projectShortName : projectShortName ?? project.ShortName, - version, - document.LocalDirectory, - !_uiOptions.MultiLanguageMode ? languageCode : languageCode ?? document.LanguageCode + context.Document.Content, + _uiOptions.SingleProjectMode.Enable ? context.ProjectShortName : context.ProjectShortName ?? context.Project.ShortName, + context.Version, + context.Document.LocalDirectory, + !_uiOptions.MultiLanguageMode ? context.LanguageCode : context.LanguageCode ?? context.Document.LanguageCode ); var html = _markdownConverter.ConvertToHtml(content); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs index 1146b3cb63..c00ebf32d6 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Options; -using Volo.Docs.Projects; +using Volo.Docs.Common.Projects; namespace Volo.Docs.Pages.Documents { diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index fb1f232cb3..21d4aab5ac 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -71,6 +71,7 @@ + @@ -290,6 +291,14 @@ id="sidebar-scroll" class="nav nav-list"> + @if (Model.HasDownloadPdf) + { + + } } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 2bb7c82c21..8ffe5c4c7a 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -10,15 +10,18 @@ using System.Web; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; using Volo.Abp.EventBus.Local; +using Volo.Docs.Common; +using Volo.Docs.Common.Documents; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; +using Volo.Docs.Documents.Rendering; using Volo.Docs.HtmlConverting; using Volo.Docs.Models; using Volo.Docs.Projects; @@ -89,6 +92,8 @@ namespace Volo.Docs.Pages.Documents.Project public bool FullSearchEnabled { get; set; } public bool IsLatestVersion { get; private set; } + + public bool HasDownloadPdf { get; set; } public DocumentNavigationsDto DocumentNavigationsDto { get; private set; } @@ -96,8 +101,10 @@ namespace Volo.Docs.Pages.Documents.Project private readonly IDocumentAppService _documentAppService; private readonly IDocumentToHtmlConverterFactory _documentToHtmlConverterFactory; private readonly IProjectAppService _projectAppService; - private readonly IDocumentSectionRenderer _documentSectionRenderer; + private readonly IWebDocumentSectionRenderer _webDocumentSectionRenderer; private readonly DocsUiOptions _uiOptions; + private readonly IPermissionChecker _permissionChecker; + private readonly IDocumentPdfAppService _documentPdfAppService; protected IDocsLinkGenerator DocsLinkGenerator => LazyServiceProvider.LazyGetRequiredService(); @@ -108,17 +115,20 @@ namespace Volo.Docs.Pages.Documents.Project IDocumentToHtmlConverterFactory documentToHtmlConverterFactory, IProjectAppService projectAppService, IOptions options, - IDocumentSectionRenderer documentSectionRenderer) + IWebDocumentSectionRenderer webDocumentSectionRenderer, + IPermissionChecker permissionChecker, + IDocumentPdfAppService documentPdfAppService) { ObjectMapperContext = typeof(DocsWebModule); _documentAppService = documentAppService; _documentToHtmlConverterFactory = documentToHtmlConverterFactory; _projectAppService = projectAppService; - _documentSectionRenderer = documentSectionRenderer; + _webDocumentSectionRenderer = webDocumentSectionRenderer; + _permissionChecker = permissionChecker; + _documentPdfAppService = documentPdfAppService; _uiOptions = options.Value; - - + LocalizationResourceType = typeof(DocsResource); } @@ -136,7 +146,7 @@ namespace Volo.Docs.Pages.Documents.Project { return RedirectPermanent(redirectUrl); } - + return await SetPageAsync(); } @@ -146,7 +156,7 @@ namespace Volo.Docs.Pages.Documents.Project ShowProjectsCombobox = _uiOptions.ShowProjectsCombobox && !_uiOptions.SingleProjectMode.Enable; ShowProjectsComboboxLabel = ShowProjectsCombobox && _uiOptions.ShowProjectsComboboxLabel; FullSearchEnabled = await _documentAppService.FullSearchEnabledAsync(); - + try { await SetProjectAsync(); @@ -204,6 +214,12 @@ namespace Volo.Docs.Pages.Documents.Project await SetNavigationAsync(); SetLanguageSelectListItems(); + HasDownloadPdf = await _permissionChecker.IsGrantedAsync(DocsCommonPermissions.Projects.PdfDownload) + && await _documentPdfAppService.ExistsAsync(new() + { + ProjectId = Project.Id, Version = LatestVersionInfo.IsSelected ? LatestVersionInfo.Version : Version, LanguageCode = DocumentLanguageCode + }); + return Page(); } @@ -561,11 +577,11 @@ namespace Volo.Docs.Pages.Documents.Project var partialTemplates = await GetDocumentPartialTemplatesAsync(); - DocumentNavigationsDto = await _documentSectionRenderer.GetDocumentNavigationsAsync(Document.Content); + DocumentNavigationsDto = await _webDocumentSectionRenderer.GetDocumentNavigationsAsync(Document.Content); try { - Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); + Document.Content = await _webDocumentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); } catch (Exception e) { @@ -577,8 +593,8 @@ namespace Volo.Docs.Pages.Documents.Project DocumentNavigationsDto = new DocumentNavigationsDto(); } - var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); - var content = converter.Convert(Project, Document, GetSpecificVersionOrLatest(), LanguageCode, ProjectName); + var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); + var content = converter.Convert(new DocumentToHtmlConverterContext(Project, Document, GetSpecificVersionOrLatest(), LanguageCode, ProjectName)); content = HtmlNormalizer.ReplaceImageSources( content, @@ -619,7 +635,7 @@ namespace Volo.Docs.Pages.Documents.Project private async Task> GetDocumentPartialTemplatesAsync() { - var partialTemplatesInDocument = await _documentSectionRenderer.GetPartialTemplatesInDocumentAsync(Document.Content); + var partialTemplatesInDocument = await _webDocumentSectionRenderer.GetPartialTemplatesInDocumentAsync(Document.Content); if (!partialTemplatesInDocument?.Any(t => t.Parameters != null) ?? true) { @@ -772,7 +788,7 @@ namespace Volo.Docs.Pages.Documents.Project return; } - var availableParameters = await _documentSectionRenderer.GetAvailableParametersAsync(Document.Content); + var availableParameters = await _webDocumentSectionRenderer.GetAvailableParametersAsync(Document.Content); DocumentPreferences = new DocumentParametersDto { @@ -813,7 +829,7 @@ namespace Volo.Docs.Pages.Documents.Project { if (!DocumentPreferences?.Parameters?.Any() ?? true) { - return; + return; } AlternativeOptionLinkQueries = CollectAlternativeOptionLinksRecursively(); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css index e8d0a035a0..dc720fba6d 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css @@ -45,4 +45,18 @@ body { outline: none; } +.docs-sidebar-footer { + border-block-start: 1px solid #aaa; + border-block-end: 1px solid #aaa; +} + +.download-pdf-btn { + text-align: left; + width: 100%; + color: #aaa; + background-color: #0000; + border-color:#0000; + font-size: 14px; +} + /*# sourceMappingURL=Index.css.map */ diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js index 23eca169b5..d55d9f2ef9 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js @@ -421,5 +421,12 @@ var doc = doc || {}; return originalSet.call(this, key, value); }; + $('#DownloadPdfBtn').click(function () { + var url = $(this).data('url'); + if (url) { + window.open(url, '_blank'); + } + }); + }); })(jQuery); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss index 426dec284c..9589b1fb73 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss @@ -6,9 +6,9 @@ } } -.input-group{ - .input-group-text{ - background-color: transparent!important; +.input-group { + .input-group-text { + background-color: transparent !important; } } @@ -16,10 +16,12 @@ .next-link, .prev-link { .desc { color: #0D6EFD; - .fa{ + + .fa { font-size: 12px; } } + .title { font-weight: 600; font-size: 18px; @@ -27,3 +29,46 @@ } } } + +body { + top: 0px !important; +} + +.skiptranslate { + iframe { + display: none !important; + } +} + +.google_translate_text { + color: #aaa; + font-family: var(--bs-body-font-family); + font-size: 10pt; + margin-left: 2px; + font-weight: 500; +} + +.goog-te-gadget { + white-space: break-spaces !important; +} + +.goog-te-combo { + &:focus-visible { + border: 0px; + outline: none; + } +} + +.docs-sidebar-footer { + border-block-start: 1px solid #aaa; + border-block-end: 1px solid #aaa; +} + +.download-pdf-btn { + text-align: left; + width: 100%; + color: #aaa; + background-color: transparent; + border-color: transparent; + font-size: 14px; +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs index 7be35394ae..ad60019b57 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Search.cshtml.cs @@ -3,18 +3,15 @@ using System.Collections.Generic; using System.Linq; using System.Text.Encodings.Web; using System.Threading.Tasks; -using System.Web; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; using Volo.Abp.Data; +using Volo.Docs.Common.Projects; using Volo.Docs.Documents; using Volo.Docs.GitHub.Documents.Version; -using Volo.Docs.HtmlConverting; -using Volo.Docs.Models; using Volo.Docs.Projects; -using Volo.Docs.Utils; namespace Volo.Docs.Pages.Documents { diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css index 32017cd466..36ca24e100 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css @@ -219,7 +219,7 @@ body.scrolledMore .alert-criteria p.alert-p { } .docs-page .docs-sidebar .docs-tree-list > ul { display: block; - height: calc(100vh - 310px); + height: calc(100vh - 350px); overflow-y: auto; margin-right: -4px !important; margin-top: 20px !important; diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss index 6c2c4c7627..deba3d39c3 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss @@ -268,7 +268,7 @@ body { > ul { display: block; - height: calc(100vh - 310px); + height: calc(100vh - 350px); overflow-y: auto; margin-right: -4px !important; margin-top: 20px !important; diff --git a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.abppkg b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.abppkg index 8f16736603..f25f6f3d3e 100644 --- a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.abppkg +++ b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.abppkg @@ -2,7 +2,18 @@ "role": "lib.mvc", "npmDependencies": { "@abp/docs": { - "version": "" + "version": "" + } + }, + "proxies": { + "Javascript": { + "VoloDocs.Web-docs": { + "applicationName": "VoloDocs.Web", + "module": "docs", + "url": "https://localhost:5001", + "output": "wwwroot/client-proxies/", + "serviceType": "application" + } } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj index 1d6e0e1ace..2c36600107 100644 --- a/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj +++ b/modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj @@ -23,7 +23,7 @@ - + diff --git a/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js new file mode 100644 index 0000000000..014e357cba --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-common-proxy.js @@ -0,0 +1,68 @@ +/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */ + + +// module docs-common + +(function(){ + + // controller volo.docs.documents.docsDocumentPdfGenerator + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.documents.docsDocumentPdfGenerator'); + + volo.docs.documents.docsDocumentPdfGenerator.generatePdf = function(input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/documents/pdf' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + })(); + + // controller volo.docs.projects.docsProject + + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.projects.docsProject'); + + volo.docs.projects.docsProject.getList = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.get = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getDefaultLanguageCode = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/defaultLanguage' + abp.utils.buildQueryString([{ name: 'version', value: version }]) + '', + type: 'GET' + }, { dataType: 'text' }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getVersions = function(shortName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/versions', + type: 'GET' + }, ajaxParams)); + }; + + volo.docs.projects.docsProject.getLanguageList = function(shortName, version, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/docs/projects/' + shortName + '/' + version + '/languageList', + type: 'GET' + }, ajaxParams)); + }; + + })(); + +})(); + + diff --git a/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js index 3195d15cd6..32bcf101cb 100644 --- a/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js +++ b/modules/docs/src/Volo.Docs.Web/wwwroot/client-proxies/docs-proxy.js @@ -5,43 +5,30 @@ (function(){ - // controller volo.docs.projects.docsProject + // controller volo.docs.areas.documents.documentNavigation (function(){ - abp.utils.createNamespace(window, 'volo.docs.projects.docsProject'); + abp.utils.createNamespace(window, 'volo.docs.areas.documents.documentNavigation'); - volo.docs.projects.docsProject.getList = function(ajaxParams) { + volo.docs.areas.documents.documentNavigation.getNavigation = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects', + url: abp.appPath + 'docs/document-navigation' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }, { name: 'projectName', value: input.projectName }, { name: 'projectFormat', value: input.projectFormat }, { name: 'routeVersion', value: input.routeVersion }]) + '', type: 'GET' }, ajaxParams)); }; - volo.docs.projects.docsProject.get = function(shortName, ajaxParams) { - return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '', - type: 'GET' - }, ajaxParams)); - }; + })(); - volo.docs.projects.docsProject.getDefaultLanguageCode = function(shortName, version, ajaxParams) { - return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '/defaultLanguage' + abp.utils.buildQueryString([{ name: 'version', value: version }]) + '', - type: 'GET' - }, { dataType: 'text' }, ajaxParams)); - }; + // controller volo.docs.areas.documents.documentResource - volo.docs.projects.docsProject.getVersions = function(shortName, ajaxParams) { - return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '/versions', - type: 'GET' - }, ajaxParams)); - }; + (function(){ + + abp.utils.createNamespace(window, 'volo.docs.areas.documents.documentResource'); - volo.docs.projects.docsProject.getLanguageList = function(shortName, version, ajaxParams) { + volo.docs.areas.documents.documentResource.getResource = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/docs/projects/' + shortName + '/' + version + '/languageList', + url: abp.appPath + 'document-resources' + abp.utils.buildQueryString([{ name: 'projectId', value: input.projectId }, { name: 'name', value: input.name }, { name: 'version', value: input.version }, { name: 'languageCode', value: input.languageCode }]) + '', type: 'GET' }, ajaxParams)); }; diff --git a/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs b/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs index 8f92c414c1..662db4c6aa 100644 --- a/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs +++ b/modules/docs/test/Volo.Docs.Application.Tests/Volo/Docs/ApplicationService_Tests.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; using Shouldly; -using Volo.Docs.Projects; +using Volo.Docs.Common.Projects; using Xunit; namespace Volo.Docs diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor index 77f5018e10..a55e1cb026 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor @@ -17,12 +17,14 @@ - @foreach (var group in Groups) - { - - @group.DisplayName - - } +
+ @foreach (var group in Groups) + { + + @group.DisplayName + + } +
@for (var i = 0; i < Groups.Count; i++) @@ -35,12 +37,12 @@ {
@{ - var disabled = IsDisabled(feature.Provider.Name); + var disabled = IsDisabled(feature); if (feature.ValueType is FreeTextStringValueType) { - @feature.DisplayName + @GetShownName(feature) @@ -56,8 +58,8 @@ var items = ((SelectionStringValueType)feature.ValueType).ItemSource.Items; var selectedValue = SelectionStringValues[feature.Name]; - @feature.DisplayName - @foreach (var item in items) { @@ -75,8 +77,8 @@ if (feature.ValueType is ToggleStringValueType) { - - @feature.DisplayName + + @GetShownName(feature) @if (feature.Description != null) { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs index 0d0728db71..8a48db4b4a 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs @@ -150,9 +150,19 @@ public partial class FeatureManagementModal return $"margin-left: {feature.Depth * 20}px"; } - protected virtual bool IsDisabled(string providerName) + protected virtual bool IsDisabled(FeatureDto feature) { - return providerName != ProviderName && providerName != DefaultValueFeatureValueProvider.ProviderName; + return feature.Value != null && + feature.Provider.Name != null && + feature.Provider.Name != ProviderName && + feature.Provider.Name != DefaultValueFeatureValueProvider.ProviderName; + } + + public virtual string GetShownName(FeatureDto featureDto) + { + return !IsDisabled(featureDto) + ? featureDto.DisplayName + : $"{featureDto.DisplayName} ({featureDto.Provider.Name})"; } protected virtual async Task OnFeatureValueChangedAsync(string value, FeatureDto feature) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs index 82c1c98cb9..f9de4cbd1f 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs @@ -1,7 +1,9 @@ -using System.Security.Principal; +using System; +using System.Security.Principal; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; +using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; namespace Volo.Abp.FeatureManagement; @@ -11,22 +13,58 @@ public class EditionFeatureManagementProvider : FeatureManagementProvider, ITran public override string Name => EditionFeatureValueProvider.ProviderName; protected ICurrentPrincipalAccessor PrincipalAccessor { get; } + protected ITenantStore TenantStore { get; } + protected ICurrentTenant CurrentTenant { get; } + protected string CurrentCompatibleProviderName { get; set; } public EditionFeatureManagementProvider( IFeatureManagementStore store, - ICurrentPrincipalAccessor principalAccessor) + ICurrentPrincipalAccessor principalAccessor, + ITenantStore tenantStore, + ICurrentTenant currentTenant) : base(store) { PrincipalAccessor = principalAccessor; + TenantStore = tenantStore; + CurrentTenant = currentTenant; } - protected override Task NormalizeProviderKeyAsync(string providerKey) + public override bool Compatible(string providerName) { - if (providerKey != null) + CurrentCompatibleProviderName = providerName; + return providerName == TenantFeatureValueProvider.ProviderName || base.Compatible(providerName); + } + + protected async override Task NormalizeProviderKeyAsync(string providerKey) + { + return (await FindEditionIdAsync(providerKey))?.ToString(); + } + + protected virtual async Task FindEditionIdAsync(string providerKey) + { + if (Guid.TryParse(providerKey, out var parsedEditionOrTenantId)) + { + if (CurrentCompatibleProviderName == TenantFeatureValueProvider.ProviderName) + { + var tenant = await TenantStore.FindAsync(parsedEditionOrTenantId); + if (tenant != null) + { + return tenant?.EditionId; + } + } + + return parsedEditionOrTenantId; + } + + if (CurrentTenant.Id.HasValue) { - return Task.FromResult(providerKey); + var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()); + if (tenant != null) + { + return tenant?.EditionId; + } } - return Task.FromResult(PrincipalAccessor.Principal?.FindEditionId()?.ToString("N")); + return PrincipalAccessor.Principal?.FindEditionId(); } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs index 9805f03752..c105779546 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs @@ -152,7 +152,7 @@ public class FeatureManager : IFeatureManager, ISingletonDependency await using (await providers[0].HandleContextAsync(providerName, providerKey)) { var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null); - if (fallbackValue.Value == value) + if (string.Equals(fallbackValue.Value, value, StringComparison.OrdinalIgnoreCase)) { //Clear the value if it's same as it's fallback value value = null; diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml index 9c3ceca88f..f9823e0e58 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml @@ -21,6 +21,7 @@ } +
@@ -39,49 +40,45 @@

@featureGroup.DisplayName


-
+
@for (var j = 0; j < featureGroup.Features.Count; j++) { var feature = featureGroup.Features[j]; + var disabled = Model.IsDisabled(feature);
+ - @if (feature.ValueType is ToggleStringValueType) { - - @if (feature.Description != null) + type="checkbox" + class="d-inline" + abp-id-name="@Model.FeatureGroups[i].Features[j].BoolValue" + label="@Model.GetShownName(feature)" + disabled="disabled" + group-data-feature-name="@feature.Name" + group-data-parent-name="@(feature.ParentName ?? "")" + group-style="margin-inline-start: @(feature.Depth * 20)px"/> + if (feature.Description != null) {
@feature.Description
} - } @if (feature.ValueType is FreeTextStringValueType) { - var type = "text"; - if(feature.ValueType.Validator is NumericValueValidator) - { - type = "number"; - } - + var type = feature.ValueType.Validator is NumericValueValidator ? "number" : "text"; - @if (feature.Description != null) + label="@Model.GetShownName(feature)" + abp-id-name="@Model.FeatureGroups[i].Features[j].Value" + type="@type" + disabled="disabled" + group-data-feature-name="@feature.Name" + group-data-parent-name="@(feature.ParentName ?? "")" + group-style="margin-inline-start: @(feature.Depth * 25)px"/> + if (feature.Description != null) {
@feature.Description
} @@ -90,19 +87,12 @@ @if (feature.ValueType is SelectionStringValueType selectType) {
- - - @foreach (var item in selectType.ItemSource.Items) { - if (item.Value == feature.Value) - { - - } - else - { - - } + var selected = item.Value == feature.Value ? "selected=\"selected\"" : ""; + @CreateHtmlLocalizer(item.DisplayText.ResourceName).GetString(item.DisplayText.Name) } @if (feature.Description != null) @@ -111,8 +101,8 @@ }
} - +
}
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs index f08d42cfd2..eb27c63aae 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs @@ -25,9 +25,9 @@ public class FeatureManagementModal : AbpPageModel [HiddenInput] [BindProperty(SupportsGet = true)] public string ProviderKey { get; set; } - + [HiddenInput] - [BindProperty(SupportsGet = true)] + [BindProperty(SupportsGet = true)] public string ProviderKeyDisplayName { get; set; } [BindProperty] @@ -69,7 +69,7 @@ public class FeatureManagementModal : AbpPageModel { var features = new UpdateFeaturesDto { - Features = FeatureGroups.SelectMany(g => g.Features).Select(f => new UpdateFeatureDto + Features = FeatureGroups.SelectMany(g => g.Features).Where(x => !x.IsDisabled).Select(f => new UpdateFeatureDto { Name = f.Name, Value = f.Type == nameof(ToggleStringValueType) ? f.BoolValue.ToString() : f.Value @@ -85,6 +85,21 @@ public class FeatureManagementModal : AbpPageModel return NoContent(); } + public virtual bool IsDisabled(FeatureDto feature) + { + return feature.Value != null && + feature.Provider.Name != null && + feature.Provider.Name != ProviderName && + feature.Provider.Name != DefaultValueFeatureValueProvider.ProviderName; + } + + public virtual string GetShownName(FeatureDto featureDto) + { + return !IsDisabled(featureDto) + ? featureDto.DisplayName + : $"{featureDto.DisplayName} ({featureDto.Provider.Name})"; + } + public class FeatureGroupViewModel { public List Features { get; set; } @@ -92,6 +107,8 @@ public class FeatureManagementModal : AbpPageModel public class FeatureViewModel { + public bool IsDisabled { get; set; } + public string Name { get; set; } public string Value { get; set; } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.css b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.css new file mode 100644 index 0000000000..921a40b160 --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.css @@ -0,0 +1,11 @@ +#FeaturesTabsContent { + padding-top: 0 !important; +} + +.custom-scroll-content { + max-height: 400px; +} + +.custom-scroll-container > .col-md-4 { + max-height: 500px; +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js index fd9c654ae6..5595db7a47 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js @@ -88,7 +88,7 @@ var abp = abp || {}; $('.custom-scroll-content').mCustomScrollbar({ theme: 'minimal-dark', }); - $('.custom-scroll-container > .col-4').mCustomScrollbar({ + $('.custom-scroll-container > .col-md-4').mCustomScrollbar({ theme: 'minimal-dark', }); }); diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index a56935424e..582d9ade42 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; @@ -58,7 +59,7 @@ public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppSe { //TODO: Should also include roles of the related OUs. - var roles = await UserRepository.GetRolesAsync(id); + var roles = (await UserRepository.GetRolesAsync(id)).OrderBy(x => x.Name).ToList(); return new ListResultDto( ObjectMapper.Map, List>(roles) @@ -68,9 +69,8 @@ public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppSe [Authorize(IdentityPermissions.Users.Default)] public virtual async Task> GetAssignableRolesAsync() { - var list = await RoleRepository.GetListAsync(); - return new ListResultDto( - ObjectMapper.Map, List>(list)); + var list = (await RoleRepository.GetListAsync()).OrderBy(x => x.Name).ToList(); + return new ListResultDto(ObjectMapper.Map, List>(list)); } [Authorize(IdentityPermissions.Users.Create)] diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/package.json b/modules/openiddict/app/OpenIddict.Demo.Server/package.json index 8bcd4ab173..a7b7d09091 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/package.json +++ b/modules/openiddict/app/OpenIddict.Demo.Server/package.json @@ -3,6 +3,6 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1" } } diff --git a/modules/openiddict/app/angular/package.json b/modules/openiddict/app/angular/package.json index 5829ce8bfd..a21c4c8dc1 100644 --- a/modules/openiddict/app/angular/package.json +++ b/modules/openiddict/app/angular/package.json @@ -12,15 +12,15 @@ }, "private": true, "dependencies": { - "@abp/ng.account": "~9.2.0", - "@abp/ng.components": "~9.2.0", - "@abp/ng.core": "~9.2.0", - "@abp/ng.oauth": "~9.2.0", - "@abp/ng.identity": "~9.2.0", - "@abp/ng.setting-management": "~9.2.0", - "@abp/ng.tenant-management": "~9.2.0", - "@abp/ng.theme.shared": "~9.2.0", - "@abp/ng.theme.lepton-x": "~4.2.0", + "@abp/ng.account": "~9.3.0-rc.1", + "@abp/ng.components": "~9.3.0-rc.1", + "@abp/ng.core": "~9.3.0-rc.1", + "@abp/ng.oauth": "~9.3.0-rc.1", + "@abp/ng.identity": "~9.3.0-rc.1", + "@abp/ng.setting-management": "~9.3.0-rc.1", + "@abp/ng.tenant-management": "~9.3.0-rc.1", + "@abp/ng.theme.shared": "~9.3.0-rc.1", + "@abp/ng.theme.lepton-x": "~4.3.0-rc.1", "@angular/animations": "^15.0.1", "@angular/common": "^15.0.1", "@angular/compiler": "^15.0.1", @@ -36,7 +36,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@abp/ng.schematics": "~9.2.0", + "@abp/ng.schematics": "~9.3.0-rc.1", "@angular-devkit/build-angular": "^15.0.1", "@angular-eslint/builder": "~15.1.0", "@angular-eslint/eslint-plugin": "~15.1.0", diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs index 0b0dd59968..819d643a21 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs @@ -8,5 +8,7 @@ public interface IPermissionAppService : IApplicationService { Task GetAsync([NotNull] string providerName, [NotNull] string providerKey); + Task GetByGroupAsync([NotNull] string groupName, [NotNull] string providerName, [NotNull] string providerKey); + Task UpdateAsync([NotNull] string providerName, [NotNull] string providerKey, UpdatePermissionsDto input); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index aa9bfe0029..28abc4d75b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -33,6 +33,16 @@ public class PermissionAppService : ApplicationService, IPermissionAppService } public virtual async Task GetAsync(string providerName, string providerKey) + { + return await GetInternalAsync(null, providerName, providerKey); + } + + public virtual async Task GetByGroupAsync(string groupName, string providerName, string providerKey) + { + return await GetInternalAsync(groupName, providerName, providerKey); + } + + protected virtual async Task GetInternalAsync(string groupName, string providerName, string providerKey) { await CheckProviderPolicy(providerName); @@ -45,7 +55,7 @@ public class PermissionAppService : ApplicationService, IPermissionAppService var multiTenancySide = CurrentTenant.GetMultiTenancySide(); var permissionGroups = new List(); - foreach (var group in await PermissionDefinitionManager.GetGroupsAsync()) + foreach (var group in (await PermissionDefinitionManager.GetGroupsAsync()).WhereIf(!groupName.IsNullOrWhiteSpace(), x => x.Name == groupName)) { var groupDto = CreatePermissionGroupDto(group); var permissions = group.GetPermissionsWithChildren() @@ -108,7 +118,7 @@ public class PermissionAppService : ApplicationService, IPermissionAppService return result; } - protected virtual PermissionGrantInfoDto CreatePermissionGrantInfoDto(PermissionDefinition permission) + protected virtual PermissionGrantInfoDto CreatePermissionGrantInfoDto(PermissionDefinition permission) { return new PermissionGrantInfoDto { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs index c89b505da2..2fe22472f0 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs @@ -26,6 +26,16 @@ public partial class PermissionsClientProxy : ClientProxyBase GetByGroupAsync(string groupName, string providerName, string providerKey) + { + return await RequestAsync(nameof(GetByGroupAsync), new ClientProxyRequestTypeValue + { + { typeof(string), groupName }, + { typeof(string), providerName }, + { typeof(string), providerKey } + }); + } + public virtual async Task UpdateAsync(string providerName, string providerKey, UpdatePermissionsDto input) { await RequestAsync(nameof(UpdateAsync), new ClientProxyRequestTypeValue diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json index 2a57defab4..208271e67d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json @@ -4,6 +4,78 @@ "rootPath": "permissionManagement", "remoteServiceName": "AbpPermissionManagement", "controllers": { + "Volo.Abp.PermissionManagement.Integration.PermissionIntegrationController": { + "controllerName": "PermissionIntegration", + "controllerGroupName": "PermissionIntegration", + "isRemoteService": true, + "isIntegrationService": true, + "apiVersion": null, + "type": "Volo.Abp.PermissionManagement.Integration.PermissionIntegrationController", + "interfaces": [ + { + "type": "Volo.Abp.PermissionManagement.Integration.IPermissionIntegrationService", + "name": "IPermissionIntegrationService", + "methods": [ + { + "name": "IsGrantedAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=9.3.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + } + ] + } + ], + "actions": { + "IsGrantedAsyncByInput": { + "uniqueName": "IsGrantedAsyncByInput", + "name": "IsGrantedAsync", + "httpMethod": "GET", + "url": "integration-api/permission-management/permissions/is-granted", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=9.3.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.Integration.IPermissionIntegrationService" + } + } + }, "Volo.Abp.PermissionManagement.PermissionsController": { "controllerName": "Permissions", "controllerGroupName": "Permissions", @@ -41,6 +113,39 @@ "typeSimple": "Volo.Abp.PermissionManagement.GetPermissionListResultDto" } }, + { + "name": "GetByGroupAsync", + "parametersOnMethod": [ + { + "name": "groupName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetPermissionListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetPermissionListResultDto" + } + }, { "name": "UpdateAsync", "parametersOnMethod": [ @@ -135,15 +240,15 @@ "allowAnonymous": null, "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" }, - "UpdateAsyncByProviderNameAndProviderKeyAndInput": { - "uniqueName": "UpdateAsyncByProviderNameAndProviderKeyAndInput", - "name": "UpdateAsync", - "httpMethod": "PUT", - "url": "api/permission-management/permissions", + "GetByGroupAsyncByGroupNameAndProviderNameAndProviderKey": { + "uniqueName": "GetByGroupAsyncByGroupNameAndProviderNameAndProviderKey", + "name": "GetByGroupAsync", + "httpMethod": "GET", + "url": "api/permission-management/permissions/by-group", "supportedVersions": [], "parametersOnMethod": [ { - "name": "providerName", + "name": "groupName", "typeAsString": "System.String, System.Private.CoreLib", "type": "System.String", "typeSimple": "string", @@ -151,7 +256,7 @@ "defaultValue": null }, { - "name": "providerKey", + "name": "providerName", "typeAsString": "System.String, System.Private.CoreLib", "type": "System.String", "typeSimple": "string", @@ -159,18 +264,18 @@ "defaultValue": null }, { - "name": "input", - "typeAsString": "Volo.Abp.PermissionManagement.UpdatePermissionsDto, Volo.Abp.PermissionManagement.Application.Contracts", - "type": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", - "typeSimple": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", "isOptional": false, "defaultValue": null } ], "parameters": [ { - "nameOnMethod": "providerName", - "name": "providerName", + "nameOnMethod": "groupName", + "name": "groupName", "jsonName": null, "type": "System.String", "typeSimple": "string", @@ -181,8 +286,8 @@ "descriptorName": "" }, { - "nameOnMethod": "providerKey", - "name": "providerKey", + "nameOnMethod": "providerName", + "name": "providerName", "jsonName": null, "type": "System.String", "typeSimple": "string", @@ -193,96 +298,101 @@ "descriptorName": "" }, { - "nameOnMethod": "input", - "name": "input", + "nameOnMethod": "providerKey", + "name": "providerKey", "jsonName": null, - "type": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", - "typeSimple": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", + "type": "System.String", + "typeSimple": "string", "isOptional": false, "defaultValue": null, "constraintTypes": null, - "bindingSourceId": "Body", + "bindingSourceId": "ModelBinding", "descriptorName": "" } ], "returnValue": { - "type": "System.Void", - "typeSimple": "System.Void" + "type": "Volo.Abp.PermissionManagement.GetPermissionListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetPermissionListResultDto" }, "allowAnonymous": null, "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" - } - } - }, - "Volo.Abp.PermissionManagement.Integration.PermissionIntegrationController": { - "controllerName": "PermissionIntegration", - "controllerGroupName": "PermissionIntegration", - "isRemoteService": true, - "isIntegrationService": true, - "apiVersion": null, - "type": "Volo.Abp.PermissionManagement.Integration.PermissionIntegrationController", - "interfaces": [ - { - "type": "Volo.Abp.PermissionManagement.Integration.IPermissionIntegrationService", - "name": "IPermissionIntegrationService", - "methods": [ - { - "name": "IsGrantedAsync", - "parametersOnMethod": [ - { - "name": "input", - "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=7.4.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", - "type": "System.Collections.Generic.List", - "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", - "isOptional": false, - "defaultValue": null - } - ], - "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" - } - } - ] - } - ], - "actions": { - "IsGrantedAsyncByInput": { - "uniqueName": "IsGrantedAsyncByInput", - "name": "IsGrantedAsync", - "httpMethod": "GET", - "url": "integration-api/permission-management/permissions/is-granted", + }, + "UpdateAsyncByProviderNameAndProviderKeyAndInput": { + "uniqueName": "UpdateAsyncByProviderNameAndProviderKeyAndInput", + "name": "UpdateAsync", + "httpMethod": "PUT", + "url": "api/permission-management/permissions", "supportedVersions": [], "parametersOnMethod": [ + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, { "name": "input", - "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=7.4.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", - "type": "System.Collections.Generic.List", - "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", + "typeAsString": "Volo.Abp.PermissionManagement.UpdatePermissionsDto, Volo.Abp.PermissionManagement.Application.Contracts", + "type": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", + "typeSimple": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", "isOptional": false, "defaultValue": null } ], "parameters": [ + { + "nameOnMethod": "providerName", + "name": "providerName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "providerKey", + "name": "providerKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, { "nameOnMethod": "input", "name": "input", "jsonName": null, - "type": "System.Collections.Generic.List", - "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", + "type": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", + "typeSimple": "Volo.Abp.PermissionManagement.UpdatePermissionsDto", "isOptional": false, "defaultValue": null, "constraintTypes": null, - "bindingSourceId": "ModelBinding", + "bindingSourceId": "Body", "descriptorName": "" } ], "returnValue": { - "type": "Volo.Abp.Application.Dtos.ListResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + "type": "System.Void", + "typeSimple": "System.Void" }, "allowAnonymous": null, - "implementFrom": "Volo.Abp.PermissionManagement.Integration.IPermissionIntegrationService" + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs index 28dab8da28..ff6d7e6128 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs @@ -22,6 +22,13 @@ public class PermissionsController : AbpControllerBase, IPermissionAppService return PermissionAppService.GetAsync(providerName, providerKey); } + [HttpGet] + [Route("by-group")] + public virtual Task GetByGroupAsync(string groupName, string providerName, string providerKey) + { + return PermissionAppService.GetByGroupAsync(groupName, providerName, providerKey); + } + [HttpPut] public virtual Task UpdateAsync(string providerName, string providerKey, UpdatePermissionsDto input) { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js index ab0daefa90..a296877917 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js @@ -18,6 +18,13 @@ }, ajaxParams)); }; + volo.abp.permissionManagement.permissions.getByGroup = function(groupName, providerName, providerKey, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/by-group' + abp.utils.buildQueryString([{ name: 'groupName', value: groupName }, { name: 'providerName', value: providerName }, { name: 'providerKey', value: providerKey }]) + '', + type: 'GET' + }, ajaxParams)); + }; + volo.abp.permissionManagement.permissions.update = function(providerName, providerKey, input, ajaxParams) { return abp.ajax($.extend(true, { url: abp.appPath + 'api/permission-management/permissions' + abp.utils.buildQueryString([{ name: 'providerName', value: providerName }, { name: 'providerKey', value: providerKey }]) + '', diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs index 52a68f60d3..11e9e8ca04 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs @@ -32,7 +32,7 @@ public class PermissionAppService_Tests : AbpPermissionManagementApplicationTest permissionListResultDto.ShouldNotBeNull(); permissionListResultDto.EntityDisplayName.ShouldBe(PermissionTestDataBuilder.User1Id.ToString()); - permissionListResultDto.Groups.Count.ShouldBe(1); + permissionListResultDto.Groups.Count.ShouldBe(2); permissionListResultDto.Groups.ShouldContain(x => x.Name == "TestGroup"); permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission1"); @@ -50,11 +50,11 @@ public class PermissionAppService_Tests : AbpPermissionManagementApplicationTest result.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission5"); result.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission5.ChildPermission1"); } - + permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission6"); permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyPermission6.ChildDisabledPermission1"); permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission6.ChildPermission2"); - + permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission1"); permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2"); permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission1"); @@ -62,6 +62,21 @@ public class PermissionAppService_Tests : AbpPermissionManagementApplicationTest permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission2.ChildPermission1"); } + [Fact] + public async Task GetByGroupAsync() + { + var permissionListResultDto = await _permissionAppService.GetByGroupAsync("TestGroup2", UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + permissionListResultDto.ShouldNotBeNull(); + permissionListResultDto.EntityDisplayName.ShouldBe(PermissionTestDataBuilder.User1Id.ToString()); + permissionListResultDto.Groups.Count.ShouldBe(1); + permissionListResultDto.Groups.ShouldContain(x => x.Name == "TestGroup2"); + + permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission7"); + permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission8"); + } + [Fact] public async Task UpdateAsync() { diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestPermissionDefinitionProvider.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestPermissionDefinitionProvider.cs index 55d034ad61..e644de8d71 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestPermissionDefinitionProvider.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestPermissionDefinitionProvider.cs @@ -22,14 +22,18 @@ public class TestPermissionDefinitionProvider : PermissionDefinitionProvider var myPermission5 = testGroup.AddPermission("MyPermission5"); myPermission5.StateCheckers.Add(new TestRequireRolePermissionStateProvider("super-admin")); myPermission5.AddChild("MyPermission5.ChildPermission1"); - + var myPermission6 = testGroup.AddPermission("MyPermission6"); myPermission6.AddChild("MyPermission6.ChildDisabledPermission1", isEnabled: false); myPermission6.AddChild("MyPermission6.ChildPermission2"); - + var myDisabledPermission2 = testGroup.AddPermission("MyDisabledPermission2", isEnabled: false); myDisabledPermission2.AddChild("MyDisabledPermission2.ChildPermission1"); var myDisabledPermission2Child2 = myDisabledPermission2.AddChild("MyDisabledPermission2.ChildPermission2"); myDisabledPermission2Child2.AddChild("MyDisabledPermission2.ChildPermission2.ChildPermission1"); + + var testGroup2 = context.AddGroup("TestGroup2"); + testGroup2.AddPermission("MyPermission7"); + testGroup2.AddPermission("MyPermission8"); } } diff --git a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/package.json b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/package.json index a155a90e38..2a45d494f7 100644 --- a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/package.json +++ b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/package.json @@ -3,6 +3,6 @@ "name": "demo-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1" } } diff --git a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/yarn.lock b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/yarn.lock index 6c8afa8deb..93d0931275 100644 --- a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/yarn.lock +++ b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/yarn.lock @@ -2,185 +2,185 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.2.0.tgz#af6ff5071cadb480b4aece0f15400d56b105a350" - integrity sha512-+LOmhSfsua7i3VQy9vYTDv7nE0fdIA+kNvorQ4wkkRzijOAlwmS4fkupglwOKJQSCWGAM7VXccPy2NzdmwvEtw== +"@abp/aspnetcore.mvc.ui.theme.basic@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-9.3.0-rc.1.tgz#649e3e7c3cb77946783b93567c4a6333482dee8e" + integrity sha512-r1lZdQMOqRqFayB/Hg3LtMruCH6DB5hxk5C8CcwifjtC9b8mwXpqepDY0WE+ujaDjYuNkWeK1WzUUACPsvqO5w== dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.shared" "~9.3.0-rc.1" -"@abp/aspnetcore.mvc.ui.theme.shared@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.2.0.tgz#791f419e8e0fab229e3f93f7a90edcd259100206" - integrity sha512-Mrs+kQg0S5OyRsPBwXQTqOq2DBWDdot7emETcX/gatv26GFbRe3nTOk1E+VWD/nsxHEOKTSE8LClC6TgkMxD8Q== +"@abp/aspnetcore.mvc.ui.theme.shared@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-9.3.0-rc.1.tgz#9ef2c2d7e058f5ff4c0f02eed493b7c170891ad5" + integrity sha512-+JjlPQJZgnyVIQ4Ejfp0pmzZI51Z8uzolo0JwX624U18BHUz76emDB611FYIinBCirfwDZlNolPs75IIor6GOg== dependencies: - "@abp/aspnetcore.mvc.ui" "~9.2.0" - "@abp/bootstrap" "~9.2.0" - "@abp/bootstrap-datepicker" "~9.2.0" - "@abp/bootstrap-daterangepicker" "~9.2.0" - "@abp/datatables.net-bs5" "~9.2.0" - "@abp/font-awesome" "~9.2.0" - "@abp/jquery-form" "~9.2.0" - "@abp/jquery-validation-unobtrusive" "~9.2.0" - "@abp/lodash" "~9.2.0" - "@abp/luxon" "~9.2.0" - "@abp/malihu-custom-scrollbar-plugin" "~9.2.0" - "@abp/moment" "~9.2.0" - "@abp/select2" "~9.2.0" - "@abp/sweetalert2" "~9.2.0" - "@abp/timeago" "~9.2.0" - -"@abp/aspnetcore.mvc.ui@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.2.0.tgz#e3e703ea46caf04cc966ea0af6deb64427a90d4c" - integrity sha512-VHH68/7Bw7r8p70T9grnVISgYPe2t3m9199S/wAXGtpGHML/lbHhDflWbm7y1MHcrmCfaXy42O9SmTHV25BJhA== + "@abp/aspnetcore.mvc.ui" "~9.3.0-rc.1" + "@abp/bootstrap" "~9.3.0-rc.1" + "@abp/bootstrap-datepicker" "~9.3.0-rc.1" + "@abp/bootstrap-daterangepicker" "~9.3.0-rc.1" + "@abp/datatables.net-bs5" "~9.3.0-rc.1" + "@abp/font-awesome" "~9.3.0-rc.1" + "@abp/jquery-form" "~9.3.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~9.3.0-rc.1" + "@abp/lodash" "~9.3.0-rc.1" + "@abp/luxon" "~9.3.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~9.3.0-rc.1" + "@abp/moment" "~9.3.0-rc.1" + "@abp/select2" "~9.3.0-rc.1" + "@abp/sweetalert2" "~9.3.0-rc.1" + "@abp/timeago" "~9.3.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-9.3.0-rc.1.tgz#5fa155f8351b74790503060a2d4ea1b4f699c1e6" + integrity sha512-l3d7HaMWqtWdXBPPHzwh5IAKUYasTIooI1OGnGZjrKrZ6gayIYhLvmZ5M9i0CFZPki41sj2m+Y2Tr6Du+mGVfA== dependencies: ansi-colors "^4.1.3" -"@abp/bootstrap-datepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.2.0.tgz#271ff68e2cee7b4ffe5a60406561a05948d6bbe6" - integrity sha512-V8o1cn1MKXE5GH1ZpBHiWWilzxjHIp4IS6rNoCDBSnaQcVvRku9KPI8tPNQSf+4x3jBfHDV9aOBDbDGTQ6J2yw== +"@abp/bootstrap-datepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-9.3.0-rc.1.tgz#7c232d14134f4f9849dbaf85ecf97dda8c5b889c" + integrity sha512-JSFeLSfrqS/6eZXAf12myzg7RhDVZ5e2FJxNwPqXsqZhH5EOi1XyF+7dOZIc40C3TbitwzKTQglKydcmFAtozA== dependencies: bootstrap-datepicker "^1.10.0" -"@abp/bootstrap-daterangepicker@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.2.0.tgz#a239f8c2efce57d2e2beca70ceeede52d1b177d5" - integrity sha512-Cd9naCyepTvmUotkR1VyOBqUMgyeSXnOVWR7HxXm+jugKtnWRzrztZB6UyfnNzzjc1RMOyiAUEjzitKSJrXeoA== +"@abp/bootstrap-daterangepicker@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-9.3.0-rc.1.tgz#d0dbbe9a90388e1164b3d74faa506fa6be561971" + integrity sha512-FSo7d6yLUBsCPJr0Y0Mo8GGxyxSQcgK+8KOOzR8g2NsqF2u1X/Ge7FxnetuzTorKAtKglIYSK5KZWmtXw+2Ujg== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.2.0.tgz#08859288b8372ea111a240b507047b144d6caca9" - integrity sha512-L3EZQza2c/5VmvZkLsf0EOuaMi8fseyyiwlFN65i1hpcDwhOLcaqnxMneeaSJ+Dy4xczJT+oBml9D9OSTuzmkA== +"@abp/bootstrap@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-9.3.0-rc.1.tgz#adad9b3e5f960ba0b47ac5f63afcde523f1d49cd" + integrity sha512-VjPhrLvVzP3qikAuTfSZDXgYtuSLb76+uNgIv0Bd5gsiAfYtYQ5k6OQGkPyNQZI13oYyegf/arAcLtaW1m9c2w== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" bootstrap "^5.3.3" -"@abp/core@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.2.0.tgz#db08fd34cfc891e94eb9e59ed3c0d0e6ef45c51a" - integrity sha512-3iESoHFj8I2xK81dwQVpCI6C1bc87VfWKyJE3/IUv4zWvG4QvI0aKhe1wxocmJqTjjowPUA3/fa2hvpfqPs2Bw== +"@abp/core@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-9.3.0-rc.1.tgz#be56a61f793510daabc36a070227052f040a36bd" + integrity sha512-eXzkeD/aqH8ssfG0sywKhvchIsNFgOwR12ctNw2EfzoBDAPkycu3WUnZbB5yIpbl7JXxqYcxYevGRuTWGXl1tA== dependencies: - "@abp/utils" "~9.2.0" + "@abp/utils" "~9.3.0-rc.1" -"@abp/datatables.net-bs5@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.2.0.tgz#eab201c959727c27aaab30dc5bd8159249d8b54b" - integrity sha512-bmK6GKffXzYbfkDIlN27D7mohnYsXoODEiHqhZnBdIzeSJyHwrwRPRVbO1EcBn1SEBHjGJp3S69Z6gDbRs018g== +"@abp/datatables.net-bs5@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-9.3.0-rc.1.tgz#98cebb8f7be5e8b6a6460028f289574c45fa3d42" + integrity sha512-Th8O4cg7S0Aac80oGBx/TQN8JTqEPPpAH/QHxyj7WGEeyD4squsuIPEbR4uKZ+igUeTl8em1UjKwn20ETTUWmw== dependencies: - "@abp/datatables.net" "~9.2.0" + "@abp/datatables.net" "~9.3.0-rc.1" datatables.net-bs5 "^2.1.8" -"@abp/datatables.net@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.2.0.tgz#e4880fe074d86d3c5dbd7f48c86244790fc376c2" - integrity sha512-bKaaa+tl0Pt4oNaV+X8pBbvsHc2mPYoL7yuAs+LN8ZLwBdsGoUw7RNhLQ63O3tuYdHuaHhI/mx23X6JThr0SYw== +"@abp/datatables.net@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-9.3.0-rc.1.tgz#fd03b526c726a5b06d9a2221e7b836707642155e" + integrity sha512-47sqHWc69e2ADUNlmcFoIEmuCUrtnaxSX9b+qnDdRMlcg2KNdXoj1nIYarYbswUDP27CVKqEAuzMqwpuFpoWaQ== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" datatables.net "^2.1.8" -"@abp/font-awesome@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.2.0.tgz#3e359da2510cbc0e5b9e46e9cb3664baf285722e" - integrity sha512-HRGg6XK3bCxFdVvEBnBKyLamqMUrenj//E4JuKOs8DtGLVH0jTyh8TwUT5/E/pI+POV7HEOpv9WpSB2p8pfsAg== +"@abp/font-awesome@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-9.3.0-rc.1.tgz#6fb1fd33a428e64abf103054878c3be22e66e43f" + integrity sha512-F4MxlzhQgYr+EUc7eJSed6Xu2gbj9hUYNy5W0jYke7ajv9tcMavrxn0DGEA3KIHBL3PUmiIj4SwT2dudiefMJA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" "@fortawesome/fontawesome-free" "^6.6.0" -"@abp/jquery-form@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.2.0.tgz#40fac992584c26e6c54f66e7f68f8abf8944a626" - integrity sha512-B7Shq1itQjsnzdU1kjLpGHWjkSGFhIM2iF5BNMkqcylG3Yq1Se4+8QPoJpn/soilmtX8gbO2fx8TOejfIazXIw== +"@abp/jquery-form@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-9.3.0-rc.1.tgz#7e937cecdc3142429ccd40bee86d178ab49dc055" + integrity sha512-CRQCVTdrzFvlIxpFhOe5OavdBhRom33CW70WOIeV9eIvwr5iqRmdjWvP5ug7PIKxx7k2k7BDarBa3SWrB+KKig== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.2.0.tgz#c2df51d024d48e71f0e7fb8d4207a8b2855393f4" - integrity sha512-c1cPfWVdo+gpaMoegAkw0DzGL2fy/1ylEi/shb95MAGt3iyECVx+X+R/XOxbVHKVI57D4d5IGj6cXYBhdKkvAw== +"@abp/jquery-validation-unobtrusive@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-9.3.0-rc.1.tgz#d14cdb04f69349eabdd3dea44057883cf84d72a7" + integrity sha512-vT31DIEsSDx+/JOM+i4tPwcxMm9/Y9ZmvpnpWcos1e/iUSDYhKWq/tddX2iR8r/MQgQs0TVuMI8eLUmIwfTGfg== dependencies: - "@abp/jquery-validation" "~9.2.0" + "@abp/jquery-validation" "~9.3.0-rc.1" jquery-validation-unobtrusive "^4.0.0" -"@abp/jquery-validation@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.2.0.tgz#97688d2e3c25699d4368ebf7234e04943aa5e6ab" - integrity sha512-UO+T6SqXBrh0ODwvMm840CGbE2fdYNo5oqJL4V4JbHv9uz7MH+k0bB1DK7mFb94iDM7QcglLzIfcN4hLRV7arw== +"@abp/jquery-validation@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-9.3.0-rc.1.tgz#f200569f28142a2c7e47af45a851903f1bc8571c" + integrity sha512-s90j9U/Uct/0AiSb0SxRwMDR6nyEFCodyrnkjDZ6O6wpGtFBnPI14BLptvr4SllW8Cm85dSBC4nGz5pL7TAm3w== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" jquery-validation "^1.21.0" -"@abp/jquery@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.2.0.tgz#38c249be6eda0cdc899cc8a1f20e5152c39ae9a0" - integrity sha512-sIe3Zk+8549ytydCtDlECZ930PapW/2J0652two/sJwYG/SGUGxYQbw3QnJGFTcL9TFwcWwRj5iWX0gWrLEIyA== +"@abp/jquery@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-9.3.0-rc.1.tgz#f37ab324f87251df2800ad3816cc16cdc0546f03" + integrity sha512-GwNfTtkpqQ5NloCAgHmb0jT8ZvRpvXy3TQq/0qUVz9+8w6L0hpCoF+w6fk5HQjVslmHWuLnPma80YyReMKCqAQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" jquery "~3.7.1" -"@abp/lodash@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.2.0.tgz#7fa4c9e956c766e34ec4677d2102a6d00f899a4b" - integrity sha512-2elXj/eWw875tF9ixbOm3uqXCxGaG5gL9Tub5k7cP+XhFpNBOYijNaXdN8SeDSxr83WDVWdrk//OQL8BF7XPdw== +"@abp/lodash@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-9.3.0-rc.1.tgz#46720281f1485eef88e93c6c030a75d426b00fc6" + integrity sha512-i+XKW1L/ZQwRJpt8kG9XHL+o69jVnyWEcPKbvbGAAGK7DZBH0D3zHzXjoGYsjR/QulWNXmUr2/KJfeUo4VZqDw== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.2.0.tgz#865db7b60dba4029134fb4a4b5eaa08c723dcea8" - integrity sha512-LWjczvzu1gFIq0/2fRz+bJW2+zsmXAmfz0I+lZ3wmqUdkViqAqwTa+5NMIl2tC92u4Dv3LGXKtH37Jw8m+XjTg== +"@abp/luxon@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-9.3.0-rc.1.tgz#eeb2c899f88635ceee8f60f5918ad7bff88506af" + integrity sha512-Xz601losjcTEgBrqzy/LfZiK+9HvmfKwWqhaPNgGzd0IR92/3WBuLIvqIETVjd9ue5ec7dcd3o6HfeNzdUwXqQ== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" luxon "^3.5.0" -"@abp/malihu-custom-scrollbar-plugin@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.2.0.tgz#09722b1e7ca34b96e2a68368db0e96cdf9ab0e6c" - integrity sha512-kfDf/1RwGtAlos/7BW+7xbh3LtJ4VG0Z4mxS+b2HsywAwlt/kE5FltfBj2ResQb030bsGNl7A5JglV9Pv1UlPw== +"@abp/malihu-custom-scrollbar-plugin@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-9.3.0-rc.1.tgz#4fe06e29f0a3aee328f8aa655a3ee672e4b2fba3" + integrity sha512-r88KhGRqd2EY+wUYSH0JuTihX+m6ReVCv/IxWymaGQndHkRfUoZK/u+96jpP4CtapPrWvgtjVDe0XYdYs5v9aA== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.2.0.tgz#137d688af4df195742061ac2b8a2bf460a027071" - integrity sha512-15aTjYAxHK+upkiZ94XCe8CoSPKMl1D8f6GXJIfwPkuYZ+na4ma17qBu4P8bFsc4gu3ngxYiLHRSzYzr4oCSYQ== +"@abp/moment@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-9.3.0-rc.1.tgz#09721a96eac42ef415b1e660f1a02ace9657c668" + integrity sha512-JKHftVm65mzK4wn0vpHsHtqdGgrthzO/IXV30mSZs1vgVxZNlDCYQ3cr2+oeAnCjg+Ec1QMwfPnIrAqy48iG5w== dependencies: moment "^2.30.1" -"@abp/select2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.2.0.tgz#c96d869be0d3298ed7c0888288ea9829e6266cd4" - integrity sha512-V+qx9hw3oe7o0WbG03ZgAjbqRJPVuedzrdy7ExEdueTc6LRP/WEgbVpXhsNISObtouE6Dadwp3iXYSExgNUC6A== +"@abp/select2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-9.3.0-rc.1.tgz#b95bf68bbc5aa3788dd443dc54a1c7dd2326614f" + integrity sha512-wBXjfOi5bxp3MtpOUgC5UzOa7rnRmkD6EdwgsX2ellTKJlcm2omJs6cV24pZQ+2HFj4GBWh78OpSBL9OV3IoXg== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.2.0.tgz#826d6dd0b70c35a7401cc884fb1e82af99a0305d" - integrity sha512-0r338ayjaL9uzmLKE8oHpcMgJeVgVoMYfhQAPINeQHv1TPXuYCLo0aoRNoLsfmUo3ayYBBa3zOrugFIVis7Q6A== +"@abp/sweetalert2@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-9.3.0-rc.1.tgz#4b223a2a205becb781421df63504f4914657eedb" + integrity sha512-/e7F5bzQbIGtJnAanAfv/YOyAwrwRyLx26zmH0z4zpK6uSgpYrEM8r0KfLoPiZACs3bN5GU1zXEerfhcoZ6H1g== dependencies: - "@abp/core" "~9.2.0" + "@abp/core" "~9.3.0-rc.1" sweetalert2 "^11.14.1" -"@abp/timeago@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.2.0.tgz#79bbe6dd32b0ee7df2e8ebd05274a0ecc7882ba7" - integrity sha512-hEUi5re5N1YkDSpaUaUtXF1Mz4YyiEvNzVADbKRz11kbR4ZAFzcvVqsQLeNo7qnuFLfJNAtuzyjkuxwL75kmaA== +"@abp/timeago@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-9.3.0-rc.1.tgz#48456854ac09d26ef3e9b9a98829214e7fed5c47" + integrity sha512-xjZRGUcykNB21YbetgOISD+ePBgY0PorrZK9DaE5Q4fnzl1+/slTT26NAakFxDc8YmNoslxjcGu5Yrgihs0sIg== dependencies: - "@abp/jquery" "~9.2.0" + "@abp/jquery" "~9.3.0-rc.1" timeago "^1.6.7" -"@abp/utils@~9.2.0": - version "9.2.0" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.2.0.tgz#bf32ced1175e45fbe010c3cb806c7cd37f85089c" - integrity sha512-aciBuXhzlaqe+o7mNt536bCk425cmxY5BE0wwl13u3pX3LfWYWLEgwl8GS0aeI11TS1/7+1N85RJELyz/+y0hQ== +"@abp/utils@~9.3.0-rc.1": + version "9.3.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-9.3.0-rc.1.tgz#d93c3be3df3cf12c3ef4b43c1bb75dd86f7b6575" + integrity sha512-qLcgFT+i7Zhq30mAQZGCCCfkoWJHlrhpo6PQKBzoENT9UNADMPtwDF8VDw4SSxqpO8xhcktREjDrQDWy26Bc4g== dependencies: just-compare "^2.3.0" diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/SettingManagement.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/SettingManagement.razor index e3ab222ccf..6fb9445860 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/SettingManagement.razor +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor/Pages/SettingManagement/SettingManagement.razor @@ -11,21 +11,22 @@ - + - @foreach (var group in SettingComponentCreationContext.Groups) - { - - @group.DisplayName - - } +
+ @foreach (var group in SettingComponentCreationContext.Groups) + { + + @group.DisplayName + + } +
@foreach (var group in SettingComponentCreationContext.Groups) { - @{ SettingItemRenders.Add(builder => { diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs index ddf451154d..b3fd120f38 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs @@ -136,7 +136,7 @@ public class SettingManager : ISettingManager, ISingletonDependency if (providers.Count > 1 && !forceToSet && setting.IsInherited && value != null) { var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null); - if (fallbackValue == value) + if (string.Equals(fallbackValue, value, StringComparison.OrdinalIgnoreCase)) { //Clear the value if it's same as it's fallback value value = null; diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml index 7fa674f4be..d31670a036 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Pages/SettingManagement/Index.cshtml @@ -35,7 +35,7 @@
-
+
diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs index 496095c807..6fe1edafc6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs @@ -28,7 +28,8 @@ public class AbpTenantManagementDomainMappingProfile : Profile return connStrings; }); }) - .ForMember(x => x.IsActive, x => x.Ignore()); + .ForMember(x => x.IsActive, x => x.Ignore()) + .ForMember(x => x.EditionId, x => x.Ignore()); CreateMap(); } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantValidator.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantValidator.cs new file mode 100644 index 0000000000..badd9515b8 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantValidator.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.TenantManagement; + +public class AbpTenantValidator : ITenantValidator, ITransientDependency +{ + protected ITenantRepository TenantRepository { get; } + + public AbpTenantValidator(ITenantRepository tenantRepository) + { + TenantRepository = tenantRepository; + } + + public virtual async Task ValidateAsync(Tenant tenant) + { + Check.NotNullOrWhiteSpace(tenant.Name, nameof(tenant.Name)); + Check.NotNullOrWhiteSpace(tenant.NormalizedName, nameof(tenant.NormalizedName)); + + var owner = await TenantRepository.FindByNameAsync(tenant.NormalizedName); + if (owner != null && owner.Id != tenant.Id) + { + throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", tenant.NormalizedName); + } + } +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantValidator.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantValidator.cs new file mode 100644 index 0000000000..3a5cc9ffb0 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantValidator.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.TenantManagement; + +public interface ITenantValidator +{ + Task ValidateAsync(Tenant tenant); +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs index 0f40cfdd0b..91cdf87abb 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs @@ -1,6 +1,4 @@ -using System; -using System.Threading.Tasks; -using Volo.Abp.Caching; +using System.Threading.Tasks; using Volo.Abp.Domain.Services; using Volo.Abp.EventBus.Local; using Volo.Abp.MultiTenancy; @@ -9,16 +7,16 @@ namespace Volo.Abp.TenantManagement; public class TenantManager : DomainService, ITenantManager { - protected ITenantRepository TenantRepository { get; } + protected ITenantValidator TenantValidator { get; } protected ITenantNormalizer TenantNormalizer { get; } protected ILocalEventBus LocalEventBus { get; } public TenantManager( - ITenantRepository tenantRepository, + ITenantValidator tenantValidator, ITenantNormalizer tenantNormalizer, ILocalEventBus localEventBus) { - TenantRepository = tenantRepository; + TenantValidator = tenantValidator; TenantNormalizer = tenantNormalizer; LocalEventBus = localEventBus; } @@ -27,9 +25,9 @@ public class TenantManager : DomainService, ITenantManager { Check.NotNull(name, nameof(name)); - var normalizedName = TenantNormalizer.NormalizeName(name); - await ValidateNameAsync(normalizedName); - return new Tenant(GuidGenerator.Create(), name, normalizedName); + var tenant = new Tenant(GuidGenerator.Create(), name, TenantNormalizer.NormalizeName(name)); + await TenantValidator.ValidateAsync(tenant); + return tenant; } public virtual async Task ChangeNameAsync(Tenant tenant, string name) @@ -37,20 +35,10 @@ public class TenantManager : DomainService, ITenantManager Check.NotNull(tenant, nameof(tenant)); Check.NotNull(name, nameof(name)); - var normalizedName = TenantNormalizer.NormalizeName(name); - - await ValidateNameAsync(normalizedName, tenant.Id); await LocalEventBus.PublishAsync(new TenantChangedEvent(tenant.Id, tenant.NormalizedName)); - tenant.SetName(name); - tenant.SetNormalizedName(normalizedName); - } - protected virtual async Task ValidateNameAsync(string normalizeName, Guid? expectedId = null) - { - var tenant = await TenantRepository.FindByNameAsync(normalizeName); - if (tenant != null && tenant.Id != expectedId) - { - throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", normalizeName); - } + tenant.SetName(name); + tenant.SetNormalizedName( TenantNormalizer.NormalizeName(name)); + await TenantValidator.ValidateAsync(tenant); } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantNameValidator_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantNameValidator_Tests.cs new file mode 100644 index 0000000000..bc1477d1ff --- /dev/null +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantNameValidator_Tests.cs @@ -0,0 +1,47 @@ +using System; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.TenantManagement; + +public class TenantValidator_Tests : AbpTenantManagementDomainTestBase +{ + private readonly TenantManager _tenantManager; + private readonly ITenantRepository _tenantRepository; + + public TenantValidator_Tests() + { + _tenantManager = GetRequiredService(); + _tenantRepository = GetRequiredService(); + } + + [Fact] + public async Task Should_Throw_If_Name_Is_Null() + { + await Assert.ThrowsAsync(() => _tenantManager.CreateAsync("")); + } + + [Fact] + public async Task Should_Throw_If_Duplicate_Name() + { + await Assert.ThrowsAsync(() => _tenantManager.CreateAsync("VOLOSOFT")); + + var tenant = await _tenantRepository.FindByNameAsync("ABP"); + await Assert.ThrowsAsync(() => _tenantManager.ChangeNameAsync(tenant, "VOLOSOFT")); + } + + [Fact] + public async Task Should_Not_Throw_For_Unique_Name() + { + var tenant = await _tenantManager.CreateAsync("VOLOSOFT2"); + await _tenantRepository.InsertAsync(tenant); + + tenant = await _tenantRepository.FindByNameAsync("ABP"); + await _tenantManager.ChangeNameAsync(tenant, "VOLOSOFT3"); + await _tenantRepository.UpdateAsync(tenant); + + tenant = await _tenantRepository.FindByNameAsync("VOLOSOFT3"); + tenant.ShouldNotBeNull(); + } +} diff --git a/modules/virtual-file-explorer/app/package.json b/modules/virtual-file-explorer/app/package.json index 8218af60fc..ac8ed3c1aa 100644 --- a/modules/virtual-file-explorer/app/package.json +++ b/modules/virtual-file-explorer/app/package.json @@ -3,7 +3,7 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~9.2.0", - "@abp/virtual-file-explorer": "~9.2.0" + "@abp/aspnetcore.mvc.ui.theme.basic": "~9.3.0-rc.1", + "@abp/virtual-file-explorer": "~9.3.0-rc.1" } } diff --git a/npm/lerna.json b/npm/lerna.json index c0ef92d64e..464ebe9073 100644 --- a/npm/lerna.json +++ b/npm/lerna.json @@ -1,5 +1,5 @@ { - "version": "9.2.0", + "version": "9.3.0-rc.1", "packages": [ "packs/*" ], diff --git a/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts b/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts deleted file mode 100644 index 0d9f82ea25..0000000000 --- a/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - -const routes: Routes = [ - { - path: '', - pathMatch: 'full', - loadChildren: () => import('./home/home.module').then(m => m.HomeModule), - }, - { - path: 'account', - loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()), - }, - { - path: 'identity', - loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()), - }, - { - path: 'tenant-management', - loadChildren: () => - import('@abp/ng.tenant-management').then(m => m.TenantManagementModule.forLazy()), - }, - { - path: 'setting-management', - loadChildren: () => - import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()), - }, -]; - -@NgModule({ - imports: [RouterModule.forRoot(routes, {})], - exports: [RouterModule], -}) -export class AppRoutingModule {} diff --git a/npm/ng-packs/apps/dev-app/src/app/app.component.ts b/npm/ng-packs/apps/dev-app/src/app/app.component.ts index 1b0993cd2f..5220d57353 100644 --- a/npm/ng-packs/apps/dev-app/src/app/app.component.ts +++ b/npm/ng-packs/apps/dev-app/src/app/app.component.ts @@ -1,12 +1,14 @@ import { Component } from '@angular/core'; +import { InternetConnectionStatusComponent, LoaderBarComponent } from '@abp/ng.theme.shared'; +import { DynamicLayoutComponent } from '@abp/ng.core'; @Component({ - standalone: false, selector: 'app-root', template: ` `, + imports: [LoaderBarComponent, DynamicLayoutComponent, InternetConnectionStatusComponent], }) export class AppComponent {} diff --git a/npm/ng-packs/apps/dev-app/src/app/app.config.ts b/npm/ng-packs/apps/dev-app/src/app/app.config.ts new file mode 100644 index 0000000000..3075c477fc --- /dev/null +++ b/npm/ng-packs/apps/dev-app/src/app/app.config.ts @@ -0,0 +1,42 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter } from '@angular/router'; + +import { appRoutes } from './app.routes'; +import { APP_ROUTE_PROVIDER } from './route.provider'; +import { provideAbpCore, withOptions } from '@abp/ng.core'; +import { environment } from '../environments/environment'; +import { registerLocale } from '@abp/ng.core/locale'; +import { provideAbpOAuth } from '@abp/ng.oauth'; +import { provideAbpThemeShared } from '@abp/ng.theme.shared'; +import { provideSettingManagementConfig } from '@abp/ng.setting-management/config'; +import { provideAccountConfig } from '@abp/ng.account/config'; +import { provideIdentityConfig } from '@abp/ng.identity/config'; +import { provideTenantManagementConfig } from '@abp/ng.tenant-management/config'; +import { provideFeatureManagementConfig } from '@abp/ng.feature-management'; +import { provideThemeBasicConfig } from '@abp/ng.theme.basic'; +import { provideAnimations } from '@angular/platform-browser/animations'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideRouter(appRoutes), + APP_ROUTE_PROVIDER, + provideAbpCore( + withOptions({ + environment, + registerLocaleFn: registerLocale(), + sendNullsAsQueryParam: false, + skipGetAppConfiguration: false, + }), + ), + provideAbpOAuth(), + provideAbpThemeShared(), + provideSettingManagementConfig(), + provideAccountConfig(), + provideIdentityConfig(), + provideTenantManagementConfig(), + provideFeatureManagementConfig(), + provideZoneChangeDetection({ eventCoalescing: true }), + provideThemeBasicConfig(), + provideAnimations(), + ], +}; diff --git a/npm/ng-packs/apps/dev-app/src/app/app.module.ts b/npm/ng-packs/apps/dev-app/src/app/app.module.ts deleted file mode 100644 index 707f1f846f..0000000000 --- a/npm/ng-packs/apps/dev-app/src/app/app.module.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { CoreModule, provideAbpCore, withOptions } from '@abp/ng.core'; -import { registerLocale } from '@abp/ng.core/locale'; -import { - InternetConnectionStatusComponent, - ThemeSharedModule, - provideAbpThemeShared, -} from '@abp/ng.theme.shared'; -import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x'; -import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts'; -import { provideAbpOAuth } from '@abp/ng.oauth'; -import { provideSettingManagementConfig } from '@abp/ng.setting-management/config'; -import { provideAccountConfig } from '@abp/ng.account/config'; -import { provideIdentityConfig } from '@abp/ng.identity/config'; -import { provideTenantManagementConfig } from '@abp/ng.tenant-management/config'; -import { provideFeatureManagementConfig } from '@abp/ng.feature-management'; -import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account'; -import { environment } from '../environments/environment'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { APP_ROUTE_PROVIDER } from './route.provider'; - -@NgModule({ - imports: [ - BrowserModule, - BrowserAnimationsModule, - AppRoutingModule, - CoreModule, - ThemeSharedModule, - ThemeLeptonXModule.forRoot(), - SideMenuLayoutModule.forRoot(), - AccountLayoutModule.forRoot(), - InternetConnectionStatusComponent, - ], - providers: [ - APP_ROUTE_PROVIDER, - provideAbpCore( - withOptions({ - environment, - registerLocaleFn: registerLocale(), - sendNullsAsQueryParam: false, - skipGetAppConfiguration: false, - }), - ), - provideAbpOAuth(), - provideAbpThemeShared(), - provideSettingManagementConfig(), - provideAccountConfig(), - provideIdentityConfig(), - provideTenantManagementConfig(), - provideFeatureManagementConfig(), - ], - declarations: [AppComponent], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/npm/ng-packs/apps/dev-app/src/app/app.routes.ts b/npm/ng-packs/apps/dev-app/src/app/app.routes.ts new file mode 100644 index 0000000000..47462b7f8f --- /dev/null +++ b/npm/ng-packs/apps/dev-app/src/app/app.routes.ts @@ -0,0 +1,25 @@ +import { Routes } from '@angular/router'; + +export const appRoutes: Routes = [ + { + path: '', + pathMatch: 'full', + loadComponent: () => import('./home/home.component').then(m => m.HomeComponent), + }, + { + path: 'account', + loadChildren: () => import('@abp/ng.account').then(m => m.createRoutes()), + }, + { + path: 'identity', + loadChildren: () => import('@abp/ng.identity').then(m => m.createRoutes()), + }, + { + path: 'tenant-management', + loadChildren: () => import('@abp/ng.tenant-management').then(m => m.createRoutes()), + }, + { + path: 'setting-management', + loadChildren: () => import('@abp/ng.setting-management').then(m => m.createRoutes()), + }, +]; diff --git a/npm/ng-packs/apps/dev-app/src/app/home/home-routing.module.ts b/npm/ng-packs/apps/dev-app/src/app/home/home-routing.module.ts deleted file mode 100644 index 7089990134..0000000000 --- a/npm/ng-packs/apps/dev-app/src/app/home/home-routing.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { HomeComponent } from './home.component'; - -const routes: Routes = [{ path: '', component: HomeComponent }]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], -}) -export class HomeRoutingModule {} diff --git a/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts b/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts index ad791cabec..4a6287a7c0 100644 --- a/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts +++ b/npm/ng-packs/apps/dev-app/src/app/home/home.component.ts @@ -1,10 +1,12 @@ -import { AuthService } from '@abp/ng.core'; +import { AuthService, LocalizationPipe } from '@abp/ng.core'; import { Component, inject } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ButtonComponent, CardBodyComponent, CardComponent } from '@abp/ng.theme.shared'; @Component({ - standalone: false, selector: 'app-home', templateUrl: './home.component.html', + imports: [CommonModule, LocalizationPipe, CardComponent, CardBodyComponent, ButtonComponent], }) export class HomeComponent { protected readonly authService = inject(AuthService); diff --git a/npm/ng-packs/apps/dev-app/src/app/home/home.module.ts b/npm/ng-packs/apps/dev-app/src/app/home/home.module.ts deleted file mode 100644 index 72d20ccc65..0000000000 --- a/npm/ng-packs/apps/dev-app/src/app/home/home.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { NgModule } from '@angular/core'; -import { SharedModule } from '../shared/shared.module'; -import { HomeRoutingModule } from './home-routing.module'; -import { HomeComponent } from './home.component'; - -@NgModule({ - declarations: [HomeComponent], - imports: [SharedModule, HomeRoutingModule], -}) -export class HomeModule {} diff --git a/npm/ng-packs/apps/dev-app/src/app/shared/shared.module.ts b/npm/ng-packs/apps/dev-app/src/app/shared/shared.module.ts deleted file mode 100644 index 964170499d..0000000000 --- a/npm/ng-packs/apps/dev-app/src/app/shared/shared.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CoreModule } from '@abp/ng.core'; -import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; -import { NgModule } from '@angular/core'; -import { ThemeSharedModule } from '@abp/ng.theme.shared'; -import { NgxValidateCoreModule } from '@ngx-validate/core'; - -@NgModule({ - declarations: [], - imports: [CoreModule, ThemeSharedModule, NgbDropdownModule, NgxValidateCoreModule], - exports: [CoreModule, ThemeSharedModule, NgbDropdownModule, NgxValidateCoreModule], - providers: [], -}) -export class SharedModule {} diff --git a/npm/ng-packs/apps/dev-app/src/main.ts b/npm/ng-packs/apps/dev-app/src/main.ts index fa4e0aef33..7180ec1a32 100644 --- a/npm/ng-packs/apps/dev-app/src/main.ts +++ b/npm/ng-packs/apps/dev-app/src/main.ts @@ -1,13 +1,5 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; - -if (environment.production) { - enableProdMode(); -} - -platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch(err => console.error(err)); +bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err)); diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 92326eadb4..2b6ae1c77e 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -44,8 +44,8 @@ }, "private": true, "devDependencies": { - "@abp/ng.theme.lepton-x": "~4.2.0", - "@abp/utils": "~9.2.0", + "@abp/ng.theme.lepton-x": "~4.3.0-rc.1", + "@abp/utils": "~9.3.0-rc.1", "@angular-devkit/build-angular": "~19.1.0", "@angular-devkit/core": "~19.1.0", "@angular-devkit/schematics": "~19.1.0", diff --git a/npm/ng-packs/packages/account-core/package.json b/npm/ng-packs/packages/account-core/package.json index 6cba82d222..6513236e38 100644 --- a/npm/ng-packs/packages/account-core/package.json +++ b/npm/ng-packs/packages/account-core/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.account.core", - "version": "9.2.0", + "version": "9.3.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.core": "~9.2.0", - "@abp/ng.theme.shared": "~9.2.0", + "@abp/ng.core": "~9.3.0-rc.1", + "@abp/ng.theme.shared": "~9.3.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/account/package.json b/npm/ng-packs/packages/account/package.json index fc34941743..6ac5bc686c 100644 --- a/npm/ng-packs/packages/account/package.json +++ b/npm/ng-packs/packages/account/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.account", - "version": "9.2.0", + "version": "9.3.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.account.core": "~9.2.0", - "@abp/ng.theme.shared": "~9.2.0", + "@abp/ng.account.core": "~9.3.0-rc.1", + "@abp/ng.theme.shared": "~9.3.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/account/src/lib/account.module.ts b/npm/ng-packs/packages/account/src/lib/account.module.ts index 58df433232..31c629bb4d 100644 --- a/npm/ng-packs/packages/account/src/lib/account.module.ts +++ b/npm/ng-packs/packages/account/src/lib/account.module.ts @@ -1,49 +1,33 @@ -import { CoreModule, LazyModuleFactory } from '@abp/ng.core'; -import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { LazyModuleFactory } from '@abp/ng.core'; import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core'; -import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; -import { NgxValidateCoreModule } from '@ngx-validate/core'; -import { AccountRoutingModule } from './account-routing.module'; -import { ChangePasswordComponent } from './components/change-password/change-password.component'; -import { LoginComponent } from './components/login/login.component'; -import { ManageProfileComponent } from './components/manage-profile/manage-profile.component'; -import { PersonalSettingsComponent } from './components/personal-settings/personal-settings.component'; -import { RegisterComponent } from './components/register/register.component'; import { AccountConfigOptions } from './models/config-options'; import { ACCOUNT_CONFIG_OPTIONS } from './tokens/config-options.token'; import { accountConfigOptionsFactory } from './utils/factory-utils'; import { AuthenticationFlowGuard } from './guards/authentication-flow.guard'; -import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component'; -import { ResetPasswordComponent } from './components/reset-password/reset-password.component'; import { RE_LOGIN_CONFIRMATION_TOKEN } from './tokens'; import { ACCOUNT_EDIT_FORM_PROP_CONTRIBUTORS } from './tokens/extensions.token'; import { AccountExtensionsGuard } from './guards/extensions.guard'; -import { PersonalSettingsHalfRowComponent } from './components/personal-settings/personal-settings-half-row.component'; -import { ExtensibleModule } from "@abp/ng.components/extensible"; - -const declarations = [ +import { + ForgotPasswordComponent, LoginComponent, - RegisterComponent, - ChangePasswordComponent, ManageProfileComponent, - PersonalSettingsComponent, - ForgotPasswordComponent, + RegisterComponent, ResetPasswordComponent, - PersonalSettingsHalfRowComponent, -]; +} from './components'; +import { AccountRoutingModule } from './account-routing.module'; @NgModule({ - declarations: [...declarations], + declarations: [], imports: [ - CoreModule, + LoginComponent, + RegisterComponent, + ForgotPasswordComponent, + ResetPasswordComponent, + ManageProfileComponent, AccountRoutingModule, - ThemeSharedModule, - NgbDropdownModule, - NgxValidateCoreModule, - ExtensibleModule, ], - exports: [...declarations], + exports: [], }) export class AccountModule { static forChild(options = {} as AccountConfigOptions): ModuleWithProviders { @@ -69,7 +53,9 @@ export class AccountModule { ], }; } - + /** + * @deprecated `AccountModule.forLazy()` is deprecated. You can use `createRoutes` **function** instead. + */ static forLazy(options = {} as AccountConfigOptions): NgModuleFactory { return new LazyModuleFactory(AccountModule.forChild(options)); } diff --git a/npm/ng-packs/packages/account/src/lib/account.routes.ts b/npm/ng-packs/packages/account/src/lib/account.routes.ts new file mode 100644 index 0000000000..5fb4236ee1 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/account.routes.ts @@ -0,0 +1,119 @@ +import { Routes } from '@angular/router'; +import { + ForgotPasswordComponent, + LoginComponent, + RegisterComponent, + ResetPasswordComponent, + ManageProfileComponent, +} from './components'; +import { eAccountComponents } from './enums'; +import { authenticationFlowGuard } from './guards'; +import { accountExtensionsResolver } from './resolvers'; +import { + RE_LOGIN_CONFIRMATION_TOKEN, + ACCOUNT_CONFIG_OPTIONS, + ACCOUNT_EDIT_FORM_PROP_CONTRIBUTORS, +} from './tokens'; +import { AccountConfigOptions } from './models'; +import { accountConfigOptionsFactory } from './utils'; +import { + authGuard, + ReplaceableComponents, + ReplaceableRouteContainerComponent, + RouterOutletComponent, +} from '@abp/ng.core'; + +export function provideAccount(options: AccountConfigOptions = {}) { + return [ + { provide: ACCOUNT_CONFIG_OPTIONS, useValue: options }, + { + provide: 'ACCOUNT_OPTIONS', + useFactory: accountConfigOptionsFactory, + deps: [ACCOUNT_CONFIG_OPTIONS], + }, + { + provide: RE_LOGIN_CONFIRMATION_TOKEN, + useValue: options.isPersonalSettingsChangedConfirmationActive ?? true, + }, + { + provide: ACCOUNT_EDIT_FORM_PROP_CONTRIBUTORS, + useValue: options.editFormPropContributors, + }, + ]; +} + +const canActivate = [authenticationFlowGuard]; + +export const createRoutes = (options: AccountConfigOptions = {}): Routes => [ + { + path: '', + component: RouterOutletComponent, + providers: provideAccount(options), + children: [ + { path: '', pathMatch: 'full', redirectTo: 'login' }, + { + path: 'login', + component: ReplaceableRouteContainerComponent, + canActivate, + data: { + replaceableComponent: { + key: eAccountComponents.Login, + defaultComponent: LoginComponent, + } as ReplaceableComponents.RouteData, + }, + title: 'AbpAccount::Login', + }, + { + path: 'register', + component: ReplaceableRouteContainerComponent, + canActivate, + data: { + replaceableComponent: { + key: eAccountComponents.Register, + defaultComponent: RegisterComponent, + } as ReplaceableComponents.RouteData, + }, + title: 'AbpAccount::Register', + }, + { + path: 'forgot-password', + component: ReplaceableRouteContainerComponent, + canActivate, + + data: { + replaceableComponent: { + key: eAccountComponents.ForgotPassword, + defaultComponent: ForgotPasswordComponent, + } as ReplaceableComponents.RouteData, + }, + title: 'AbpAccount::ForgotPassword', + }, + { + path: 'reset-password', + component: ReplaceableRouteContainerComponent, + canActivate: [], + data: { + tenantBoxVisible: false, + replaceableComponent: { + key: eAccountComponents.ResetPassword, + defaultComponent: ResetPasswordComponent, + } as ReplaceableComponents.RouteData, + }, + title: 'AbpAccount::ResetPassword', + }, + { + path: 'manage', + component: ReplaceableRouteContainerComponent, + canActivate: [authGuard], + resolve: [accountExtensionsResolver], + data: { + replaceableComponent: { + key: eAccountComponents.ManageProfile, + defaultComponent: ManageProfileComponent, + } as ReplaceableComponents.RouteData, + }, + title: 'AbpAccount::MyAccount', + }, + ], + }, +]; diff --git a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html index 074b6d53ac..a10e190664 100644 --- a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html +++ b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html @@ -1,4 +1,4 @@ - + @if (!hideCurrentPassword) {