diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6842c542ce..b9c94c0106 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,7 +6,7 @@
-
+
@@ -27,7 +27,7 @@
-
+
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
index bd795bb48c..aa16e3931c 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
@@ -563,8 +563,35 @@
"RegistrationUrl": "Registration Url",
"AllowAbpStudioBetaAccess": "Allow ABP Studio Beta Access",
"TotalQuestionCanNotBeNullMessage": "Total Question can not be null",
+ "Permission:OrganizationAutoRenewalPayments": "Organization Auto Renewal Payments",
+ "Permission:RetryFailedPayments": "Retry Failed Payments",
+ "AutoRenewalIsNotEnabled": "Auto Renewal is not enabled!",
+ "LicenseIsNotExpired": "License is not expired!",
+ "PaymentNotFound": "Payment not found!",
+ "PaymentAlreadyTried": "Payment already tried!",
+ "PaymentIsNotFailed": "Payment is not failed!",
+ "OrganizationIdIsNull": "OrganizationId is null!",
+ "Menu:AutoRenewals": "Auto Renewals",
+ "OrganizationAutoRenewalPayments": "Organization Auto Renewal Payments",
+ "PaymentDate": "Payment Date",
+ "TryCount": "Try Count",
+ "ErrorMessage": "Error Message",
+ "ErrorCode": "Error Code",
+ "CreditCard": "Credit Card",
+ "BuyerName": "Buyer Name",
+ "BuyerSurname": "Buyer Surname",
+ "BuyerEmail": "Buyer Email",
+ "AutoRenewalStartTime": "Auto Renewal Start Time",
+ "AutoRenewalEndTime": "Auto Renewal End Time",
+ "AutoRenewalEnabled": "Auto Renewal Enabled",
+ "LastAutoRenewalPaymentTime": "Last Auto Renewal Payment Time",
+ "OrganizationDoesNotHaveACreditCard": "Organization does not have a credit card!",
"Permission:EditWinners": "Edit Winners",
"Permission:ChangeDrawingStatus": "Change Drawing Status",
- "RemoveAllWinnersConfirmationMessage": "Are you sure you want to remove all winners?"
+ "Menu:Licenses": "Licenses",
+ "OrganizationId": "Organization Id",
+ "RemoveAllWinnersConfirmationMessage": "Are you sure you want to remove all winners?",
+ "AutoRenewals": "Auto Renewals",
+ "OrganizationHasCreditCard": "Organization has credit card. Please remove credit card first!"
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
index 0dae45eee8..46bd84d0df 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
@@ -29,6 +29,7 @@
"Volo.AbpIo.Domain:030012": "A user is entitled to have only 1 free trial period. You already used your trial license.",
"Volo.AbpIo.Domain:030013": "A user with an active license cannot start a trial license.",
"Volo.AbpIo.Domain:040000": "Telemetry already exists!.",
+ "Volo.AbpIo.Domain:050000": "Organization has credit card. You can not delete it!",
"Volo.AbpIo.Domain:070000": "The organization name can only contain latin letters, numbers, dots and hyphens!",
"Volo.AbpIo.Domain:070001": "The company name can only contain latin letters, numbers, dots, space and hyphens!",
"WantToLearn?": "Want to learn?",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json
index 7897e0cef2..89d13529a8 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json
@@ -531,8 +531,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "تاريخ بدء الترخيص - تاريخ انتهاء الصلاحية",
"MyOrganizations_Detail_OwnerRightInfo": "أنت تستخدم {0} من {1} حقوق المالك.",
"MyOrganizations_Detail_CopyApiKey": "انسخ المفتاح",
- "MyOrganizations_Detail_ApiKeyDescription": "مفتاح API هو الرمز المميز لحزم PRO المستضافة على {1}.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "مصدر NuGet الخاص بك هو {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "مفتاح API هو الرمز المميز لحزم PRO المستضافة على {1}.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "مصدر NuGet الخاص بك هو {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "تتم إضافة هذا تلقائيًا كوجز إلى NuGet.Config في حل ABP الخاص بك. لا تشارك مفتاحك الخاص مع مستخدمين غير مصرح لهم!",
"MyOrganizations_Detail_DeveloperSeatInfo": "أنت تستخدم {0} من {1} مقاعد مطوري البرامج.",
"NeedMoreSeatsForYourTeam": "هل تحتاج إلى المزيد من المقاعد لفريقك؟",
@@ -615,7 +615,7 @@
"Tools_Page_Description": "يوفر ABP التجاري أدوات تطوير سريعة للتطبيقات لزيادة إنتاجية المطورين. يتيح لك ABP Suite إنشاء صفحات CRUD بسهولة.",
"DeveloperPrice": "سعر المطور",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} مطورين",
- "LicenseRemainingDays": "لمدة {0} يوم",
+ "LicenseRemainingDays": "لمدة {0} يوم",
"ExtendPaymentInfoSection_Description": "من خلال تمديد / تجديد رخصتك، ستستمر في الحصول على الدعم المتميز. ستتمكن أيضًا من الحصول على تحديثات رئيسية أو ثانوية للوحدات والسمات. ستتمكن من الاستمرار في إنشاء مشاريع جديدة. وستظل قادرًا على استخدام ABP Suite مما يسرع من تطويرك.",
"LicenseRenewalPrice": "سعر تجديد الرخصة",
"LicensePrice": "سعر الرخصة",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
index a1fa38028b..e5d8c15ac2 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
@@ -556,8 +556,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "License Start Date - Expiry Date",
"MyOrganizations_Detail_OwnerRightInfo": "You are using {0} of your {1} owners rights.",
"MyOrganizations_Detail_CopyApiKey": "Copy the Key",
- "MyOrganizations_Detail_ApiKeyDescription": "The API Key is the token of PRO packages hosted on {1}.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "Your private NuGet source is {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "The API Key is the token of PRO packages hosted on {1}.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "Your private NuGet source is {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "This is automatically added as a feed to your NuGet.Config in your ABP solution. Do not share your private key with unauthorized users!",
"MyOrganizations_Detail_DeveloperSeatInfo": "You are using {0} of your {1} developer seats.",
"NeedMoreSeatsForYourTeam": "Need more seats for your team?",
@@ -641,7 +641,7 @@
"Tools_Page_Description": "ABP Commercial provides rapid application development tooling to increase developer productivity. ABP Suite allows you to create CRUD pages easily.",
"DeveloperPrice": "Developer Price",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} developers",
- "LicenseRemainingDays": "for {0} days",
+ "LicenseRemainingDays": "for {0} days",
"ExtendPaymentInfoSection_Description": "By extending/renewing your license, you will continue to get premium support. You will also be able to get major or minor updates for modules and themes. You will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development.",
"LicenseRenewalPrice": "License renewal price",
"LicensePrice": "License Price",
@@ -838,7 +838,7 @@
"ModulesPageTitle": "ABP Pre-Built Application Modules",
"Volo.AbpIo.Commercial:040001": "API Access Key is incorrect.",
"GetLepton": "Get Lepton Now",
- "MyOrganizations_Detail_LicenseStartDate": "License Start Date",
+ "MyOrganizations_Detail_LicenseStartDate": "Start Date",
"MyOrganizations_Detail_LicenseExpiryDate": "Expiry Date",
"BlazoriseSupport": "How do I get the Blazorise license key and support from the Blazorise team?",
"BlazoriseSupportExplanation": "Follow the steps below to get support from the Blazorise team and get your Blazorise license key:",
@@ -1090,8 +1090,46 @@
"AbpStudioBetaAccessInfoTitle": "ABP Studio Beta Access",
"AbpStudioBetaAccessInfoText": "We're thrilled to share with you the beta version of ABP Studio! This release marks a significant milestone in our development journey, and we're eager to gather your feedback to make the application even better.",
"YouAreNotAuthorizedToDownloadStudio": "You are not authorized to download ABP Studio.",
+ "OrganizationHasNoDefaultCreditCard": "Your organization has no default credit card. Please add a credit card to your organization.",
+ "YouAreNotAuthorizedToPayThisPaymentRequest": "You are not authorized to pay this payment request.",
+ "YouAreNotAuthorizedToCreateBillingInfoForThisPaymentRequest": "You are not authorized to create billing info for this payment request.",
+ "OrganizationNotFound": "Organization not found.",
+ "CannotDeleteDefaultCardBecauseAutoRenewalEnabled": "You cannot delete this card at the moment because the Auto-Renewal feature is enabled. To delete the card, first disable Auto-Renewal.",
+ "AreYouSureWantToDeleteThisCard": "Are you sure you want to delete this card?",
+ "AreYouSureWantToSetThisCardAsDefault": "Are you sure you want to set this card as default?",
+ "OrganizationBillingInfoIsNotSuitableForIyzicoPayment": "Your organization's billing info is not suitable for iyzico payment.",
+ "AutomaticRenewal": "Automatic Renewal",
+ "AutomaticRenewal_Description": "Renewing a license before it expires lets you get a discount of up to %40. The auto-renewal process lets you renew your license without losing this discount, and your development will never interrupt. Auto-renewal is only available for credit card payment. You can disable auto-renewal at any time by accessing your Organization Management page. ABP does not save your credit card information, but our global payment gateways do secure savings.",
+ "CardNotFoundMessage": "Do you want to add a new card?",
+ "CardNotFoundTitle": "Card Not Found",
+ "AutoRenewalEnabled": "Auto Renewal Enabled",
+ "AutoRenewalDisabled": "Auto Renewal Disabled",
+ "PaymentRequestIdIsNotProvided": "Payment request id is not provided.",
"PaymentFailedInfo": "Sorry, payment failed! This could be due to insufficient funds, invalid credit card numbers or invalid pin",
"UsedPayment": "This payment has been already used",
+ "ABPStudioBetaAccess": "ABP Studio Beta Access",
+ "VisitABPStudio": "Visit ABP Studio",
+ "EditBillingInformation": "Edit Billing Information",
+ "Organization": "Organization",
+ "E-Book": "E-Book",
+ "CreditCards": "Credit Cards",
+ "BillingInformation": "Billing Information",
+ "AddNewCreditCard": "Add New Credit Card",
+ "MyOrganizations_LearnMorePlan": "Learn more about plans on the pricing page",
+ "AutoLicenseRenewalIsNotEnabled": "Auto license renewal is not enabled.",
+ "SetAsDefaultPaymentMethod": "Set as default payment method",
+ "{0}PerAdditionalDeveloper": "{0} per additional developer",
+ "CardAlias": "Card Alias",
+ "AbpDoesNotSaveYourPaymentDetails_Description": "The payment data will be saved in {2} security vaults and you can remove stored data anytime. Enabling auto-renewal ensures that your ABP subscription will automatically renew prior to expiration, providing a valid credit card. Disabling auto-renewal means you will have to renew your subscription manually. To continue your project development without interruption, we suggest you enable the Auto-Renewal option.",
+ "AddBillingInformation": "Add Billing Information",
+ "YouHaveNoCardsSaved": "You have no cards saved.",
+ "CreateCreditCardModal_BillingDetails_Description": "You must save your billing details to be able to add your credit card.",
+ "TaxNo": "Tax No",
+ "CardNumber": "Card Number",
+ "NameOnCard": "Name on Card",
+ "BillingDetails": "Billing Details",
+ "ThereIsNoDeveloper": "There is no developer.",
+ "CardDetails": "Card Details",
"NoActiveLicence": "You are not eligible for this action! You have no active license."
}
}
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
index a1be88768f..1311b5012a 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
@@ -553,8 +553,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "Lisenssin alkamispäivä - viimeinen voimassaolopäivä",
"MyOrganizations_Detail_OwnerRightInfo": "Käytät {0} {1} omistajan oikeuksistasi.",
"MyOrganizations_Detail_CopyApiKey": "Kopioi avain",
- "MyOrganizations_Detail_ApiKeyDescription": "API-avain on {1}-palvelussa isännöivien PRO-pakettien tunnus.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "Yksityinen NuGet-lähteesi on {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "API-avain on {1}-palvelussa isännöivien PRO-pakettien tunnus.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "Yksityinen NuGet-lähteesi on {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "Tämä lisätään automaattisesti syötteeksi NuGet.Configiin ABP-ratkaisussasi. Älä jaa yksityistä avaintasi luvattomien käyttäjien kanssa!",
"MyOrganizations_Detail_DeveloperSeatInfo": "Käytät {0} {1} kehittäjäpaikastasi.",
"NeedMoreSeatsForYourTeam": "Tarvitsetko lisää paikkoja tiimillesi?",
@@ -639,7 +639,7 @@
"Tools_Page_Description": "ABP Commercial tarjoaa nopeat sovelluskehitystyökalut kehittäjien tuottavuuden lisäämiseksi. ABP Suiten avulla voit luoda CRUD-sivuja helposti.",
"DeveloperPrice": "Kehittäjän hinta",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} kehittäjät",
- "LicenseRemainingDays": " {0} päivän ajan",
+ "LicenseRemainingDays": " {0} päivän ajan",
"ExtendPaymentInfoSection_Description": "Pidentämällä/uusimalla käyttölupaasi saat edelleen premium-tuen. Voit myös saada suurempia tai pieniä päivityksiä moduuleille ja teemoille. Voit jatkaa uusien projektien luomista. Voit silti käyttää ABP Suitea, joka nopeuttaa kehitystäsi.",
"LicenseRenewalPrice": "Lisenssin uusimisen hinta",
"LicensePrice": "Lisenssin hinta",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json
index 762376d384..7bd6c24cad 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json
@@ -556,8 +556,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "Datum početka licence - Datum isteka",
"MyOrganizations_Detail_OwnerRightInfo": "Koristite {0} od svojih {1} vlasničkih prava.",
"MyOrganizations_Detail_CopyApiKey": "Kopirajte ključ",
- "MyOrganizations_Detail_ApiKeyDescription": "API ključ je token PRO paketa hostiranih na {1}.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "Vaš privatni NuGet izvor je {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "API ključ je token PRO paketa hostiranih na {1}.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "Vaš privatni NuGet izvor je {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "Ovo se automatski dodaje kao feed u vaš NuGet.Config u vašem ABP rješenju. Ne dijelite svoj privatni ključ s neovlaštenim korisnicima!",
"MyOrganizations_Detail_DeveloperSeatInfo": "Koristite {0} od svojih {1} razvojnih mjesta.",
"NeedMoreSeatsForYourTeam": "Trebate više mjesta za svoj tim?",
@@ -641,7 +641,7 @@
"Tools_Page_Description": "ABP Commercial pruža alate za brzi razvoj aplikacija za povećanje produktivnosti programera. ABP Suite vam omogućuje jednostavno stvaranje CRUD stranica.",
"DeveloperPrice": "Cijena programera",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} programeri",
- "LicenseRemainingDays": "za {0} dana",
+ "LicenseRemainingDays": "za {0} dana",
"ExtendPaymentInfoSection_Description": "Produljenjem/obnavljanjem licence i dalje ćete dobivati premium podršku . Također ćete moći dobiti veća ili manja ažuriranja za module i teme. Moći ćete nastaviti stvarati nove projekte. I dalje ćete moći koristiti ABP Suite koji ubrzava vaš razvoj.",
"LicenseRenewalPrice": "Cijena obnove licence",
"LicensePrice": "Cijena licence",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json
index 0a3dd2894c..7795f3830b 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json
@@ -554,8 +554,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "licensz kezdő dátuma – lejárati dátum",
"MyOrganizations_Detail_OwnerRightInfo": "Ön {1} tulajdonosi jogának {0}-át használja.",
"MyOrganizations_Detail_CopyApiKey": "Másolja ki a kulcsot",
- "MyOrganizations_Detail_ApiKeyDescription": "Az API-kulcs a(z) {1} webhelyen tárolt PRO-csomagok tokenje.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "Az Ön privát NuGet-forrása {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "Az API-kulcs a(z) {1} webhelyen tárolt PRO-csomagok tokenje.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "Az Ön privát NuGet-forrása {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "Ez automatikusan hozzáadódik feedként a NuGet.Config-hoz az ABP-megoldásban. Ne ossza meg privát kulcsát illetéktelen felhasználókkal!",
"MyOrganizations_Detail_DeveloperSeatInfo": "Ön {1} fejlesztői helyéből {0}-ot használ.",
"NeedMoreSeatsForYourTeam": "Több hozzáférésre van szüksége a csapatának?",
@@ -639,7 +639,7 @@
"Tools_Page_Description": "Az ABP Commercial gyors alkalmazásfejlesztési eszközöket biztosít a fejlesztők termelékenységének növelése érdekében. Az ABP Suite segítségével könnyedén hozhat létre CRUD oldalakat.",
"DeveloperPrice": "Fejlesztői ár",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} fejlesztő",
- "LicenseRemainingDays": "{0} napig",
+ "LicenseRemainingDays": "{0} napig",
"ExtendPaymentInfoSection_Description": "A licensz meghosszabbításával/megújításával továbbra is prémium támogatást kap. Emellett kisebb-nagyobb frissítéseket is kaphat a modulokhoz és témákhoz. Folytathatja új projektek létrehozását. És továbbra is használhatja az ABP Suite -ot, amely felgyorsítja a fejlesztést.",
"LicenseRenewalPrice": "Licensz megújítási ára",
"LicensePrice": "Licensz ára",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json
index 6d93f7108d..d167a86866 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json
@@ -557,8 +557,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "Дата начала действия лицензии – дата истечения срока действия",
"MyOrganizations_Detail_OwnerRightInfo": "Вы используете {0} ваших прав владельца {1}.",
"MyOrganizations_Detail_CopyApiKey": "Скопируйте ключ",
- "MyOrganizations_Detail_ApiKeyDescription": "Ключ API — это токен PRO-пакетов, размещенных на {1}.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "Ваш личный источник NuGet: {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "Ключ API — это токен PRO-пакетов, размещенных на {1}.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "Ваш личный источник NuGet: {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "Он автоматически добавляется в качестве канала в ваш NuGet.Config в вашем решении ABP. ",
"MyOrganizations_Detail_DeveloperSeatInfo": "Вы используете {0} из {1} мест разработчика.",
"NeedMoreSeatsForYourTeam": "Вам нужно больше мест для вашей команды?",
@@ -642,7 +642,7 @@
"Tools_Page_Description": "ABP Commercial предоставляет инструменты для быстрой разработки приложений, позволяющие повысить продуктивность разработчиков. ",
"DeveloperPrice": "Цена застройщика",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} Разработчики",
- "LicenseRemainingDays": "для {0} дни",
+ "LicenseRemainingDays": "для {0} дни",
"ExtendPaymentInfoSection_Description": "Продлив/продлив лицензию, вы продолжите получать премиум-поддержка. ABP Люкс что ускоряет ваше развитие.",
"LicenseRenewalPrice": "Стоимость продления лицензии",
"LicensePrice": "Цена лицензии",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
index 546fea32c7..1d933b2704 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
@@ -563,8 +563,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "Lisans Başlangıç Tarihi - Sona Erme Tarihi",
"MyOrganizations_Detail_OwnerRightInfo": "{1} sahiplik hakkınızın {0}'ını kullanıyorsunuz.",
"MyOrganizations_Detail_CopyApiKey": "Anahtarı Kopyala",
- "MyOrganizations_Detail_ApiKeyDescription": "API Anahtarı, {1} üzerinde barındırılan PRO paketlerinin belirtecidir.",
- "MyOrganizations_Detail_YourPrivateNugetSource": "Özel NuGet kaynağınız {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "API Anahtarı, {1} üzerinde barındırılan PRO paketlerinin belirtecidir.",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "Özel NuGet kaynağınız {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "Bu, ABP çözümünüzdeki NuGet.Config'inize otomatik olarak bir besleme olarak eklenir. Özel anahtarınızı yetkisiz kullanıcılarla paylaşmayın!",
"MyOrganizations_Detail_DeveloperSeatInfo": "{1} geliştirici koltuğunuzun {0} tanesini kullanıyorsunuz.",
"NeedMoreSeatsForYourTeam": "Takımınız için daha fazla geliştirici koltuğu gerekiyor mu?",
@@ -648,7 +648,7 @@
"Tools_Page_Description": "ABP Commercial, geliştirici verimliliğini artırmak için hızlı uygulama geliştirme araçları sağlar. ABP Suite, CRUD sayfalarını kolayca oluşturmanızı sağlar.",
"DeveloperPrice": "Geliştirici Fiyatı",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} geliştiriciler",
- "LicenseRemainingDays": " {0} gün boyunca",
+ "LicenseRemainingDays": " {0} gün boyunca",
"ExtendPaymentInfoSection_Description": "Lisansınızı uzatarak/yenileyerek premium destek almaya devam edeceksiniz. You will also be able to get major or minor updates for modules and themes. You will be able to continue creating new projects. Ve gelişiminizi hızlandıran ABP Suite'i kullanmaya devam edebileceksiniz.",
"LicenseRenewalPrice": "Lisans yenileme fiyatı",
"LicensePrice": "Lisans fiyatı",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
index db53fde072..37d63cf826 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
@@ -556,8 +556,8 @@
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "许可证开始日期 - 到期日期",
"MyOrganizations_Detail_OwnerRightInfo": "您正在使用{1}所有者权利中的{0}项权利。",
"MyOrganizations_Detail_CopyApiKey": "复制密钥",
- "MyOrganizations_Detail_ApiKeyDescription": "API 密钥是 {1}. 上托管的 PRO 包的标记。",
- "MyOrganizations_Detail_YourPrivateNugetSource": "您的 NuGet 私有源是 {0}",
+ "MyOrganizations_Detail_ApiKeyDescription": "API 密钥是 {1}. 上托管的 PRO 包的标记。",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "您的 NuGet 私有源是 {0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "此密钥会自动添加到 ABP 解决方案中的 NuGet.Config 中。请勿与未经授权的用户共享您的私人密钥!",
"MyOrganizations_Detail_DeveloperSeatInfo": "您正在使用{1}个开发人员席位中的{0}个。",
"NeedMoreSeatsForYourTeam": "您的团队需要更多座位?",
@@ -641,7 +641,7 @@
"Tools_Page_Description": "ABP 商业版提供快速应用程序开发工具,以提高开发人员的工作效率。ABP Suite 可让您轻松创建 CRUD 页面。",
"DeveloperPrice": "开发者价格",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0}<小>开发人员小",
- "LicenseRemainingDays": "为 {0} 天",
+ "LicenseRemainingDays": "为 {0} 天",
"ExtendPaymentInfoSection_Description": "延长/续订许可证后,您将继续获得高级支持。您还可以获得模块和主题的主要或次要更新。您还可以继续创建新项目。您还可以使用 ABP Suite 来加快开发速度。",
"LicenseRenewalPrice": "许可证续期价格",
"LicensePrice": "许可证价格",
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
index 447732cec2..8ef66674b7 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
@@ -545,7 +545,7 @@
"MyOrganizations_Detail_OwnerRightInfo": "您正在使用您的 {1} 項所有者權利中的 {0} 項。",
"MyOrganizations_Detail_CopyApiKey": "複製密鑰",
"MyOrganizations_Detail_ApiKeyDescription": "API 金鑰是{1} 上託管的 PRO 包的令牌。",
- "MyOrganizations_Detail_YourPrivateNugetSource": "您的私有 NuGet 來源是{0}",
+ "MyOrganizations_Detail_YourPrivateNugetSource": "您的私有 NuGet 來源是{0}",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "這會作為 feed 自動添加到 ABP 解決方案中的 NuGet.Config 中。不要與未經授權的用戶分享您的私鑰!",
"MyOrganizations_Detail_DeveloperSeatInfo": "您正在使用 {1} 個開發者席位中的 {0} 個。",
"NeedMoreSeatsForYourTeam": "您的團隊需要更多座位嗎?",
@@ -628,7 +628,7 @@
"Tools_Page_Description": "ABP Commercial 提供快速應用程式開發工具來提高開發人員的工作效率。 ABP Suite 讓您輕鬆建立 CRUD 頁面。",
"DeveloperPrice": "開發商價格",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0}開發者",
- "LicenseRemainingDays": "{0}天",
+ "LicenseRemainingDays": "{0}天",
"ExtendPaymentInfoSection_Description": "透過延長/更新您的許可證,您將繼續獲得高級支援。您還可以獲得模組和主題的主要或次要更新。您將能夠繼續建立新專案。而且您仍然可以使用ABP Suite來加快您的開發速度。",
"LicenseRenewalPrice": "許可證更新價格",
"LicensePrice": "許可價格",
diff --git a/docs/en/Getting-Started-Running-Solution.md b/docs/en/Getting-Started-Running-Solution.md
index 921fb2b247..d71c0a64da 100644
--- a/docs/en/Getting-Started-Running-Solution.md
+++ b/docs/en/Getting-Started-Running-Solution.md
@@ -127,6 +127,29 @@ abp bundle
> **Note**: Before starting the application, run `abp install-libs` command in your Web directory to restore the client-side libraries. This will populate the `libs` folder.
+{{ if UI == "BlazorServer" }}
+
+> **Important:** The `.AuthServer` application serves as the **Authentication Server** for the `.Blazor` application. It is essential to have the `.AuthServer` application running in the background to ensure the proper functioning of the `.Blazor` application.
+
+To do this, open terminal in `.AuthServer` project folder and run the following command.
+
+````bash
+dotnet run
+````
+
+Once the `.AuthServer`application has started, it is time to run `.HttpApi.Host` application.
+
+> **Important:** Prior to launching the `.Blazor` project, it is essential to execute the `.HttpApi.Host` application as well.
+
+To do this, open terminal in `.HttpApi.Host` project folder and run the following command.
+
+````bash
+dotnet run
+````
+Once the `.AuthServer` and `.HttpApi.Host` applications has started, you can proceed to run the `.Blazor` project.
+
+{{ end # UI }}
+
{{ if Tiered == "Yes" }}
> Tiered solutions use **Redis** as the distributed cache. Ensure that it is installed and running in your local computer. If you are using a remote Redis Server, set the configuration in the `appsettings.json` files of the projects below.
@@ -195,6 +218,16 @@ You can see the application APIs and test them here. Get [more info](https://swa
### Running the Blazor Application (Client Side)
+> **Important:** The `.HttpApi.Host` application serves as the **Authentication Server** for the `.Blazor` application. It is essential to have the `.HttpApi.Host` application running in the background to ensure the proper functioning of the `.Blazor` application.
+
+To do this, you can open terminal in `.HttpApi.Host` project folder and run the following command.
+
+````bash
+dotnet run
+````
+
+Once the `.HttpApi.Host` application has started, you can proceed to run the `.Blazor` application.
+
Ensure that the `.Blazor` project is the startup project and run the application.
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.
diff --git a/docs/en/Migration-Guides/Abp-8_0.md b/docs/en/Migration-Guides/Abp-8_0.md
index 8214dfef1a..09e44b7ec8 100644
--- a/docs/en/Migration-Guides/Abp-8_0.md
+++ b/docs/en/Migration-Guides/Abp-8_0.md
@@ -181,7 +181,7 @@ You can see the following list of NuGet libraries that have been upgraded with .
| Dapper | 2.0.123 | 2.1.21 |
| Dapr.AspNetCore | 1.9.0 | 1.12.0 |
| Dapr.Client | 1.9.0 | 1.12.0 |
-| Devart.Data.Oracle.EFCore | 10.1.134.7 | 10.1.151.7 |
+| Devart.Data.Oracle.EFCore | 10.1.134.7 | 10.3.10.8 |
| DistributedLock.Core | 1.0.4 | 1.0.5 |
| DistributedLock.Redis | 1.0.1 | 1.0.2 |
| EphemeralMongo.Core | 1.1.0 | 1.1.3 |
diff --git a/docs/en/UI/Angular/HTTP-Error-Handling.md b/docs/en/UI/Angular/HTTP-Error-Handling.md
new file mode 100644
index 0000000000..606211bfeb
--- /dev/null
+++ b/docs/en/UI/Angular/HTTP-Error-Handling.md
@@ -0,0 +1,197 @@
+# HTTP Error Handling
+
+When the `RestService` is used, all HTTP errors are reported to the [`HttpErrorReporterService`](./HTTP-Error-Reporter-Service), and then `ErrorHandler`, a service exposed by the `@abp/ng.theme.shared` package automatically handles the errors.
+
+## Custom HTTP Error Handler
+
+### Function Method `Deprecated`
+
+A custom HTTP error handler can be registered to an injection token named `HTTP_ERROR_HANDLER`. If a custom handler function is registered, the `ErrorHandler` executes that function.
+
+See an example:
+
+```ts
+// http-error-handler.ts
+import { ContentProjectionService, PROJECTION_STRATEGY } from '@abp/ng.core';
+import { ToasterService } from '@abp/ng.theme.shared';
+import { HttpErrorResponse } from '@angular/common/http';
+import { Injector } from '@angular/core';
+import { of, EMPTY } from 'rxjs';
+import { Error404Component } from './error404/error404.component';
+
+export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
+ if (httpError.status === 400) {
+ const toaster = injector.get(ToasterService);
+ toaster.error(httpError.error?.error?.message || 'Bad request!', '400');
+ return EMPTY;
+ }
+
+ if (httpError.status === 404) {
+ const contentProjection = injector.get(ContentProjectionService);
+ contentProjection.projectContent(PROJECTION_STRATEGY.AppendComponentToBody(Error404Component));
+ return EMPTY;
+ }
+
+ return of(httpError);
+}
+
+// app.module.ts
+import { Error404Component } from './error404/error404.component';
+import { handleHttpErrors } from './http-error-handling';
+import { HTTP_ERROR_HANDLER, ... } from '@abp/ng.theme.shared';
+
+@NgModule({
+ // ...
+ providers: [
+ // ...
+ { provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors }
+ ],
+ declarations: [
+ //...
+ Error404Component],
+})
+export class AppModule {}
+```
+
+In the example above:
+
+- Created a function named `handleHttpErrors` and defined as value of the `HTTP_ERROR_HANDLER` provider in app.module. After this, the function executes when an HTTP error occurs.
+- 400 bad request errors is handled. When a 400 error occurs.
+
+- Since `of(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors.
+
+**Note 1:** If you put `return EMPTY` to next line of handling an error, default error handling will not work for that error. [EMPTY](https://rxjs.dev/api/index/const/EMPTY) can be imported from `rxjs`.
+
+```ts
+export function handleHttpErrors(
+ injector: Injector,
+ httpError: HttpErrorResponse
+) {
+ if (httpError.status === 403) {
+ // handle 403 errors here
+ return EMPTY; // put return EMPTY to skip default error handling
+ }
+}
+```
+
+**Note 2:** If you put `return of(httpError)`, default error handling will work.
+
+- `of` is a function. It can be imported from `rxjs`.
+- `httpError` is the second parameter of the error handler function which is registered to the `HTTP_ERROR_HANDLER` provider. Type of the `httpError` is `HttpErrorResponse`.
+
+```ts
+import { of } from "rxjs";
+
+export function handleHttpErrors(
+ injector: Injector,
+ httpError: HttpErrorResponse
+) {
+ if (httpError.status === 500) {
+ // handle 500 errors here
+ }
+
+ // you can return the of(httpError) at bottom of the function to run the default handler of ABP for HTTP errors that you didn't handle above.
+ return of(httpError);
+}
+```
+
+### Service Method
+
+You can provide **more than one handler** with services, a custom HTTP error handler service can be registered with injection token named **`CUSTOM_ERROR_HANDLERS`**. ABP has some default [error handlers](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/theme-shared/src/lib/providers/error-handlers.provider.ts).
+
+### How To Add New Handler Service
+
+ABP error handler services are implements the interface of **CustomHttpErrorHandlerService**.
+
+**Interface of `CUSTOM_ERROR_HANDLERS`**
+
+```ts
+interface CustomHttpErrorHandlerService {
+ readonly priority: number;
+ canHandle(error: unknown): boolean;
+ execute(): void;
+}
+```
+
+- **`priority`** ABP sorts the services according to the number of the priority variable. Higher priority will be checked first.
+- **`canHandle`** Check if the service can handle the error. Returns boolean.
+- **`execute`** If the service can handle the error, then run the execute method.
+
+**In Summary**
+
+- Services are sorted by their priority number.
+- Start from highest priority service and run canHandle() method. Pick the service if can handle the error, if not check next service.
+- If the service found, run the execute method of a service. Done.
+
+See an example:
+
+```ts
+// custom-error-handler.service.ts
+import { inject, Injectable } from "@angular/core";
+import { HttpErrorResponse } from "@angular/common/http";
+import { CustomHttpErrorHandlerService } from "@abp/ng.theme.shared";
+import { CUSTOM_HTTP_ERROR_HANDLER_PRIORITY } from "@abp/ng.theme.shared";
+import { ToasterService } from "@abp/ng.theme.shared";
+
+@Injectable({ providedIn: "root" })
+export class MyCustomErrorHandlerService
+ implements CustomHttpErrorHandlerService
+{
+ // You can write any number here, ex: 9999
+ readonly priority = CUSTOM_HTTP_ERROR_HANDLER_PRIORITY.veryHigh;
+ protected readonly toaster = inject(ToasterService);
+ private error: HttpErrorResponse | undefined = undefined;
+
+ // What kind of error should be handled by this service? You can decide it in this method. If error is suitable to your case then return true; otherwise return false.
+ canHandle(error: unknown): boolean {
+ if (error instanceof HttpErrorResponse && error.status === 400) {
+ this.error = error;
+ return true;
+ }
+ return false;
+ }
+
+ // If this service is picked from ErrorHandler, this execute method will be called.
+ execute() {
+ this.toaster.error(
+ this.error.error?.error?.message || "Bad request!",
+ "400"
+ );
+ }
+}
+```
+
+```ts
+
+// app.module.ts
+import { CUSTOM_ERROR_HANDLERS, ... } from '@abp/ng.theme.shared';
+import { MyCustomErrorHandlerService } from './custom-error-handler.service';
+
+@NgModule({
+ // ...
+ providers: [
+ // ...
+ {
+ provide: CUSTOM_ERROR_HANDLERS,
+ useExisting: MyCustomErrorHandlerService,
+ multi: true,
+ }
+ ]
+})
+export class AppModule {}
+```
+
+In the example above:
+
+- Created a service named `MyCustomErrorHandlerService`, and provided via `useExisting` key because we dont want another instance of it. And set `multi` key to true because ABP default error handlers are also provided with **CUSTOM_ERROR_HANDLERS** injection token.
+
+- 400 errors are handled from custom `MyCustomErrorHandlerService`. When a 400 error occurs, backend error message will be displayed as shown below:
+
+
+
+### Notes
+
+- If your service cannot handle the error. Then ABP will check the next Error Service.
+- If none of the service handle the error. Then basic confirmation message about the error will be shown to the user.
+- You can provide more than one service, with CUSTOM_ERROR_HANDLER injection token.
+- If you want your custom service to be evaluated (checked) earlier, set the priority variable high.
diff --git a/docs/en/UI/Angular/HTTP-Requests.md b/docs/en/UI/Angular/HTTP-Requests.md
index a0e53df9c9..9bef5cb8f2 100644
--- a/docs/en/UI/Angular/HTTP-Requests.md
+++ b/docs/en/UI/Angular/HTTP-Requests.md
@@ -1,7 +1,5 @@
# How to Make HTTP Requests
-
-
## About HttpClient
Angular has the amazing [HttpClient](https://angular.io/guide/http) for communication with backend services. It is a layer on top and a simplified representation of [XMLHttpRequest Web API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest). It also is the recommended agent by Angular for any HTTP request. There is nothing wrong with using the `HttpClient` in your ABP project.
@@ -23,14 +21,10 @@ Although clear and flexible, handling errors this way is repetitive work, even w
An `HttpInterceptor` is able to catch `HttpErrorResponse` and can be used for a centralized error handling. Nevertheless, cases where default error handler, therefore the interceptor, must be disabled require additional work and comprehension of Angular internals. Check [this issue](https://github.com/angular/angular/issues/20203) for details.
-
-
## RestService
ABP core module has a utility service for HTTP requests: `RestService`. Unless explicitly configured otherwise, it catches HTTP errors and dispatches a `RestOccurError` action. This action is then captured by the `ErrorHandler` introduced by the `ThemeSharedModule`. Since you should already import this module in your app, when the `RestService` is used, all HTTP errors get automatically handled by default.
-
-
### Getting Started with RestService
In order to use the `RestService`, you must inject it in your class as a dependency.
@@ -48,11 +42,9 @@ class DemoService {
You do not have to provide the `RestService` at module or component/directive level, because it is already **provided in root**.
-
-
### How to Make a Request with RestService
-You can use the `request` method of the `RestService` is for HTTP requests. Here is an example:
+You can use the `request` method of the `RestService` is for HTTP requests. Here is an example:
```js
getFoo(id: number) {
@@ -65,8 +57,6 @@ getFoo(id: number) {
}
```
-
-
The `request` method always returns an `Observable`. Therefore you can do the following wherever you use `getFoo` method:
```js
@@ -79,12 +69,8 @@ doSomethingWithFoo(id: number) {
}
```
-
-
**You do not have to worry about unsubscription.** The `RestService` uses `HttpClient` behind the scenes, so every observable it returns is a finite observable, i.e. it closes subscriptions automatically upon success or error.
-
-
As you see, `request` method gets a request options object with `Rest.Request` type. This generic type expects the interface of the request body. You may pass `null` when there is no body, like in a `GET` or a `DELETE` request. Here is an example where there is one:
```js
@@ -99,11 +85,7 @@ postFoo(body: Foo) {
}
```
-
-
-You may [check here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L23) for complete `Rest.Request` type, which has only a few changes compared to [HttpRequest](https://angular.io/api/common/http/HttpRequest) class in Angular.
-
-
+You may [check here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L23) for complete `Rest.Request` type, which has only a few changes compared to [HttpRequest](https://angular.io/api/common/http/HttpRequest) class in Angular.
### How to Disable Default Error Handler of RestService
@@ -120,8 +102,6 @@ deleteFoo(id: number) {
}
```
-
-
`skipHandleError` config option, when set to `true`, disables the error handler and the returned observable starts throwing an error that you can catch in your subscription.
```js
@@ -137,14 +117,10 @@ removeFooFromList(id: number) {
}
```
-
-
### How to Get a Specific API Endpoint From Application Config
Another nice config option that `request` method receives is `apiName` (available as of v2.4), which can be used to get a specific module endpoint from application configuration.
-
-
```js
putFoo(body: Foo, id: string) {
const request: Rest.Request = {
@@ -157,8 +133,6 @@ putFoo(body: Foo, id: string) {
}
```
-
-
`putFoo` above will request `https://localhost:44305/api/some/path/to/foo/{id}` as long as the environment variables are as follows:
```js
@@ -167,19 +141,17 @@ putFoo(body: Foo, id: string) {
export const environment = {
apis: {
default: {
- url: 'https://localhost:44305',
+ url: "https://localhost:44305",
},
foo: {
- url: 'https://localhost:44305/api/some/path/to/foo',
+ url: "https://localhost:44305/api/some/path/to/foo",
},
},
-
+
/* rest of the environment variables here */
-}
+};
```
-
-
### How to Observe Response Object or HTTP Events Instead of Body
`RestService` assumes you are generally interested in the body of a response and, by default, sets `observe` property as `'body'`. However, there may be times you are rather interested in something else, such as a custom proprietary header. For that, the `request` method receives `observe` property in its config object.
@@ -202,104 +174,6 @@ getSomeCustomHeaderValue() {
You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10).
-
-## HTTP Error Handling
-
-When the `RestService` is used, all HTTP errors are reported to the [`HttpErrorReporterService`](./HTTP-Error-Reporter-Service), and then `ErrorHandler`, a service exposed by the `@abp/ng.theme.shared` package automatically handles the errors.
-
-### Custom HTTP Error Handler
-
-A custom HTTP error handler can be registered to an injection token named `HTTP_ERROR_HANDLER`. If a custom handler function is registered, the `ErrorHandler` executes that function.
-
-See an example:
-
-```js
-// http-error-handler.ts
-import { ContentProjectionService, PROJECTION_STRATEGY } from '@abp/ng.core';
-import { ToasterService } from '@abp/ng.theme.shared';
-import { HttpErrorResponse } from '@angular/common/http';
-import { Injector } from '@angular/core';
-import { throwError } from 'rxjs';
-import { Error404Component } from './error404/error404.component';
-
-export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
- if (httpError.status === 400) {
- const toaster = injector.get(ToasterService);
- toaster.error(httpError.error?.error?.message || 'Bad request!', '400');
- return;
- }
-
- if (httpError.status === 404) {
- const contentProjection = injector.get(ContentProjectionService);
- contentProjection.projectContent(PROJECTION_STRATEGY.AppendComponentToBody(Error404Component));
- return;
- }
-
- return throwError(httpError);
-}
-
-// app.module.ts
-import { Error404Component } from './error404/error404.component';
-import { handleHttpErrors } from './http-error-handling';
-import { HTTP_ERROR_HANDLER, ... } from '@abp/ng.theme.shared';
-
-@NgModule({
- // ...
- providers: [
- // ...
- { provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors }
- ],
- declarations: [
- //...
- Error404Component],
-})
-export class AppModule {}
-```
-
-In the example above:
-
- - Created a function named `handleHttpErrors` and defined as value of the `HTTP_ERROR_HANDLER` provider in app.module. After this, the function executes when an HTTP error occurs.
- - 400 bad request errors is handled. When a 400 error occurs, backend error message will be displayed as shown below:
-
- 
-
- - 404 not found errors is handled. When a 404 error occurs, `Error404Component` will be appended to the `` as shown below:
-
-
-
- - Since `throwError(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors.
-
-
-**Note 1:** If you put `return` to next line of handling an error, default error handling will not work for that error.
-
-```js
-export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
- if (httpError.status === 403) {
- // handle 403 errors here
- return; // put return to skip default error handling
- }
-}
-```
-
-**Note 2:** If you put `return throwError(httpError)`, default error handling will work.
- - `throwError` is a function. It can be imported from `rxjs`.
- - `httpError` is the second parameter of the error handler function which is registered to the `HTTP_ERROR_HANDLER` provider. Type of the `httpError` is `HttpErrorResponse`.
-
-```js
-import { throwError } from 'rxjs';
-
-export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
- if (httpError.status === 500) {
- // handle 500 errors here
- return;
- }
-
- // you can return the throwError(httpError) at bottom of the function to run the default handler of ABP for HTTP errors that you didn't handle above.
- return throwError(httpError)
-}
-```
-
-
### How to Skip HTTP interceptors and ABP headers
The ABP Framework adds several HTTP headers to the HttpClient, such as the "Auth token" or "tenant Id".
@@ -309,4 +183,8 @@ The ABP Http interceptors check the value of the `IS_EXTERNAL_REQUEST` token. If
The `ExternalHttpClient` extends from `HTTPClient` and sets the `IS_EXTERNAL_REQUEST` context token to true.
When you are using `ExternalHttpClient` as HttpClient in your components, it does not add ABP-specific headers.
-Note: With `IS_EXTERNAL_REQUEST` or without it, ABP loading service works.
+Note: With `IS_EXTERNAL_REQUEST` or without it, ABP loading service works.
+
+## See Also
+
+- [HTTP Error Handling / Customization](./HTTP-Error-Handling)
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index 86b58938aa..eeefa3d06e 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -1053,7 +1053,16 @@
},
{
"text": "HTTP Requests",
- "path": "UI/Angular/HTTP-Requests.md"
+ "items": [
+ {
+ "text": "How to Make HTTP Requests",
+ "path": "UI/Angular/HTTP-Requests.md"
+ },
+ {
+ "text": "HTTP Error Handling / Customization",
+ "path": "UI/Angular/HTTP-Error-Handling.md"
+ }
+ ]
},
{
"text": "Localization",
@@ -1173,8 +1182,8 @@
"path": "UI/Angular/Content-Security-Strategy.md"
},
{
- "text":"Abp Window Service",
- "path":"UI/Angular/Abp-Window-Service.md"
+ "text": "Abp Window Service",
+ "path": "UI/Angular/Abp-Window-Service.md"
}
]
},
diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj
index 70d234cd20..bb46006ac9 100644
--- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj
+++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj
@@ -21,7 +21,6 @@
-
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs
index 74aac7b814..a8908129d2 100644
--- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs
@@ -10,7 +10,7 @@ public interface IMenuItemAdminAppService : IApplicationService
{
Task> GetListAsync();
- Task GetAsync(Guid id);
+ Task GetAsync(Guid id);
Task CreateAsync(MenuItemCreateInput input);
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/MenuItemWithDetailsDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/MenuItemWithDetailsDto.cs
new file mode 100644
index 0000000000..a6d9906157
--- /dev/null
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/MenuItemWithDetailsDto.cs
@@ -0,0 +1,10 @@
+using System;
+using Volo.CmsKit.Menus;
+
+namespace Volo.CmsKit.Admin.Menus;
+
+[Serializable]
+public class MenuItemWithDetailsDto : MenuItemDto
+{
+ public string? PageTitle { get; set; }
+}
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
index 56f58f8078..1394b608c7 100644
--- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs
@@ -46,5 +46,8 @@ public class CmsKitAdminApplicationAutoMapperProfile : Profile
CreateMap().MapExtraProperties();
CreateMap