diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml index 92121c4fe8..c9d39fad30 100644 --- a/.github/workflows/auto-pr.yml +++ b/.github/workflows/auto-pr.yml @@ -1,13 +1,13 @@ -name: Merge branch rel-7.2 with rel-7.1 +name: Merge branch dev with rel-7.2 on: push: branches: - - rel-7.1 + - rel-7.2 permissions: contents: read jobs: - merge-rel-7-2-with-rel-7-1: + merge-dev-with-rel-7-2: 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,16 +15,16 @@ jobs: steps: - uses: actions/checkout@v2 with: - ref: rel-7.2 + ref: dev - name: Reset promotion branch run: | - git fetch origin rel-7.1:rel-7.1 - git reset --hard rel-7.1 + git fetch origin rel-7.2:rel-7.2 + git reset --hard rel-7.2 - name: Create Pull Request uses: peter-evans/create-pull-request@v3 with: - branch: auto-merge/rel-7-1/${{github.run_number}} - title: Merge branch rel-7.2 with rel-7.1 - body: This PR generated automatically to merge rel-7.2 with rel-7.1. Please review the changed files before merging to prevent any errors that may occur. + branch: auto-merge/rel-7-2/${{github.run_number}} + title: Merge branch dev with rel-7.2 + body: This PR generated automatically to merge dev with rel-7.2. Please review the changed files before merging to prevent any errors that may occur. reviewers: ${{github.actor}} token: ${{ github.token }} diff --git a/README.md b/README.md index c3c7679aa3..b588e0cba4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![ABP Discord server](https://img.shields.io/discord/951497912645476422?label=Discord)](https://discord.gg/abp) -ABP Framework is a complete **infrastructure** based on the **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**. Check out https://abp.io +ABP Framework is a complete **infrastructure** based on **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**. Check out https://abp.io ## Getting Started @@ -49,7 +49,7 @@ ABP provides a **full stack developer experience**. -ABP offers a complete, **modular** and **layered** software architecture based on **[Domain Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design)** principles and patterns. It also provides the necessary infrastructure and guiding to [implement this architecture](https://docs.abp.io/en/abp/latest/Domain-Driven-Design-Implementation-Guide). +ABP offers a complete, **modular** and **layered** software architecture based on **[Domain Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design)** principles and patterns. It also provides the necessary infrastructure and guidance to [implement this architecture](https://docs.abp.io/en/abp/latest/Domain-Driven-Design-Implementation-Guide). ABP Framework is suitable for **[microservice solutions](https://docs.abp.io/en/abp/latest/Microservice-Architecture)** as well as monolithic applications. diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs index b3ebccd72f..fe24f4d4ec 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs @@ -84,4 +84,4 @@ namespace AbpIoLocalization }); } } -} \ No newline at end of file +} diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/fi.json index a7a52d3811..79dd25aa26 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/fi.json @@ -4,13 +4,14 @@ "Account": "ABP-tili - Kirjaudu ja rekisteröidy | ABP.IO", "Welcome": "Tervetuloa", "UseOneOfTheFollowingLinksToContinue": "Käytä yhtä seuraavista linkeistä jatkaaksesi", - "FrameworkHomePage": "Kehyksen kotisivu", - "FrameworkDocumentation": "Puitteet", + "FrameworkHomePage": "Frameworkin kotisivu", + "FrameworkDocumentation": "Frameworkin dokumentaatio", "OfficialBlog": "Virallinen blogi", "CommercialHomePage": "Kaupallinen kotisivu", "CommercialSupportWebSite": "Kaupallisen tuen verkkosivusto", "CommunityWebSite": "ABP-yhteisön verkkosivusto", "ManageAccount": "Oma tili | ABP.IO", - "ManageYourAccount": "Hallitse tiliäsi" + "ManageYourProfile": "Hallinnoi profiiliasi", + "ReturnToApplication": "Palaa sovellukseen" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json index a773568a31..2bf4bb3837 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json @@ -11,6 +11,7 @@ "CommercialSupportWebSite": "商业版支持网站", "CommunityWebSite": "ABP社区网站", "ManageAccount": "我的帐户 | ABP.IO", - "ManageYourProfile": "管理您的个人资料" + "ManageYourProfile": "管理您的个人资料", + "ReturnToApplication": "返回应用" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json index 6e9253891e..9b95078f66 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "يمكن تحديد تاريخ الشراء فقط عند شراء الحالة!", "Volo.AbpIo.Commercial:030009": "لم يتم العثور على المستخدم!", "Volo.AbpIo.Commercial:030010": "لشراء الترخيص التجريبي ، تحتاج أولاً إلى تنشيط الترخيص التجريبي الخاص بك!", - "Volo.AbpIo.Commercial:030011": "لا يمكنك حذف ترخيص تجريبي عند شرائه!" + "Volo.AbpIo.Commercial:030011": "لا يمكنك حذف ترخيص تجريبي عند شرائه!", + "MoveWaitList": "الانتقال إلى قائمة الانتظار", + "CommunityLinkTitle": "افتح على موقع المجتمع", + "CommunityLink": "رابط المجتمع", + "ReloadFromSource": "إعادة التحميل من المصدر", + "ReloadFromSourceConfirmationMessage": "سيتم تحديث هذه المشاركة من \"{0}\". هل تريد الاستمرار؟" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/cs.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/cs.json index c9b4bacc6d..b594121f0f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/cs.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/cs.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "Datum nákupu lze nastavit pouze ve stavu Zakoupeno!", "Volo.AbpIo.Commercial:030009": "Uživatel nenalezen!", "Volo.AbpIo.Commercial:030010": "Chcete-li zakoupit zkušební licenci, musíte nejprve aktivovat zkušební licenci!", - "Volo.AbpIo.Commercial:030011": "Po zakoupení zkušební licence nelze odstranit!" + "Volo.AbpIo.Commercial:030011": "Po zakoupení zkušební licence nelze odstranit!", + "MoveWaitList": "Přejít na čekací listinu", + "CommunityLinkTitle": "Otevřít na webu komunity", + "CommunityLink": "Odkaz na komunitu", + "ReloadFromSource": "Znovu načíst ze zdroje", + "ReloadFromSourceConfirmationMessage": "Tento příspěvek bude obnoven z „{0}“. Chceš pokračovat?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 0caa284764..9f4fe44349 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -421,7 +421,7 @@ "ContentCacheSlidingExpirationByDay": "Content Cache Sliding Expiration By Day", "MaxDaysForCaching": "Max Days For Caching", "Enabled": "Enabled", - "Menu:NugetPackagesContentCache": "NuGet Packages Content Cache", + "Menu:NugetPackagesContentCache": "NuGet Cache", "NugetPackagesContentCache": "NuGet Content Cache", "SlidingExpritionByDayInfo": "Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. This will not extend the entry lifetime beyond the absolute expiration.", "MaxDaysForCachingInfo": "Gets or sets an absolute expiration time, relative to now.", @@ -452,6 +452,11 @@ "WhoWeAreItem": "Who We Are Item", "FieldIsRequired": "{0} is required.", "FieldIsNotValid": " {0} is not valid.", - "InterestedLicenseType": "Interested License Type" + "InterestedLicenseType": "Interested License Type", + "MoveWaitList": "Move to wait list", + "CommunityLinkTitle": "Open on the community website", + "CommunityLink": "Community Link", + "ReloadFromSource": "Reload From the Source", + "ReloadFromSourceConfirmationMessage": "This post will be refreshed from \"{0}\". Do you want to continue?" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fi.json index 6f43725360..3248ec9863 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fi.json @@ -6,22 +6,22 @@ "Permission:DiscountRequests": "Alennushakemukset", "Permission:DiscountManage": "Hallitse alennuspyyntöjä", "Permission:Disable": "Poista käytöstä", - "Permission:Enable": "ota käyttöön", + "Permission:Enable": "Ota käyttöön", "Permission:EnableSendEmail": "Ota Lähetä sähköposti käyttöön", - "Permission:SendEmail": "Lähettää sähköpostia", + "Permission:SendEmail": "Lähetä sähköpostia", "Permission:NpmPackages": "NPM-paketit", "Permission:NugetPackages": "Nuget-paketit", "Permission:Maintenance": "Huolto", - "Permission:Maintain": "Ylläpitää", + "Permission:Maintain": "Ylläpito", "Permission:ClearCaches": "Tyhjennä välimuistit", "Permission:Modules": "Moduulit", "Permission:Packages": "Paketit", - "Permission:Edit": "Muokata", - "Permission:Delete": "Poistaa", - "Permission:Create": "Luoda", + "Permission:Edit": "Muokkaus", + "Permission:Delete": "Poisto", + "Permission:Create": "Luonti", "Permission:Accounting": "Kirjanpito", - "Permission:Accounting:Quotation": "Tarjous", - "Permission:Accounting:Invoice": "Lasku", + "Permission:Accounting:Quotation": "Tarjoukset", + "Permission:Accounting:Invoice": "Laskutus", "Menu:Organizations": "Organisaatiot", "Menu:Accounting": "Kirjanpito", "Menu:Packages": "Paketit", @@ -52,9 +52,9 @@ "NugetPackageTarget.Web": "Web", "NugetPackageTarget.EntityFrameworkCore": "PoistaAllEntityFramework Core", "NugetPackageTarget.MongoDB": "MongoDB", - "Edit": "Muokata", - "Delete": "Poistaa", - "Refresh": "virkistää", + "Edit": "Muokkaa", + "Delete": "Poista", + "Refresh": "Virkistä", "NpmPackages": "NPM-paketit", "NugetPackages": "Nuget-paketit", "NpmPackageCount": "NPM-pakettimäärä", @@ -87,7 +87,7 @@ "Email": "Sähköposti", "Developers": "Kehittäjät", "AddDeveloper": "Lisää kehittäjä", - "Create": "Luoda", + "Create": "Luo", "UserNotFound": "Käyttäjää ei löydy", "{0}WillBeRemovedFromDevelopers": "{0} Poistetaanko kehittäjiltä, vahvistatko?", "{0}WillBeRemovedFromOwners": "{0} Poistetaanko omistajilta, vahvistatko?", @@ -153,7 +153,7 @@ "DiscountRequests": "Alennuspyyntö", "Copylink": "Kopioi linkki", "Disable": "Poista käytöstä", - "Enable": "ota käyttöön", + "Enable": "Ota käyttöön", "EnableSendEmail": "Ota Lähetä sähköposti käyttöön", "SendEmail": "Lähettää sähköpostia", "SuccessfullyDisabled": "Poistettu onnistuneesti käytöstä", @@ -168,12 +168,12 @@ "TotalQuestionMustBeGreaterWarningMessage": "TotalQuestionCountin on oltava suurempi kuin RemainingQuestionCount!", "QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount ja RemainingQuestionCount on oltava nolla tai suurempi kuin nolla!", "UnlimitedQuestionCount": "Rajoittamaton kysymysten määrä", - "Notes": "Huomautuksia", + "Notes": "Huomautukset", "Menu:Community": "Yhteisö", "Menu:Posts": "Artikkelit", "Wait": "Odota", - "Approve": "Hyväksyä", - "Reject": "Hylätä", + "Approve": "Hyväksy", + "Reject": "Hylkää", "Details": "Yksityiskohdat", "Url": "URL-osoite", "Title": "Otsikko", @@ -184,7 +184,7 @@ "PostHasBeenApproved": "Artikkeli on hyväksytty", "PostHasBeenRejected": "Artikkeli on hylätty", "Permission:Community": "Yhteisö", - "Permission:CommunityPost": "Artikla", + "Permission:CommunityPost": "Artikkeli", "Link": "Linkki", "Enum:ContentSource:0": "Github", "Enum:ContentSource:1": "Ulkoinen", @@ -215,24 +215,27 @@ "Gateway": "Yhdyskäytävä", "State": "Osavaltio", "FailReason": "Epäonnistunut syy", - "ReIndexAllPosts": "Reindex Kaikki viestit", + "ReIndexAllPosts": "Indeksoi uudelleen kaikki viestit", "ReIndexAllPostsConfirmationMessage": "Haluatko varmasti indeksoida kaikki viestit uudelleen?", "SuccessfullyReIndexAllPosts": "Kaikki viestit on indeksoitu uudelleen.", "Permission:FullSearch": "Koko tekstihaku", - "Menu:CliAnalytics": "Cli Analytics", + "Menu:CliAnalytics": "Cli-analytiikka", + "Menu:Reports": "Raportit", "TemplateName": "Mallin nimi", "TemplateVersion": "Malliversio", "DatabaseProvider": "Tietokannan tarjoaja", - "IsTiered": "Onko porrastettu", + "IsTiered": "Onko monikerros", "ProjectName": "Projektin nimi", "Username": "Käyttäjänimi", "Tool": "Työkalu", "Command": "Komento", "UiFramework": "Ui-kehys", "Options": "Vaihtoehdot", - "CliAnalytics": "Cli Analytics", - "Permission:CliAnalyticses": "Cli Analyticses", - "Permission:CliAnalytics": "Cli Analytics", + "CliAnalytics": "Cli-analytiikka", + "Reports": "Raportit", + "Permission:CliAnalyticses": "Cli-analytiikat", + "Permission:CliAnalytics": "Cli-analytiikka", + "Permission:Reports": "Raportit", "Search": "Hae", "ClearFilter": "Tyhjennä suodatin", "LicensePrivateKey": "Lisenssin yksityinen avain", @@ -316,14 +319,12 @@ "TrialLicenseStatusFilter": "Tila", "TrialLicenseStartDateFilter": "Aloituspäivämäärä", "TrialLicenseEndDateFilter": "Päättymispäivä", - "FirsName": "Etunimi", + "FirstName": "Etunimi", "LastName": "Sukunimi", "StartDate": "Aloituspäivämäärä", "EndDate": "Päättymispäivä", "PurchasedDate": "Ostopäivämäärä", "OrganizationDetail": "Organisaation tiedot", - "SendActivationMail": "Lähetä aktivointiviesti", - "ActivationMailSentSuccessfully": "Aktivointiviesti lähetetty onnistuneesti!", "TrialLicenseStatus": "Kokeilulisenssin tila", "TrialLicenseDetail": "Kokeilulisenssin tiedot", "AcceptsMarketingCommunications": "Markkinointiviestintä", @@ -337,17 +338,125 @@ "Expired": "Vanhentunut", "TrialLicenseDeletionWarningMessage": "Haluatko varmasti poistaa koekäyttöluvan? Kokeilulisenssi, organisaatio, tukitilit poistetaan!", "LicenseCategoryFilter": "Lisenssiluokka", - "Volo.AbpIo.Commercial:030000": "Olet jo käyttänyt kokeilujaksosi.", - "Volo.AbpIo.Commercial:030001": "Tämä organisaation nimi on jo olemassa.", - "Volo.AbpIo.Commercial:030002": "Kun kokeilukäyttöoikeus on aktivoitu, sitä ei voi asettaa pyydettyksi!", - "Volo.AbpIo.Commercial:030003": "Sellaista statusta ei ole!", - "Volo.AbpIo.Commercial:030004": "Tilaa ei voitu muuttaa odottamattoman virheen vuoksi!", - "Volo.AbpIo.Commercial:030005": "Alkamis- ja lopetuspäivämäärät voidaan päivittää, kun koekäyttölisenssi on -aktivoitu-tilassa!", - "Volo.AbpIo.Commercial:030006": "Päättymispäivän on aina oltava aloituspäivää suurempi!", - "Volo.AbpIo.Commercial:030007": "Tämä kokeiluversio on jo aktivoitu kerran!", - "Volo.AbpIo.Commercial:030008": "Ostopäivä voidaan asettaa vain, kun tila on Ostettu!", - "Volo.AbpIo.Commercial:030009": "Käyttäjää ei löydy!", - "Volo.AbpIo.Commercial:030010": "Kokeilulisenssin ostamiseksi sinun on ensin aktivoitava kokeilulisenssi!", - "Volo.AbpIo.Commercial:030011": "Kokeilulisenssiä ei voi poistaa, kun se on ostettu!" + "Permission:SendWelcomeEmail": "Lähetä tervetulosähköposti", + "SendWelcomeEmail": "Lähetä tervetulosähköposti", + "SendWelcomeEmailWarningMessage": "Haluatko varmasti lähettää tervetuloviestin organisaation jäsenille?", + "SendWelcomeEmailSuccessMessage": "Tervetulosähköposti lähetetty onnistuneesti!", + "Activate": "Aktivoi", + "ActivateTrialLicenseWarningMessage": " Kun aktivoit kokeilulisenssin, käyttäjälle lähetetään tervetulosähköposti. Haluatko aktivoida sen?", + "ActivateTrialLicenseSuccessMessage": "Aktivointi onnistui ja tervetulosähköposti lähetetty organisaation jäsenille.", + "PaymentRequestId": "Maksupyynnön tunnus", + "AdditionalDeveloperCount": "Lisäkehittäjien määrä", + "LicensePrice": "Lisenssin hinta", + "PurchaseDate": "Ostopäivä", + "IsAbpBookDownloaded": "Mastering ABP Book ladattu?", + "IsMasteringAbpBookDownloadEnabled": "ABP-kirjan lataus käytössä", + "Permission:Accounting:CustomPaymentLinkGenerator": "Mukautettu maksulinkki", + "CustomPaymentLink": "Mukautettu maksulinkki", + "Menu:CustomPaymentLink": "Mukautettu maksulinkki", + "Amount": "Määrä", + "GenerateCustomPaymentLink": "Luo mukautettu maksulinkki", + "GeneratedPaymentLink": "Luotu maksulinkki", + "CopyText": "Kopioi teksti", + "Permission:CommunityEvents": "Tapahtumat", + "Menu:Events": "Tapahtumat", + "Events": "Tapahtumat", + "EventType": "Tapahtumatyyppi", + "Number": "Määrä", + "RegistrationURL": "Rekisteröinnin URL-osoite", + "URL": "URL-osoite", + "EventDeletionConfirmationMessage": "Haluatko varmasti poistaa tämän tapahtuman?", + "Enum:EventType:0": "Yhteisön keskustelut", + "CreateAnEvent": "Luo tapahtuma", + "Permission:CommunitySpeakers": "Esiintyjät", + "CreateASpeaker": "Luo esiintyjä", + "Speakers": "Esiintyjät", + "Image": "Kuva", + "GithubURL": "Githubin URL-osoite", + "SpeakerDeletionConfirmationMessage": "Haluatko varmasti poistaa tämän esiintyjän?", + "Menu:Speakers": "Esiintyjät", + "ChooseSpeakerImage": "Valitse esiintyjän kuva...", + "SpeakerImage": "Esiintyjän kuva", + "AddSpeaker": "Lisää esiintyjä", + "ShowPurchaseItemsOfOrganizations": "Osta kohteita", + "Enum:OrganizationPurchaseState:0": "Ei toimitettu", + "Enum:OrganizationPurchaseState:1": "Toimitettu", + "PurchaseItems": "Osta kohteita", + "SuccessfullyUpdated": "Päivitetty onnistuneesti", + "SuccessfullyAdded": "Lisätty onnistuneesti", + "PurchaseState": "Ostoksen tila", + "ShowBetweenDayCount": "Näytä päivien välissä", + "PurchaseOrder": "Ostotilaus", + "ShowCreateInvoiceOfOrganization": "Luo lasku", + "ShowCreateQuotationOfOrganization": "Luo tarjous", + "BookDiscounts": "Kirja-alennukset", + "Permission:BookDiscount": "Varaa alennus", + "Menu:BookDiscounts": "Kirja-alennukset", + "BookType": "Kirjan tyyppi", + "PurchasePlatform": "Ostoalusta", + "StartTime": "Aloitusaika", + "EndTime": "Loppu aika", + "CreateABookDiscount": "Luo kirja-alennus", + "BookDiscountDeletionConfirmationMessage": "Haluatko varmasti poistaa tämän kirja-alennuksen?", + "CustomPaymentFlexSwitchDescription": "Lisenssillä", + "AllowFeatureUpgradeOnLicenseExpire": "Salli ominaisuuden päivitys lisenssin vanhentuessa", + "Deleted{0}": "[poistettu {0}]", + "Tags": "Tunnisteet", + "SetTagsInfo": "Tunnisteet on erotettava pilkuilla. Esim: CSharp, Entity Framework", + "RejectTrialLicenseWarningMessage": "Haluatko varmasti hylätä tämän kokeilulupapyynnön?", + "ExportToExcel": "Vie Exceliin", + "OverallTotalPrice": "Kokonaishinta", + "OverallDiscountPrice": "Kokonaisalennushinta", + "OverallDiscountText": "Kokonaisalennusteksti", + "SelectReport": "- Valitse Raportti -", + "NoDataAvailable": "Tietoja ei ole saatavilla", + "StatisticsOfCachedContents": "Nuget.abp.io:n välimuistissa olevan NuGet-paketin sisällön tilastot", + "Compact": "Kompakti", + "EditSettings": "Muokkaa asetuksia", + "CurrentEstimatedSize": "Nykyinen arvioitu koko", + "CurrentEntryCount": "Nykyinen kohteiden määrä", + "TotalHits": "Yhteensä osumia", + "TotalMisses": "Yhteensä huteja", + "NoResponseFrom": "Ei vastausta käyttäjältä", + "ContentCacheSlidingExpirationByDay": "Sisällön välimuistin liukuva vanheneminen päivältä", + "MaxDaysForCaching": "Enimmäispäiviä välimuistiin", + "Enabled": "Käytössä", + "Menu:NugetPackagesContentCache": "NuGet-välimuisti", + "NugetPackagesContentCache": "NuGet-sisältövälimuisti", + "SlidingExpritionByDayInfo": "Hakee tai määrittää, kuinka kauan välimuistimerkintä voi olla passiivinen (esim. sitä ei käytetä), ennen kuin se poistetaan. Tämä ei pidennä merkinnän käyttöikää absoluuttisen vanhenemisen jälkeen.", + "MaxDaysForCachingInfo": "Hakee tai asettaa absoluuttisen vanhenemisajan suhteessa nykyhetkeen.", + "CurrentEstimatedSizeInfo": "Ilmaisee arvioidun summan kaikkien NuGet-pakettien tämänhetkisen sisältökoon välimuistissa", + "CurrentEntryCountInfo": "Ilmaisee välimuistissa tällä hetkellä olevien esiintymien määrän.", + "TotalHitsInfo": "Ilmaisee välimuistin hutien kokonaismäärän. Välimuistiosuma tapahtuu, kun välimuistista pyydetään tiedostoa ja välimuisti pystyy täyttämään pyynnön.", + "TotalMissesInfo": "Ilmaisee välimuistin osumien kokonaismäärän. Välimuisti puuttuu, kun välimuisti ei sisällä pyydettyä sisältöä.", + "Permission:VersionHistory": "Versiohistoria", + "Caches": "Välimuistit", + "VersionHistories": "Versiohistoria", + "Version": "Versio", + "PublishDate": "Julkaisupäivämäärä", + "IsStableVersion": "Vakaa versio", + "IsActive": "Aktiivinen", + "NewVersion": "Uusi versio", + "VersionHistoryDeletionConfirmationMessage": "Haluatko varmasti poistaa tämän version?", + "CreateAbpConsultantLogoInfo": "Tiedoston enimmäiskoko: 1Mt
Tuetut tiedostotyypit: jpg, jpeg, png, SVG, WebP", + "UrlCode": "URL-koodi", + "Clear": "Tyhjennä", + "Permission:AbpConsultant": "ABP-konsultti", + "Menu:AbpConsultants": "ABP konsultit", + "CreateAbpConsultant": "Luo ABP-konsultti", + "UrlCodeIsNotAvailable": "Toinen ABP-konsultti käyttää URL-koodia.", + "AbpConsultants": "ABP konsultit", + "AbpConsultant": "ABP-konsultti", + "AbpConsultantEdit": "Muokkaa ABP-konsulttia", + "AbpConsultantCreate": "Luo ABP-konsultti", + "WhoWeAreItem": "Keitä me olemme -tuote", + "FieldIsRequired": "{0} vaaditaan.", + "FieldIsNotValid": " {0} ei kelpaa.", + "InterestedLicenseType": "Kiinnostunut lisenssityyppi", + "MoveWaitList": "Siirrä jonotuslistalle", + "CommunityLinkTitle": "Avaa yhteisön verkkosivuilla", + "CommunityLink": "Yhteisön linkki", + "ReloadFromSource": "Lataa uudelleen lähteestä", + "ReloadFromSourceConfirmationMessage": "Tämä viesti päivitetään kohteesta \"{0}\". Haluatko jatkaa?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fr.json index 8ac2e0e770..075992d7c7 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/fr.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "La date d'achat ne peut être définie que lorsque le statut est Acheté !", "Volo.AbpIo.Commercial:030009": "Utilisateur non trouvé!", "Volo.AbpIo.Commercial:030010": "Pour acheter la licence d'essai, vous devez d'abord activer votre licence d'essai !", - "Volo.AbpIo.Commercial:030011": "Vous ne pouvez pas supprimer une licence d'essai lorsqu'elle est achetée !" + "Volo.AbpIo.Commercial:030011": "Vous ne pouvez pas supprimer une licence d'essai lorsqu'elle est achetée !", + "MoveWaitList": "Passer à la liste d'attente", + "CommunityLinkTitle": "Ouvert sur le site communautaire", + "CommunityLink": "Lien communautaire", + "ReloadFromSource": "Recharger à partir de la source", + "ReloadFromSourceConfirmationMessage": "Ce message sera actualisé à partir de \"{0}\". Voulez-vous continuer?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/hi.json index bbe2980c7b..01d9a571e1 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/hi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/hi.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "खरीद की तारीख तभी निर्धारित की जा सकती है जब स्थिति खरीदी गई हो!", "Volo.AbpIo.Commercial:030009": "उपयोगकर्ता नहीं मिला!", "Volo.AbpIo.Commercial:030010": "परीक्षण लाइसेंस खरीदने के लिए, पहले आपको अपना परीक्षण लाइसेंस सक्रिय करना होगा!", - "Volo.AbpIo.Commercial:030011": "जब आप एक परीक्षण लाइसेंस खरीदा जाता है तो आप उसे हटा नहीं सकते हैं!" + "Volo.AbpIo.Commercial:030011": "जब आप एक परीक्षण लाइसेंस खरीदा जाता है तो आप उसे हटा नहीं सकते हैं!", + "MoveWaitList": "प्रतीक्षा सूची में ले जाएँ\n", + "CommunityLinkTitle": "सामुदायिक वेबसाइट पर खोलें", + "CommunityLink": "सामुदायिक लिंक", + "ReloadFromSource": "स्रोत से पुनः लोड करें", + "ReloadFromSourceConfirmationMessage": "यह पोस्ट \"{0}\" से ताज़ा की जाएगी। क्या आप जारी रखना चाहते हैं?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/it.json index eb6b0e7779..f4e51f77c0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/it.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/it.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "La data di acquisto può essere impostata solo quando lo stato è Acquistato!", "Volo.AbpIo.Commercial:030009": "Utente non trovato!", "Volo.AbpIo.Commercial:030010": "Per acquistare la licenza di prova, devi prima attivare la tua licenza di prova!", - "Volo.AbpIo.Commercial:030011": "Non è possibile eliminare una licenza di prova al momento dell'acquisto!" + "Volo.AbpIo.Commercial:030011": "Non è possibile eliminare una licenza di prova al momento dell'acquisto!", + "MoveWaitList": "Passa alla lista d'attesa", + "CommunityLinkTitle": "Apri sul sito web della comunità", + "CommunityLink": "Collegamento comunitario", + "ReloadFromSource": "Ricarica dalla sorgente", + "ReloadFromSourceConfirmationMessage": "Questo post verrà aggiornato da \"{0}\". Volete continuare?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/sl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/sl.json index 421ed3f0d4..968c8fa8c0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/sl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/sl.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "Datum nakupa je mogoče nastaviti samo, če je status Kupljeno!", "Volo.AbpIo.Commercial:030009": "Uporabnik ni najden!", "Volo.AbpIo.Commercial:030010": "Za nakup preizkusne licence morate najprej aktivirati preizkusno licenco!", - "Volo.AbpIo.Commercial:030011": "Preskusne licence ne morete izbrisati, ko je kupljena!" + "Volo.AbpIo.Commercial:030011": "Preskusne licence ne morete izbrisati, ko je kupljena!", + "MoveWaitList": "Presuňte sa na zoznam čakateľov", + "CommunityLinkTitle": "Otvorte na webovej stránke komunity", + "CommunityLink": "Odkaz na komunitu", + "ReloadFromSource": "Znovu načítať zo zdroja", + "ReloadFromSourceConfirmationMessage": "Tento príspevok bude obnovený z „{0}“. Chceš pokračovať?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json index 8fb4eeb4e1..4559503a6d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json @@ -412,6 +412,11 @@ "CustomPaymentFlexSwitchDescription": "Lisanslı", "AllowFeatureUpgradeOnLicenseExpire": "Lisans süresi dolunca özellik yükseltmesine izin ver", "Deleted{0}": "[{0} silindi]", - "Permission:BookDiscount": "Kitap indirimleri" + "Permission:BookDiscount": "Kitap indirimleri", + "MoveWaitList": "Bekleme listesine geç", + "CommunityLinkTitle": "Topluluk web sitesinde açın", + "CommunityLink": "Topluluk Bağlantısı", + "ReloadFromSource": "Kaynaktan Yeniden Yükle", + "ReloadFromSourceConfirmationMessage": "Bu gönderi \"{0}\" adresinden yenilenecek. Devam etmek istiyor musun?" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json index b363aa0c64..0ed00a2c75 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json @@ -220,6 +220,7 @@ "SuccessfullyReIndexAllPosts": "成功索引所有的帖子", "Permission:FullSearch": "全文检索", "Menu:CliAnalytics": "客户端分析", + "Menu:Reports": "报表", "TemplateName": "模板名称", "TemplateVersion": "模板版本", "DatabaseProvider": "数据库提供者", @@ -231,8 +232,10 @@ "UiFramework": "界面框架", "Options": "选项", "CliAnalytics": "客户端分析", + "Reports": "报表", "Permission:CliAnalyticses": "客户端分析", "Permission:CliAnalytics": "客户端分析", + "Permission:Reports": "报表", "Search": "搜索", "ClearFilter": "清除过滤", "LicensePrivateKey": "许可私有密钥", @@ -397,6 +400,63 @@ "BookDiscountDeletionConfirmationMessage": "你确定要删除这个书籍折扣吗?", "CustomPaymentFlexSwitchDescription": "授权", "AllowFeatureUpgradeOnLicenseExpire": "允许在授权过期时进行功能升级", - "Deleted{0}": "[已删除 {0}]" + "Deleted{0}": "[已删除 {0}]", + "Tags": "标签", + "SetTagsInfo": "标签使用逗号分隔,例如:CSharp, Entity Framework", + "RejectTrialLicenseWarningMessage": "您确定要拒绝这个试用许可证申请吗?", + "ExportToExcel": "导出Excel", + "OverallTotalPrice": "总价", + "OverallDiscountPrice": "折扣价", + "OverallDiscountText": "折扣内容", + "SelectReport": "- 选择报表 -", + "NoDataAvailable": "无数据", + "StatisticsOfCachedContents": "nuget.abp.io缓存的NuGet包内容统计", + "Compact": "紧凑型", + "EditSettings": "编辑设置", + "CurrentEstimatedSize": "当前预计规模", + "CurrentEntryCount": "当前数量", + "TotalHits": "点击量", + "TotalMisses": "未命中总数", + "NoResponseFrom": "没有收到任何答复", + "ContentCacheSlidingExpirationByDay": "内容缓存按天滑动过期", + "MaxDaysForCaching": "缓存的最大天数", + "Enabled": "启用", + "Menu:NugetPackagesContentCache": "NuGet包缓存", + "NugetPackagesContentCache": "NuGet内容缓存", + "SlidingExpritionByDayInfo": "获取或设置一个缓存在多长时间内不活动(例如,不被访问)才会被删除。这不会使期超过绝对到期时间。", + "MaxDaysForCachingInfo": "获取或设置相对于当前时间的绝对过期时间。", + "CurrentEstimatedSizeInfo": "当前在内存缓存中的所有NuGet包的内容大小的估计总和", + "CurrentEntryCountInfo": "当前在内存缓存中的实例数量。", + "TotalHitsInfo": "缓存未命中总数,当从缓存请求文件并且缓存能够满足该请求时,就会发生缓存命中。。", + "TotalMissesInfo": "缓存命中的总数,缓存未命中是指缓存中不包含请求的内容。", + "Permission:VersionHistory": "版本历史", + "Caches": "缓存", + "VersionHistories": "版本历史", + "Version": "版本", + "PublishDate": "发布日期", + "IsStableVersion": "稳定版", + "IsActive": "激活", + "NewVersion": "新版本", + "VersionHistoryDeletionConfirmationMessage": "您确定要删除此版本吗?", + "CreateAbpConsultantLogoInfo": "最大文件大小:1MB
支持的文件类型:jpg, jpeg, png, SVG, WebP", + "UrlCode": "许可证代码", + "Clear": "清除", + "Permission:AbpConsultant": "ABP顾问", + "Menu:AbpConsultants": "ABP顾问", + "CreateAbpConsultant": "创建ABP顾问", + "UrlCodeIsNotAvailable": "Url代码已被其他ABP顾问使用。", + "AbpConsultants": "ABP顾问", + "AbpConsultant": "ABP顾问", + "AbpConsultantEdit": "编辑ABP顾问", + "AbpConsultantCreate": "创建ABP顾问", + "WhoWeAreItem": "关于我们", + "FieldIsRequired": "{0}是必须的。", + "FieldIsNotValid": "{0}是无效的。", + "InterestedLicenseType": "感兴趣的许可证类型", + "MoveWaitList": "移至候补名单", + "CommunityLinkTitle": "在社区网站上打开", + "CommunityLink": "在社区网站上打开", + "ReloadFromSource": "从源重新加载", + "ReloadFromSourceConfirmationMessage": "此帖子将从“{0}”刷新。 你想继续吗?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json index 209e667c83..b5ec2f3816 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json @@ -348,6 +348,11 @@ "Volo.AbpIo.Commercial:030008": "購買日期只能在狀態為已購買時設置!", "Volo.AbpIo.Commercial:030009": "未找到用戶!", "Volo.AbpIo.Commercial:030010": "要購買試用許可證,首先您需要激活您的試用許可證!", - "Volo.AbpIo.Commercial:030011": "購買試用許可證後,您無法刪除它!" + "Volo.AbpIo.Commercial:030011": "購買試用許可證後,您無法刪除它!", + "MoveWaitList": "移至候补名单", + "CommunityLinkTitle": "在社区网站上打开", + "CommunityLink": "社区链接", + "ReloadFromSource": "從源重新加載", + "ReloadFromSourceConfirmationMessage": "此帖子將從“{0}”刷新。 你想繼續嗎?" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json index 89f7648368..783582d7be 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -27,6 +27,8 @@ "Volo.AbpIo.Domain:030010": "To purchase the trial license, you first need to activate your trial license!", "Volo.AbpIo.Domain:030011": "You cannot delete a trial license when it is purchased!", "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: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?", @@ -177,6 +179,7 @@ "BuyNewLicenseBetweenDatesToGetBenefit": "Buy a new license between {0} and {1} to get benefit for extra 2 months!", "CheckAllCommunityTalks": "Check All Community Posts", "ReadMore": "Read More", + "ContinueReading": "Continue Reading", "Post": "Post", "ExploreTheContentsCreatedByTheCoreABPTeamAndTheABPCommunity": "Explore the contents created by the core ABP team and the ABP community.", "WelcomeFallCampaign": "Welcome Fall Campaign!", @@ -205,6 +208,8 @@ "Icons": "Icons", "Url": "Url", "Icon": "Icon", - "RecentActivities": "Recent Activities" + "RecentActivities": "Recent Activities", + "SpringCampaign": "Welcome
Spring Sale!", + "SpringCampaign2": "Limited
Time Offer!
" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json index 441efbc761..cd2802fef4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/fi.json @@ -14,13 +14,29 @@ "Volo.AbpIo.Domain:020002": "Tätä NPM-pakettia ei voitu poistaa, koska moduulit \"{Modules}\" käyttävät tätä pakettia.", "Volo.AbpIo.Domain:020003": "Tätä NPM-pakettia ei voitu poistaa, koska moduulit \"{Modules}\" käyttävät tätä pakettia ja \"{NugetPackages}\" -nugettipaketit ovat riippuvaisia tästä paketista.", "Volo.AbpIo.Domain:020004": "Tätä Nuget-pakettia ei voitu poistaa, koska moduulit \"{Modules}\" käyttävät tätä pakettia.", + "Volo.AbpIo.Domain:030000": "Olet jo suorittanut kokeilujaksosi.", + "Volo.AbpIo.Domain:030001": "Tämä organisaation nimi on jo olemassa.", + "Volo.AbpIo.Domain:030002": "Kun kokeilukäyttöoikeus on aktivoitu, et voi vaihtaa -pyynnön tilaan!", + "Volo.AbpIo.Domain:030003": "Sellaista statusta ei ole!", + "Volo.AbpIo.Domain:030004": "Tilaa ei voitu muuttaa odottamattoman virheen vuoksi!", + "Volo.AbpIo.Domain:030005": "Alkamis- ja päättymispäivä voidaan päivittää, kun koekäyttöoikeus on -aktivoitu-tilassa!", + "Volo.AbpIo.Domain:030006": "Päättymispäivän on oltava aloituspäivää suurempi!", + "Volo.AbpIo.Domain:030007": "Tämä kokeilukäyttöoikeus on jo aktivoitu!", + "Volo.AbpIo.Domain:030008": "Ostopäivä voidaan asettaa vain, kun tila on -ostettu-!", + "Volo.AbpIo.Domain:030009": "Käyttäjää ei löydy!", + "Volo.AbpIo.Domain:030010": "Kokeilulisenssin ostamiseksi sinun on ensin aktivoitava kokeilulisenssi!", + "Volo.AbpIo.Domain:030011": "Kokeilulisenssiä ei voi poistaa, kun se on ostettu!", + "Volo.AbpIo.Domain:030012": "Käyttäjällä on oikeus saada vain yksi ilmainen kokeilujakso. Olet jo käyttänyt kokeilukäyttölupaasi.", + "Volo.AbpIo.Domain:030013": "Käyttäjä, jolla on aktiivinen käyttöoikeus, ei voi aloittaa kokeilukäyttöoikeutta.", + "Volo.AbpIo.Domain:070000": "Organisaation nimi saa sisältää vain latinalaisia kirjaimia, numeroita, pisteitä ja yhdysmerkkejä!", + "Volo.AbpIo.Domain:070001": "Yrityksen nimi saa sisältää vain latinalaisia kirjaimia, numeroita, pisteitä, välilyöntejä ja yhdysmerkkejä!", "WantToLearn?": "Haluan oppia?", "ReadyToGetStarted?": "Oletko valmis aloittamaan?", "JoinOurCommunity": "Liity yhteisöömme", - "GetStartedUpper": "ALOITTAA", + "GetStartedUpper": "ALOITA", "ForkMeOnGitHub": "Haaraa minut GitHubiin", "Features": "ominaisuudet", - "GetStarted": "Aloittaa", + "GetStarted": "Aloita", "Documents": "Asiakirjat", "Community": "Yhteisö", "ContributionGuide": "Contribution Guide", @@ -39,6 +55,159 @@ "TrialLicensePeriodHasExpired": "Kokeilulisenssijaksosi päättyi {0} päivää sitten.", "TrialLicensePeriodWillExpire": "Kokeilulisenssijaksosi vanhenee {0} päivän kuluttua.", "TrialLicensePeriodExpireToday": "Kokeilulisenssijaksosi päättyy tänään.", - "PurchaseNow": "Osta nyt!" + "PurchaseNow": "Osta nyt!", + "LatestReleaseLogs": "Uusimmat julkaisulokit", + "RoadMap": "Tiekartta", + "FAQ": "FAQ", + "SourceCode": "Lähdekoodi", + "SeeAllPosts": "Katso kaikki viestit", + "Contribute": "Osallistu", + "LiveDemo": "Live-demo", + "GetLicense": "Hanki lisenssi", + "OpenSource": "Avoin lähdekoodi", + "WebApplication": "Verkkosovellus", + "MeetTheABP": "Tapaa ABP", + "CompleteWebDevelopment": "Täydellinen verkkokehitys", + "Platform": "Alusta", + "ABPDescription": "ABP Framework on täydellinen infrastruktuuri nykyaikaisten verkkosovellusten luomiseen noudattamalla ohjelmistokehityksen parhaita käytäntöjä.", + "StrongInfrastructure": "Vahva infrastruktuuri", + "CompleteArchitecture": "Täydellinen arkkitehtuuri", + "DeveloperFocused": "Kehittäjä-fokusoitunut", + "ShareYourExperiences": "Jaa kokemuksesi ABP Frameworkista", + "LatestPosts": "Uusimmat viestit", + "LatestVideos": "Uusimmat videot", + "Views": "Näkymät", + "LearnLatestNewsAboutABPFramework": "Hanki tietoa ABP:n tapahtumista, kuten uusista julkaisuista, ilmaisista lähteistä, julkaisuista ja paljon muuta.", + "DeveloperTools": "Kehittäjän työkalut", + "StartupTemplates": "Käynnistysmallit", + "ApplicationModules": "Sovellusmoduulit", + "UI": "UI", + "Themes": "Teemat", + "Premium": "Premium", + "PrivacyPolicy": "Tietosuojakäytäntö", + "TermsAndConditions": "Käyttöehdot", + "WouldLikeToReceiveMarketingMaterials": "Haluan saada markkinointimateriaaleja, kuten tuotetarjouksia ja erikoistarjouksia.", + "JoinOurMarketingNewsletter": "Liity markkinointiuutiskirjeeseemme", + "CommunityPrivacyPolicyConfirmation": "Hyväksyn käyttöehdot ja tietosuojakäytännön .", + "WouldLikeToReceiveNotification": "Haluan saada viimeisimmät uutiset abp.io-sivustoilta.", + "CommercialNewsletterConfirmationMessage": "Hyväksyn käyttöehdot ja tietosuojakäytännön.", + "FreeDDDEBook": "Ilmainen DDD e-kirja", + "AdditionalServices": "Lisäpalvelut", + "Learn": "Opi", + "AccountOverview": "Tilin yleiskatsaus", + "MyOrganizations": "Omat organisaatiot", + "MySupportQuestions": "Tukikysymykseni", + "MyProfile": "Profiilini", + "Logout": "Kirjaudu ulos", + "Home": "Koti", + "Posts": "Viestit", + "Videos": "Videot", + "JoinTheABPCommunity": "Liity ABP-yhteisöön", + "SubmitYourPost": "Lähetä viestisi", + "Modules": "Moduulit", + "Tools": "Työkalut", + "Pricing": "Hinnoittelu", + "ChangeLogs": "Muutoslokit", + "SubscribeToNewsletter": "Tilaa uutiskirje", + "SubscribeToNewsletterDescription": "Hanki tietoa ABP:n tapahtumista, kuten uusista julkaisuista, ilmaisista lähteistä, julkaisuista ja muusta.", + "EmailAddress": "Sähköpostiosoite", + "Subscribe": "Tilaa", + "WelcomeToABP": "Tervetuloa ABP:hen", + "EULA": "EULA", + "ABPCommercialIntroductionMessage": "Valmiiksi rakennetut sovellusmoduulit, edistyneet käynnistysmallit, nopeat sovelluskehitystyökalut, ammattikäyttöliittymäteemat ja ensiluokkainen tuki.", + "MasteringAbpFrameworkEBook": "ABP-kehyksen hallitseminen", + "MasteringTheABPFrameworkExplanation": "Tämä ABP Frameworkin luojan kirjoittama kirja auttaa sinua saamaan täydellisen käsityksen viitekehyksestä ja nykyaikaisista verkkosovelluskehitystekniikoista.", + "Speakers": "Esiintyjät", + "PreviousEvents": "Aiemmat tapahtumat", + "WatchTheEvent": "Katso Tapahtuma", + "RegisterNow": "Rekisteröidy nyt", + "ThereIsNoEvent": "Tapahtumaa ei ole.", + "Events": "Tapahtumat", + "Volo.AbpIo.Domain:080000": "Ostokohde nimeltä \"{Name}\" on jo olemassa", + "MasteringAbpFrameworkBook": "Kirja: Mastering ABP Framework", + "ABPIO-CommonPreferenceDefinition": "Hanki viimeisimmät uutiset ABP Platformista, kuten uudet viestit, tapahtumat ja paljon muuta.", + "BuiltOn": "Rakennettu", + "AbpFramework": "ABP-kehys", + "Volo.AbpIo.Domain:080001": "Aloitusaika ei voi olla suurempi kuin lopetusaika", + "Enum:BookType:0": "Mastering ABP Framework", + "Enum:PurchasePlatform:0": "Amazon", + "Enum:PurchasePlatform:1": "Packt", + "Copied": "Kopioitu!", + "CouldNotCopy": "Ei voitu kopioida!", + "CopyNotSupportByYourBrowser": "Tämä ominaisuus ei toimi käyttämässäsi selaimessa.", + "City": "Kaupunki", + "ZipCode": "Postinumero", + "Address": "Osoite", + "Homepage": "Kotisivu", + "Year": "vuosi", + "Copyright": "Tekijänoikeus © {1}", + "DomainDrivenDesign": "Domain Driven Design", + "CrossCuttingConcerns": "Cross Cutting Concerns", + "AbpCommunity": "ABP-yhteisö", + "Footer_GithubStarCount": "{0} tähteä GitHubissa", + "Footer_NugetDownloadCount": "{0} Lataukset NuGetissä", + "AbpDescription": "ABP on avoimen lähdekoodin sovelluskehys, joka keskittyy AspNet Core -pohjaiseen verkkosovelluskehitykseen. Älä toista itseäsi, vaan keskity omaan yrityskoodiisi.", + "Layout_AbpFramework_MetaTitle": "ABP Framework - avoimen lähdekoodin verkkosovelluskehys", + "CommunityTalks_CountdownDays": "Pv", + "CommunityTalks_CountdownHours": "T", + "CommunityTalks_CountdownMinutes": "Min", + "CommunityTalks_CountdownSeconds": "Sek", + "SeePreviousEvents": "Katso aiemmat tapahtumat", + "CookieConsent_Accept": "Hyväksy", + "CookieConsent_Explanation_1": "Käytämme evästeitä tarjotaksemme sinulle parhaan kokemuksen verkkosivustollamme.", + "CookieConsent_Explanation_2": "Jos jatkat selaamista, hyväksyt tietosuojakäytäntömme ja evästekäytäntömme.", + "Error_Page_400_Title": "Pyydetyn sivun näyttämisessä oli ongelma.", + "Error_Page_400_Description_1": "Yleensä tämä tarkoittaa, että pyyntöäsi käsiteltäessä tapahtui odottamaton virhe.", + "Error_Page_400_Description_2": "Jos ongelma jatkuu, ota meihin yhteyttä osoitteeseen info@abp.io, niin autamme sinua pääsemään eteenpäin.", + "GoToHomepage": "Mene kotisivulle", + "Error_Page_404_Title": "Sivua ei löytynyt!", + "Error_Page_404_Description_1": "Tämä ei ole etsimäsi verkkosivu.", + "Error_Page_500_Title": "Näyttää siltä, että jotain meni pieleen!", + "Error_Page_500_Description_1": "Seuraamme näitä virheitä automaattisesti, mutta jos ongelma jatkuu,
ota meihin yhteyttä. Kokeile sillä välin sivun päivittämistä.", + "Error_Page_500_Description_2": "Ota meihin yhteyttä osoitteessa info@abp.io.", + "Books": "Kirjat", + "ABPDiscordServer": "ABP Discord-palvelin", + "ABPCommunityTalks": "ABP Community Talks", + "ABPCommunityPosts": "ABP-yhteisön viestit", + "BuyAndGetMonths": "OSTA 12 KUUKAUTA, SAAT 14 KUUKAUTA!", + "GetYourDeal": "Hanki tarjouksesi", + "BuyOrRenewLicense": "Osta tai uusi lisenssi nyt ja saat 2 lisäkuukautta!", + "BuyOrRenewLicenseToGetExtra2Months": "Osta tai uusi lisenssi nyt ja saat 2 lisäkuukautta! KIIREHDI! ⏰ Viimeinen päivä: {0}", + "HurryUp": "KIIREHDI!", + "LastDay": "Viimeinen päivä: {0}", + "BuyNewLicenseBetweenDatesToGetBenefit": "Osta uusi lisenssi välillä {0} - {1}, niin saat 2 lisäkuukautta!", + "CheckAllCommunityTalks": "Tarkista kaikki yhteisön viestit", + "ReadMore": "Lue lisää", + "Post": "Viesti", + "ExploreTheContentsCreatedByTheCoreABPTeamAndTheABPCommunity": "Tutustu ABP-ydintiimin ja ABP-yhteisön luomaan sisältöön.", + "WelcomeFallCampaign": "Tervetuloa syksyn kampanjaan!", + "GiveAwayForNewPurchases": "Sovelluskehityksen luokkahuonekoulutus jaetaan uusien ostosten yhteydessä!", + "BlackFriday": "MUSTA PERJANTAI", + "ValidForExistingCustomers": "Voimassa myös
olemassa oleville asiakkaille!", + "CampaignBetweenDates": "{0}
- {1}", + "SaveUpTo": "SÄÄSTÄ JOPA${0}K", + "ImplementingDDD": "Implementing Domain Driven Design", + "ExploreTheEBook": "Tutustu e-kirjaan", + "ExploreTheBook": "Tutustu Kirjaan", + "ConsultantType": "Konsultointityyppi", + "Expert": "ABP-asiantuntija", + "Partner": "ABP kumppani", + "Industry": "Ala", + "Location": "Sijainti", + "Contact": "Ottaa yhteyttä", + "Partner_Year": "Kumppanuuden vuosi", + "Info": "Tiedot", + "SpokenLanguages": "Puhutut kielet", + "SocialMedia": "Sosiaalinen media", + "Activity": "Toiminta", + "Type": "Tyyppi", + "Contribution": "Osallistuminen", + "WhoWeAre": "Keitä olemme", + "Icons": "Kuvakkeet", + "Url": "URL-osoite", + "Icon": "Kuvake", + "RecentActivities": "Viimeaikaiset toimet", + "SpringCampaign": "Tervetuloa kevätaleen!", + "SpringCampaign2": "Rajoitetun
ajan tarjous!
" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json index dee01c8589..4275bb3771 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json @@ -22,17 +22,13 @@ "Features": "Özellikler", "GetStarted": "Başlayın", "Documents": "Dokümanlar", - "Community": "Topluluk", "ContributionGuide": "Katkı Rehberi", "Blog": "Blog", - "Commercial": "Ticari", "MyAccount": "Hesabım", "Permission:License": "Lisans", "Permission:UserInfo": "kullanıcı bilgisi", "SeeDocuments": "Dokümanlara Göz Atın", - "Samples": "örnekler", - "Framework": "Çerçeve", - "Support": "Destek", + "Samples": "Örnekler", "FreeDDDBook": "Ücretsiz DDD Kitabı", "New": "Yeni", "Volo.AbpIo.Domain:020005": "Lisans uzatma yılı {MinExtendLicenseYear} yıldan az {MaxExtendLicenseYear} yıldan fazla olamaz.", @@ -96,7 +92,7 @@ "MySupportQuestions": "Destek Sorularım", "MyProfile": "Profilim", "Logout": "Çıkış Yap", - "Home": "Ev", + "Home": "Ana Sayfa", "Posts": "Gönderiler", "JoinTheABPCommunity": "ABP Topluluğuna Katılın", "SubmitYourPost": "Gönderinizi Gönderin", @@ -166,6 +162,12 @@ "ABPCommunityTalks": "ABP Topluluk Konuşmaları", "ABPCommunityPosts": "ABP Topluluk Gönderileri", "WelcomeFallCampaign": "Hoş Geldin Sonbahar Kampanyası!", - "GiveAwayForNewPurchases": "Yeni alımlar için Uygulama Geliştirme Sınıfı Eğitimi hediye edilecektir!" + "GiveAwayForNewPurchases": "Yeni alımlar için Uygulama Geliştirme Sınıfı Eğitimi hediye edilecektir!", + "ExploreTheContentsCreatedByTheCoreABPTeamAndTheABPCommunity": "ABP ekibi ve ABP topluluğu tarafından oluşturulan içerikleri keşfedin.", + "CheckAllCommunityTalks": "Tüm Topluluk Gönderilerine Göz Atın", + "ExploreTheBook": "Kitabı Keşfedin", + "ExploreTheEBook": "E-Kitabı Keşfedin", + "LatestVideos": "Son Videolar", + "Videos": "Videolar" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json index 0dcd69bbd8..af0190dcbb 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json @@ -26,6 +26,8 @@ "Volo.AbpIo.Domain:030009": "找不到用户!", "Volo.AbpIo.Domain:030010": "要购买试用许可证,您首先需要激活您的试用许可证!", "Volo.AbpIo.Domain:030011": "购买后不能删除试用许可证!", + "Volo.AbpIo.Domain:030012": "用户只有一个免费试用期。您已经使用了试用许可证。", + "Volo.AbpIo.Domain:030013": "已激活许可证的用户无法启动试用许可证。", "Volo.AbpIo.Domain:070000": "组织名称只能包含拉丁字母、数字、点和连字符!", "Volo.AbpIo.Domain:070001": "公司名称只能包含拉丁字母、数字、点、空格和连字符!", "WantToLearn?": "想学习吗?", @@ -183,6 +185,29 @@ "BlackFriday": "黑色 星期五", "ValidForExistingCustomers": "也适用于
现有用户!", "CampaignBetweenDates": "从 {0}
至 {1}", - "SaveUpTo": "最多节省${0}K" + "SaveUpTo": "最多节省${0}K", + "ImplementingDDD": "实现领域驱动设计", + "ExploreTheEBook": "浏览电子书", + "ExploreTheBook": "浏览书籍", + "ConsultantType": "顾问类型", + "Expert": "ABP专家", + "Partner": "ABP合作伙伴", + "Industry": "行业", + "Location": "地点", + "Contact": "联系", + "Partner_Year": "合作年份", + "Info": "信息", + "SpokenLanguages": "母语", + "SocialMedia": "社交媒体", + "Activity": "活动", + "Type": "类型", + "Contribution": "贡献", + "WhoWeAre": "关于我们", + "Icons": "图标", + "Url": "Url", + "Icon": "图标", + "RecentActivities": "最近的活动", + "SpringCampaign": "欢迎
春季促销!", + "SpringCampaign2": "限时优惠!
" } -} +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ar.json index d441da99a4..6da2313da5 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ar.json @@ -1,7 +1,7 @@ { "culture": "ar", "texts": { - "AbpTitle": "إطار عمل ABP - إطار عمل تطبيق ويب مفتوح المصدر", + "AbpTitle": "قراءة جميع مشاركات المدونة", "AbpDescription": "ABP هو إطار عمل مفتوح المصدر يركز على تطوير تطبيقات الويب القائمة على AspNet Core. لا تكرر نفسك ، ركز على كود عملك الخاص." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/en.json index 6f52556e72..2da5698215 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/en.json @@ -1,7 +1,8 @@ { "culture": "en", "texts": { - "AbpTitle": "ABP Framework - Open Source Web Application Framework", - "AbpDescription": "ABP is an open source application framework focused on AspNet Core based web application development. Don't repeat yourself, focus on your own business code." + "AbpTitle": "Read All Blog Posts", + "AbpDescription": "ABP is an open source application framework focused on AspNet Core based web application development. Don't repeat yourself, focus on your own business code.", + "AbpDefinition": "ABP blog for .NET development, cross-platform, ASP.NET application templates, ABP-related news and more..." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/fi.json new file mode 100644 index 0000000000..26f9152365 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/fi.json @@ -0,0 +1,8 @@ +{ + "culture": "fi", + "texts": { + "AbpTitle": "ABP Framework - avoimen lähdekoodin verkkosovelluskehys", + "AbpDescription": "ABP on avoimen lähdekoodin sovelluskehys, joka keskittyy AspNet Core -pohjaiseen verkkosovelluskehitykseen. Älä toista itseäsi, vaan keskity omaan yrityskoodiisi.", + "AbpDefinition": "ABP-blogi .NET-kehityksestä, useista alustoista, ASP.NET-sovellusmalleista, ABP:hen liittyvistä uutisista ja muusta..." + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/tr.json index c5f72d9fbe..6c75de02f9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/tr.json @@ -1,7 +1,7 @@ { "culture": "tr", "texts": { - "AbpTitle": "ABP Framework - Açık Kaynak Web Uygulama Çerçevesi", + "AbpTitle": "Tüm Blog Yazılarını Oku", "AbpDescription": "ABP, AspNet Core tabanlı web uygulaması geliştirmeye odaklanan açık kaynaklı bir uygulama çerçevesidir. Kendinizi tekrar etmeyin, kendi iş kodunuza odaklanın." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hans.json index 524c3345e3..7ede6b35c2 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hans.json @@ -1,7 +1,8 @@ { "culture": "zh-Hans", "texts": { - "AbpTitle": "ABP 框架 - 开源 Web 应用程序框架", - "AbpDescription": "ABP 是一个开源应用程序框架,专注于基于 AspNet Core 的 Web 应用程序开发。 Don't repeat yourself,专注于自己的业务代码。" + "AbpTitle": "阅读所有博客文章", + "AbpDescription": "ABP 是一个开源应用程序框架,专注于基于 AspNet Core 的 Web 应用程序开发。 Don't repeat yourself,专注于自己的业务代码。", + "AbpDefinition": ".NET开发的ABP博客,跨平台,ASP.NET应用程序模板,ABP相关新闻等..." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json index b202302d8e..938f3f9525 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json @@ -48,7 +48,7 @@ "LiveDemo": "عرض حي", "GetLicence": "احصل على ترخيص", "Application": "تطبيق", - "StartupTemplates": "قوالب بدء التشغيل", + "StartupTemplates": "قوالب بدء تشغيل ABP", "Startup": "بدء", "Templates": "القوالب", "Developer": "مطور", @@ -190,7 +190,7 @@ "ChangingDevelopers": "هل يمكنني تغيير المطورين المسجلين لمنظمتي في المستقبل؟", "ChangingDevelopersExplanation": "بالإضافة إلى إضافة مطورين جدد إلى الترخيص الخاص بك ، يمكنك أيضًا تغيير المطورين الحاليين (يمكنك إزالة مطور وإضافة مطور جديد إلى نفس المقعد) دون أي تكلفة إضافية.", "WhenShouldIRenewMyLicense": "متى يجب أن أجدد رخصتي؟", - "WhenShouldIRenewMyLicenseExplanation": "إذا قمت بتجديد ترخيصك في غضون شهر واحد بعد انتهاء صلاحية ترخيصك ، فسيتم تطبيق الخصومات التالية: ترخيص الفريق {0}؛ رخصة تجارية {1} ؛ ترخيص المؤسسة {2}. ومع ذلك ، إذا جددت ترخيصك بعد شهر واحد من تاريخ انتهاء صلاحية الترخيص ، فسيكون سعر التجديد هو نفسه سعر شراء الترخيص ولن يكون هناك خصم على التجديد.", + "WhenShouldIRenewMyLicenseExplanation": "إذا قمت بتجديد ترخيصك في غضون {3} يوما بعد انتهاء صلاحية رخصتك ، فسيتم تطبيق الخصومات التالية: رخصة الفريق {0}؛ الرخصة التجارية {1} ؛ رخصة المؤسسة {2}. ومع ذلك ، إذا جددت رخصتك بعد {3} يوما من تاريخ انتهاء صلاحية الرخصة ، فسيكون سعر التجديد هو نفسه سعر شراء الرخصة ولن يكون هناك خصم على التجديد.", "TrialPlan": "هل لديك خطة تجريبية؟", "DoYouAcceptBankWireTransfer": "هل تقبل التحويل البنكي؟", "DoYouAcceptBankWireTransferExplanation": "نعم ، نحن نقبل التحويل البنكي.
بعد إرسال رسوم الترخيص عبر التحويل المصرفي ، أرسل لنا بريدًا إلكترونيًا على accounting@abp.io إيصالك ونوع الترخيص المطلوب. معلومات حسابنا المصرفي الدولي:", @@ -489,7 +489,7 @@ "AddBasket": "إضافة إلى السلة", "SendTrainingRequest": "إرسال طلب تدريب", "OnlyEnglishVersionOfThisDocumentIsTheRecentAndValid": "* النسخة الإنجليزية من هذه الوثيقة هي الأحدث وستتم العةدة اليها خلال أي نزاع.", - "Pricing_Page_Title": "الخطط والتسعير", + "Pricing_Page_Title": "التسعير والخطط", "Pricing_Page_Description": "اختر الميزات والوظائف التي يحتاجها عملك اليوم. شراء رخصة تجارية ABP وإنشاء مشاريع غير محدودة.", "Pricing_Page_HurryUp": "أسرع!", "Pricing_Page_BuyLicense": "اشترِ رخصة من أسعار 2021 حتى 16 يناير!", @@ -515,6 +515,7 @@ "Pricing_Page_Testimonial_3": "نحن نحب ABP. ليس علينا كتابة كل شيء من الصفر. نبدأ من الميزات الجاهزة ونركز فقط على ما نحتاج حقًا إلى كتابته. أيضًا ، ABP مصمم جيدًا والشفرة عالية الجودة مع عدد أقل من الأخطاء. إذا كان علينا كتابة كل ما نحتاجه بمفردنا ، فقد نضطر إلى قضاء سنوات. مرة أخرى نحب أن الإصدار الجديد ، أو إصلاح المشكلة ، أو التحسين يأتي قريبًا جدًا كل أسبوعين. نحن لا ننتظر طويلا.", "Pricing_Page_Testimonial_4": "ABP التجاري منتج رائع يوصى به. تسويق المنتجات التجارية لعملائنا في منصة واحدة قابلة للتكوين. البداية السريعة التي يوفرها إطار العمل والأدوات لأي فريق تستحق كل سنت. كانت ABP هي الأنسب لاحتياجاتنا.", "Pricing_Page_Testimonial_5": "إطار عمل ABP ليس مجرد إطار عمل ، ولكنه أيضًا دليل لتطوير / إدارة المشروع ، لأنه يوفر تدريب DDD و GenericRepository و DI و Microservice و Modularity. حتى إذا كنت لن تستخدم الإطار نفسه ، يمكنك تطوير نفسك باستخدام docs.abp.io المُعد جيدًا ومهنيًا (OpenIdict و Redis و Quartz وما إلى ذلك). نظرًا لأن العديد من الأشياء مبنية مسبقًا ، فإنها تقصر وقت تطوير المشروع بشكل كبير (مثل صفحة تسجيل الدخول ، ومعالجة الاستثناءات ، وتصفية البيانات ، والبذر ، وتسجيل التدقيق ، والترجمة ، ووحدة التحكم في واجهة برمجة التطبيقات التلقائية ، وما إلى ذلك). كمثال من تطبيقنا ، لقد استخدمت Local Event Bus للتحكم في المخزون. لذلك ، أنا قادر على إدارة حركات الأوامر عن طريق كتابة معالج الأسهم. إنه لأمر رائع ألا تضيع الوقت من أجل CreationTime ، CreatorId. يتم ملؤها تلقائيًا.", + "Pricing_Page_Testimonial_6": "إطار عمل ABP هو إطار عمل جيد ولكنه يحتاج إلى وقت لفهم الطبقات والفئات والمكتبات المختلفة التي يستخدمها (خاصة ABP). قضيت الكثير من الوقت في قراءة قاعدة الكود ، لكن ABP Commercial توفر لنا الوقت لإنشاء كيانات تخصص المشروع (AR) والمستودع المرتبط بكل منها. أعجبني أيضًا أن النهج المستخدم في ABP ناضج جدًا ، ونعلم أنه يعتمد على DDD و monolith.", "AbpBookDownloadArea_ClaimYourEBook": "احصل على كتاب إتقان إطار عمل ABP الالكتروني الخاص بك", "AddMemberModal_Warning_1": "اذا كان المستخدم الذي تحاول اضافته لا يوجد في النظام, يرجى مطالبة عضو فريقك بالتسجيل في {0} ومشاركة اسم المستخدم الخاص بحسابه معك.", "MyOrganizations_Detail_WelcomeMessage": "مرحبًا بك في مؤسستك، {0}", @@ -599,12 +600,11 @@ "Faq_Page_Currency": "العملة", "Faq_Page_VatNumber": "رقم ضريبة القيمة المضافة", "Faq_Page_OtherCurrenciesInfo": "للعملات الأخرى ، انظر الى جميع الحسابات", - "ModuleDetail_Page_Title": "تفاصيل الوحدة - {0}", "ProjectCreatedSuccess_Page_Title": "تم إنشاء مشروعك", "ProjectCreatedSuccess_Page_Description": "تم إنشاء مشروع ABP الخاص بك بنجاح!", - "Suite_Page_Title": "ABP Suite - إنشاء صفحات CRUD", + "Suite_Page_Title": "جناح ABP", "Suite_Page_Description": "يوفر ABP التجاري أدوات تطوير سريعة للتطبيقات لزيادة إنتاجية المطورين. يتيح لك ABP Suite إنشاء صفحات CRUD بسهولة.", - "Themes_Page_Title": "سمات واجهة المستخدم الحديثة والوظيفية", + "Themes_Page_Title": "ثيمات ABP", "Themes_Page_Description": "يوفر ABP التجاري العديد من سمات واجهة المستخدم الاحترافية والحديثة. أنشئ عرضًا تجريبيًا مجانيًا للحصول على عرض سريع لشكل واجهة المستخدم.", "Tools_Page_Title": "أدوات تطوير التطبيقات السريعة", "Tools_Page_Description": "يوفر ABP التجاري أدوات تطوير سريعة للتطبيقات لزيادة إنتاجية المطورين. يتيح لك ABP Suite إنشاء صفحات CRUD بسهولة.", @@ -779,6 +779,13 @@ "UpgradePaymentInfoSection_LicenseRenewalPrice": "تجديد الرخصة", "Total": "المجموع", "SupportPolicyFaqTitle": "ما هي سياسة الدعم الخاصة بك؟", - "SupportPolicyFaqExplanation": "نحن ندعم فقط الإصدار الرئيسي النشط والسابق. لا نضمن إصدار تصحيح للإصدارات الرئيسية الثالثة والأقدم. على سبيل المثال ، إذا كان الإصدار النشط هو 7.0.0 ، فسنصدر إصدارات تصحيح لكل من 6.x.x و 7.x.x. إلى جانب ذلك ، نحن نقدم الدعم فقط لإطار عمل ABP والقضايا التجارية المتعلقة بـ ABP. هذا يعني أنه لا يتم تقديم أي دعم لتطبيقات الطرف الثالث والخدمات السحابية والمكتبات الطرفية الأخرى التي تستخدمها منتجات ABP. سنبذل جهودًا معقولة تجاريًا لتزويد عملائنا بالدعم الفني خلال ساعات العمل الرسمية لـ \"Volosoft Bilisim A.S\". من ناحية أخرى ، نحن لا نلتزم بوقت استجابة اتفاقية مستوى الخدمة (SLA) ، لكننا سنحاول الرد على المشكلات الفنية في أسرع وقت ممكن خلال ساعات العمل الرسمية لدينا. ما لم يتم إبرام اتفاقية خاصة مع العميل ، فإننا نقدم الدعم فقط على https://support.abp.io. لدينا أيضًا دعم خاص بالبريد الإلكتروني ، وهو متاح فقط لحاملي تراخيص المؤسسة." + "SupportPolicyFaqExplanation": "نحن ندعم فقط الإصدار الرئيسي النشط والسابق. لا نضمن إصدار تصحيح للإصدارات الرئيسية الثالثة والأقدم. على سبيل المثال ، إذا كان الإصدار النشط هو 7.0.0 ، فسنصدر إصدارات تصحيح لكل من 6.x.x و 7.x.x. إلى جانب ذلك ، نحن نقدم الدعم فقط لإطار عمل ABP والقضايا التجارية المتعلقة بـ ABP. هذا يعني أنه لا يتم تقديم أي دعم لتطبيقات الطرف الثالث والخدمات السحابية والمكتبات الطرفية الأخرى التي تستخدمها منتجات ABP. سنبذل جهودًا معقولة تجاريًا لتزويد عملائنا بالدعم الفني خلال ساعات العمل الرسمية لـ \"Volosoft Bilisim A.S\". من ناحية أخرى ، نحن لا نلتزم بوقت استجابة اتفاقية مستوى الخدمة (SLA) ، لكننا سنحاول الرد على المشكلات الفنية في أسرع وقت ممكن خلال ساعات العمل الرسمية لدينا. ما لم يتم إبرام اتفاقية خاصة مع العميل ، فإننا نقدم الدعم فقط على https://support.abp.io. لدينا أيضًا دعم خاص بالبريد الإلكتروني ، وهو متاح فقط لحاملي تراخيص المؤسسة.", + "WhyUseAbpIoPlatform": "لماذا يجب علي استخدام منصة ABP.IO بدلاً من إنشاء حل جديد من البداية؟", + "WhyUseAbpIoPlatformFaqExplanation": "انظر الى هذا المستند للحصول على شرح مفصل لسبب استخدام ABP.IO Platform لفائدته الكبيرة بدلًا من القيام بكل شيء بنفسك.", + "EulaPageTitle": "اتفاقية ترخيص المستخدم النهائي (EULA)", + "PrivacyPolicyPageTitle": "سياسة الخصوصية - سياسة ملفات تعريف الارتباط", + "TermsConditionsPageTitle": "الأحكام والشروط", + "TrainingsPageTitle": "حزم تدريب ABP", + "ModulesPageTitle": "وحدات تطبيق ABP سابقة البناء" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json index f50b176063..a1205f1809 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Mohu v budoucnu změnit registrované vývojáře své organizace?", "ChangingDevelopersExplanation": "Kromě přidání nových vývojářů do vaší licence můžete také změnit stávající vývojáře (můžete odebrat vývojáře a přidat nového na stejné místo) bez jakýchkoli dalších nákladů.", "WhenShouldIRenewMyLicense": "Kdy bych měl obnovit licenci?", - "WhenShouldIRenewMyLicenseExplanation": "Pokud si licenci obnovíte do 1 měsíce po vypršení platnosti licence, budou uplatněny následující slevy: Týmová licence {0}; Obchodní licence {1}; Enterprise Licence {2}. Pokud však licenci obnovíte po 1 měsíci od data vypršení platnosti vaší licence, cena za obnovení bude stejná jako cena za zakoupení licence a na obnovení nebude poskytnuta žádná sleva.", + "WhenShouldIRenewMyLicenseExplanation": "Pokud si licenci obnovíte do {3} dní po vypršení platnosti licence, budou uplatněny následující slevy: Týmová licence {0}; Obchodní licence {1}; Enterprise Licence {2}. Pokud však licenci obnovíte po {3} měsíci od data vypršení platnosti vaší licence, cena za obnovení bude stejná jako cena za zakoupení licence a na obnovení nebude poskytnuta žádná sleva.", "TrialPlan": "Máte zkušební plán?", "DoYouAcceptBankWireTransfer": "Přijímáte bankovní převod?", "DoYouAcceptBankWireTransferExplanation": "Ano, přijímáme bankovní převod.
Po zaslání licenčního poplatku bankovním převodem nám zašlete e-mail na adresu accounting@abp.io potvrzení a požadovaný typ licence. Informace o našem mezinárodním bankovním účtu:", @@ -383,6 +383,24 @@ "RenewLicenseEarly": "Pokud si předčasně obnovím licenci, dostanu celý rok?", "RenewLicenseEarylExplanation": "Když obnovíte licenci před datem vypršení platnosti licence, bude k datu vypršení platnosti licence přidán 1 rok. Pokud například platnost vaší licence vyprší dne {0}-06-06 a obnovíte ji dne {0}-01-01, bude vaše nové datum vypršení platnosti licence {1}-06-06.", "discountForYears": "{0}% sleva po dobu {1} let", - "BlackFridayDiscount": "Black Friday sleva" + "BlackFridayDiscount": "Black Friday sleva", + "OnboardingTrainingFaqTitle": "Máte školení ABP onboarding?", + "OnboardingTrainingFaqExplanation": "Ano, máme školicí služby ABP, které vám pomohou rychle zahájit váš projekt ABP. Dozvíte se o ABP od hlavního člena týmu ABP a získáte dovednosti pro zahájení vašeho projektu ABP. Na onboarding školení si vysvětlíme, jak nastavit vaše vývojové prostředí, nainstalovat požadované nástroje, vytvořit plně funkční stránku CRUD. Školení bude probíhat živě a bude se používat aplikace Zoom a jsme otevřeni využití dalších online platforem pro setkávání. Jazykem školení bude angličtina. Během sezení můžete také klást otázky týkající se ABP. Pro obě strany bude naplánován vhodný čas a datum. Chcete-li získat další informace, kontaktujte nás na adrese info@abp.io.", + "SupportPolicyFaqTitle": "Jaká je vaše politika podpory?", + "SupportPolicyFaqExplanation": "Podporujeme pouze aktivní a předchozí hlavní verzi. Nezaručujeme vydání opravy pro třetí a starší hlavní verzi. Například pokud je aktivní verze 7.0.0, vydáme opravné verze pro verzi 6.x.x i 7.x.x. Kromě toho poskytujeme podporu pouze pro problémy související s ABP Framework a ABP Commercial. To znamená, že neposkytujeme žádnou podporu aplikacím třetích stran, cloudovým službám a dalším periferním knihovnám používaným produkty ABP. Vynaložíme komerčně přiměřené úsilí, abychom našim zákazníkům poskytli technickou podporu během oficiální pracovní doby společnosti \"Volosoft Bilisim A.S\". Na druhou stranu se nezavazujeme k době odezvy podle dohody o úrovni služeb (SLA), ale budeme se snažit reagovat na technické problémy co nejrychleji v rámci naší oficiální pracovní doby. Pokud není se zákazníkem uzavřena zvláštní dohoda, poskytujeme podporu pouze na adrese https://support.abp.io. Máme také soukromou e-mailovou podporu, která je k dispozici pouze držitelům licence Enterprise.", + "DowngradeLicensePlan": "Mohu v budoucnu přejít na nižší licenční plán?", + "DowngradeLicensePlanExplanation": "Stávající licenční plán nelze snížit. Můžete si však zakoupit nový nižší licenční plán a pokračovat ve vývoji s novou licencí. Po zakoupení nižší licence se stačí přihlásit k novému licenčnímu plánu pomocí příkazu ABP CLI: abp login -o `.", + "LicenseTransfer": "Lze licenci převést z jednoho vývojáře na druhého?", + "LicenseTransferExplanation": "Ano! Zakoupením licence se stáváte jejím držitelem, a proto budete mít přístup na stránku pro správu organizace. Organizace má role vlastníka a vývojáře. Vlastníci mohou spravovat místa pro vývojáře a přiřazovat vývojáře. Každý přidělený vývojář se do systému přihlásí pomocí příkazu ABP CLI a bude mít oprávnění k vývoji a podpoře.", + "WhatHappensWhenLicenseEnds": "Co se stane po skončení licenčního období?", + "WhatHappensWhenLicenseEndsExplanation1": "Komerční licence ABP je trvalá licence. Po vypršení platnosti licence můžete pokračovat ve vývoji svého projektu. A nejste povinni licenci obnovovat. Vaše licence je dodávána s ročním plánem aktualizací a podpory již v balení. Abyste mohli i nadále získávat nové funkce, vylepšení výkonu, opravy chyb, podporu a pokračovat v používání sady ABP Suite, musíte svou licenci obnovit. Po vypršení platnosti licence;", + "WhatHappensWhenLicenseEndsExplanation2": "Pomocí ABP Commercial nemůžete vytvářet nová řešení, ale můžete navždy pokračovat ve vývoji stávajících aplikací.", + "WhatHappensWhenLicenseEndsExplanation3": "Aktualizace modulů a témat budete moci získat v rámci své verze MINOR (kromě verzí RC nebo Preview). Například: pokud používáte modul ve verzi 3.2.0, můžete stále získávat aktualizace pro verzi 3.2.x (v3.2.1, v3.2.5... atd.) tohoto modulu. Nemůžete však získat aktualizace pro další hlavní nebo vedlejší verzi (např. v3.3.0, v3.3.3, 4.x.x... atd.). Například když vám vypršela licence, poslední verze byla v4.4.3 a později byla zveřejněna jak verze 4.4.4, tak verze 4.5.0, měli byste přístup k verzi v4.4.X, ale k verzi v4.5.X byste přístup neměli.", + "WhatHappensWhenLicenseEndsExplanation4": "Po skončení platnosti licence nelze instalovat nové moduly a motivy přidané do platformy ABP Commercial.", + "WhatHappensWhenLicenseEndsExplanation5": "Sadu ABP Suite nelze použít.", + "WhatHappensWhenLicenseEndsExplanation6": "Již nelze získat prémiovou podporu.", + "WhatHappensWhenLicenseEndsExplanation7": "Pokud chcete i nadále využívat tyto výhody, můžete svou licenci prodloužit (obnovit). Pokud prodloužíte licenci do {3} dní po vypršení platnosti licence, budou uplatněny následující slevy: Týmová licence {0}; Obchodní licence {1}; Enterprise Licence {2}.", + "BlazoriseLicense": "Musíme si koupit licenci Blazorise?", + "BlazoriseLicenseExplanation": "Máme dohodu mezi společnostmi Volosoft a Megabit, na základě této dohody je licence Blazorise přibalena k produktům ABP Commercial, proto si naši zákazníci nemusí kupovat další licenci Blazorise." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json index 5b4eb201aa..ebc78f8b51 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Kann ich die registrierten Entwickler meiner Organisation in Zukunft ändern?", "ChangingDevelopersExplanation": "Sie können nicht nur neue Entwickler zu Ihrer Lizenz hinzufügen, sondern auch die vorhandenen Entwickler ändern (Sie können einen Entwickler entfernen und einen neuen zum selben Arbeitsplatz hinzufügen) ohne zusätzliche Kosten.", "WhenShouldIRenewMyLicense": "Wann sollte ich meine Lizenz erneuern?", - "WhenShouldIRenewMyLicenseExplanation": "Wenn Sie Ihre Lizenz innerhalb von 1 Monat nach Ablauf Ihrer Lizenz erneuern, werden die folgenden Rabatte gewährt: Team-Lizenz {0}% Rabatt, Business-Lizenz {1}% Rabatt, Enterprise-Lizenz {2}% Rabatt . Wenn Sie Ihre Lizenz 1 Monat nach dem Ablaufdatum Ihrer Lizenz verlängern, entspricht der Verlängerungspreis dem Lizenzkaufpreis und es wird kein Rabatt auf Ihre Verlängerung gewährt.", + "WhenShouldIRenewMyLicenseExplanation": "Wenn Sie Ihre Lizenz innerhalb von {3} Tage nach Ablauf Ihrer Lizenz erneuern, werden die folgenden Rabatte gewährt: Team-Lizenz {0}% Rabatt, Business-Lizenz {1}% Rabatt, Enterprise-Lizenz {2}% Rabatt . Wenn Sie Ihre Lizenz {3} Tage nach dem Ablaufdatum Ihrer Lizenz verlängern, entspricht der Verlängerungspreis dem Lizenzkaufpreis und es wird kein Rabatt auf Ihre Verlängerung gewährt.", "TrialPlan": "Hast du einen Probeplan?", "DoYouAcceptBankWireTransfer": "Akzeptieren Sie Banküberweisungen?", "DoYouAcceptBankWireTransferExplanation": "Ja, wir akzeptieren Banküberweisungen.
Nachdem Sie die Lizenzgebühr per Banküberweisung gesendet haben, senden Sie uns Ihre Quittung und den gewünschten Lizenztyp per E-Mail an accounting@abp.io. Unsere internationale Bankverbindung:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 6e5e69f079..b388a4e71b 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -160,7 +160,7 @@ "SearchQuestionPlaceholder": "Search in frequently asked questions", "WhatIsTheABPCommercial": "What is ABP Commercial?", "WhatAreDifferencesThanAbpFramework": "What are the differences between the open source ABP Framework and ABP Commercial?", - "AbpCommercialMetaTitle": "ABP Commercial - Complete Web Development Platform : {0} | ABP Commercial", + "AbpCommercialMetaTitle": " {0} | ABP Commercial", "AbpCommercialMetaDescription": "ABP Commercial is a set of pre-built application modules, rapid development tooling, UI themes and services built on top of the open-source ABP framework.", "ABPCommercialExplanation": "ABP Commercial is a set of premium modules, tools, themes and services that are built on top of the open source ABP framework. ABP Commercial is being developed and supported by the same team behind the ABP framework.", "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP framework is a modular, themeable, microservice compatible application development framework for ASP.NET Core. It provides a complete architecture and a strong infrastructure to let you focus on your own business code rather than repeating yourself for every new project. It is based on the best practices of software development and popular tools you already know.

ABP framework is completely free, open source and community-driven. It also provides a free theme and some pre-built modules (e.g. identity management and tenant management).

", @@ -196,19 +196,19 @@ "ChangingDevelopers": "Can I change the registered developers of my organization in the future?", "ChangingDevelopersExplanation": "In addition to adding new developers to your license, you can also change the existing developers (you can remove a developer and add a new one to the same seat) without any additional cost.", "WhatHappensWhenLicenseEnds": "What happens when my license period ends?", - "WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a perpetual license. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires, you will not get the following benefits:", + "WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a perpetual license. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires;", "WhatHappensWhenLicenseEndsExplanation2": "You can not create new solutions using the ABP Commercial, but you can continue developing your existing applications forever.", "WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MINOR version (except RC or Preview versions). For example: if you are using v3.2.0 of a module, you can still get updates for v3.2.x (v3.2.1, v3.2.5... etc.) of that module. But you cannot get updates for the next major or minor version (like v3.3.0, v3.3.3, 4.x.x.. etc.). For example, when your license expired, the latest release was v4.4.3, and later, it published both 4.4.4 version and 4.5.0 version, you would be able to access the v4.4.X but you wouldn't be access the v4.5.X.", "WhatHappensWhenLicenseEndsExplanation4": "You can not install new modules and themes added to the ABP Commercial platform after your license ends.", "WhatHappensWhenLicenseEndsExplanation5": "You can not use the ABP Suite.", "WhatHappensWhenLicenseEndsExplanation6": "You can not get the premium support anymore.", - "WhatHappensWhenLicenseEndsExplanation7": "You can extend (renew) your license if you want to continue getting these benefits. If you extend your license within 1 month after your license expires, the following discounts will be applied: Team License {0}; Business License {1}; Enterprise License {2}.", + "WhatHappensWhenLicenseEndsExplanation7": "You can extend (renew) your license if you want to continue getting these benefits. If you extend your license within {3} days after your license expires, the following discounts will be applied: Team License {0}; Business License {1}; Enterprise License {2}.", "discountForYears": "{0}% discount for {1} year(s)", "WhatHappensWhenLicenseEndsExplanation8": "The ABP projects you generated are not stored on our servers. Therefore, it is your responsibility to keep the source code you download. When your license expires, there's no way to get your generated ABP project source code.", "WhenShouldIRenewMyLicense": "When should I renew my license?", - "WhenShouldIRenewMyLicenseExplanation": "If you renew your license within 1 month after your license expires, the following discounts will be applied: Team License {0}; Business License {1}; Enterprise License {2}. However, if you renew your license after 1 month since the expiry date of your license, the renewal price will be the same as the license purchase price and there will be no discount on your renewal.", + "WhenShouldIRenewMyLicenseExplanation": "If you renew your license within {3} days after your license expires, the following discounts will be applied: Team License {0}; Business License {1}; Enterprise License {2}. However, if you renew your license after {3} days since the expiry date of your license, the renewal price will be the same as the license purchase price and there will be no discount on your renewal.", "TrialPlan": "Do you have a trial plan?", - "TrialPlanExplanation": "It has a 14 days trial period for the ABP Commercial team license. For more information visit here. Furthermore, for the Team licenses we provide a 30 days money-back guarantee. You can just request a refund in the first 30 days. For the Business and Enterprise licenses, we provide 60% refund in 30 days. This is because Business and Enterprise licenses include the full source code of all the modules and the themes.", + "TrialPlanExplanation": "No, there is no trial version for ABP Commercial. You can check the community edition to understand the code quality and approaches. We also offer a 30-day money-back guarantee for the Team license, no questions asked! You can request a refund within the first 30 days. We provide a 60% refund within 30 days for Business and Enterprise licenses. This is because the Business and Enterprise licenses contain the full source-code of all the modules and themes.", "DoYouAcceptBankWireTransfer": "Do you accept bank wire transfers?", "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfers.
After sending the license fee via bank transfer, send your receipt and requested license type to accounting@volosoft.com.
Our international bank account information:", "HowToUpgrade": "How to upgrade existing applications when a new version is available?", @@ -511,7 +511,7 @@ "AddBasket": "Add to Basket", "SendTrainingRequest": "Send Training Request", "OnlyEnglishVersionOfThisDocumentIsTheRecentAndValid": "* The English version of this document is the most up-to-date and the English version will prevail in any dispute.", - "Pricing_Page_Title": "Plans & Pricing", + "Pricing_Page_Title": "Pricing & Plans", "Pricing_Page_Description": "Choose the features and functionality your business needs today. Buy an ABP Commercial license and create unlimited projects.", "Pricing_Page_HurryUp": "Hurry Up!", "Pricing_Page_BuyLicense": "Buy a license at 2021 prices until January 16!", @@ -537,6 +537,7 @@ "Pricing_Page_Testimonial_3": "We love ABP. We don't have to write everything from scratch. We start from out-of-the-box features and just focus on what we really need to write. Also, ABP is well-architected and the code is high quality with fewer bugs. If we would have to write everything we needed on our own, we might have to spend years. Once more things we like is that the new version, or issue fixing, or improvement come out very soon every other week. We don't wait too long.", "Pricing_Page_Testimonial_4": "ABP Commercial is a fantastic product would recommend. Commercial products to market for our customers in a single configurable platform. The jump start that the framework and tooling provide any team is worth every cent. ABP Commercial was the best fit for our needs.", "Pricing_Page_Testimonial_5": "ABP Framework is not only a framework, but it is also a guide for project development/management, because it provides DDD, GenericRepository, DI, Microservice, and Modularity training. Even if you are not going to use the framework itself, you can develop yourself with docs.abp.io which is well and professionally prepared (OpenIddict, Redis, Quartz etc.). Because many things are pre-built, it shortens project development time significantly (Such as login page, exception handling, data filtering, seeding, audit logging, localization, auto API controller etc.). As an example from our application, I have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler. It is wonderful not to lose time for CreationTime, CreatorId. They are being filled automatically.", + "Pricing_Page_Testimonial_6": "ABP Framework is a good framework but it needs time to understand the different layers, classes, and libraries it used (specially ABP). I spent a lot of time reading the code base, but ABP Commercial save us time to create the project specialty entities (AR) and the repository linked to each of them. I liked also the approach used in ABP is very mature, we know is based on DDD and monolith.", "AbpBookDownloadArea_ClaimYourEBook": "Claim your Mastering ABP Framework E-Book", "AddMemberModal_Warning_1": "If the username you are trying to add doesn't exist in the system, please ask your team member to register on {0} and share the username of his/her account with you.", "MyOrganizations_Detail_WelcomeMessage": "Welcome to your organization, {0}", @@ -597,7 +598,7 @@ "Purchase_PricePerDeveloper": "{0} {1} per developer", "Purchase_IncludedDeveloperInfo": "{0} {1} included.", "Purchase_LicenseExtraDeveloperPurchaseMessage": "The {0} license contains {1} developer(s). You can add additional developers now or later.", - "StartupTemplates_Page_Title": "The Startup Templates", + "StartupTemplates_Page_Title": "ABP Startup Templates", "StartupTemplates_Page_Description": "ABP Commercial allows you to build solutions with any level of complexity. It provides two main pre-built startup solutions. You can select the one close to your requirements and build your own custom solution on top of it.", "MicroserviceStartupSolutionForDotnet": "Microservice Startup Solution for .NET", "MonolithSolutionForDotnet": "Monolith (modular) Solution for .NET", @@ -622,12 +623,11 @@ "Faq_Page_Currency": "Currency", "Faq_Page_VatNumber": "VAT number", "Faq_Page_OtherCurrenciesInfo": "For other currencies, see all accounts", - "ModuleDetail_Page_Title": "Module Detail - {0}", "ProjectCreatedSuccess_Page_Title": "Your project created", "ProjectCreatedSuccess_Page_Description": "Your ABP project created successfully!", - "Suite_Page_Title": "ABP Suite - Create CRUD Pages", + "Suite_Page_Title": "ABP Suite", "Suite_Page_Description": "ABP Commercial provides rapid application development tooling to increase developer productivity. ABP Suite allows you to create CRUD pages easily.", - "Themes_Page_Title": "Modern and Functional UI Themes", + "Themes_Page_Title": "ABP Themes", "Themes_Page_Description": "ABP Commercial provides multiple professional, modern UI themes. Create a free demo to have a quick view of what the UI looks like.", "Tools_Page_Title": "Rapid Application Development Tools", "Tools_Page_Description": "ABP Commercial provides rapid application development tooling to increase developer productivity. ABP Suite allows you to create CRUD pages easily.", @@ -760,6 +760,7 @@ "ViewLiveDemo": "View Live Theme Demo", "GetLeptonX": "Get LeptonX Now", "SeeLeptonXDocumentation": "See LeptonX Documentation", + "SeeLeptonDocumentation": "See Lepton Documentation", "SimplifiedMenu": "Simplified menu", "SimplifiedMenuDescription": "You can easily find the page you are looking for by filtering the menu", "YourFavoritePages": "Your favorite pages at your reach", @@ -818,6 +819,18 @@ "DeletingMemberWarningMessage": "\"{0}\" will be removed from the developer list. If you want, you can assign this empty seat to another developer later.", "AdditionalInfo": "If the developer seats are above your requirements, you can reduce them. You can email at info@abp.io to remove some of your developer seats. Clearing unused developer seats will reduce the license renewal cost. If you want, you can re-purchase additional developer seats within your active license period. Note that, since there are {0} developers in this license package, you cannot reduce this number.", "LinkExpiredErrorMessage": "The link you are trying to access is expired.", - "ExpirationDate": "Expiration Date" + "ExpirationDate": "Expiration Date", + "SpringCampaignDiscount": "Spring Campaign Discount", + "WhyUseAbpIoPlatform": "Why should I use the ABP.IO Platform instead of creating a new solution from scratch?", + "WhyUseAbpIoPlatformFaqExplanation": "See that document for a detailed explanation of why using ABP.IO Platform has a significant advantage over doing everything yourself.", + "EulaPageTitle": "End User License Agreement (EULA)", + "PrivacyPolicyPageTitle": "Privacy Policy - Cookie Policy", + "TermsConditionsPageTitle": "Terms and Conditions", + "TrainingsPageTitle": "ABP Training Packages", + "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_LicenseExpiryDate": "Expiry Date" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json index 7625f777eb..88ce642703 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "¿Puedo cambiar los desarrolladores registrados de mi organización en el futuro?", "ChangingDevelopersExplanation": "Además de agregar nuevos desarrolladores a su licencia, también puede cambiar los desarrolladores existentes (puede eliminar un desarrollador y agregar uno nuevo al mismo puesto) sin ningún costo adicional.", "WhenShouldIRenewMyLicense": "¿Cuándo debo renovar mi licencia?", - "WhenShouldIRenewMyLicenseExplanation": "Si renueva su licencia dentro de 1 mes después de su vencimiento, se aplicarán los siguientes descuentos: Licencia de equipo {0}% de descuento, Licencia comercial {1}% de descuento, Licencia empresarial {2}% de descuento . Si renueva su licencia 1 mes después de la fecha de vencimiento de su licencia, el precio de renovación será el mismo que el precio de compra de la licencia y no habrá descuento en su renovación.", + "WhenShouldIRenewMyLicenseExplanation": "Si renueva su licencia dentro de {3} dias después de su vencimiento, se aplicarán los siguientes descuentos: Licencia de equipo {0}% de descuento, Licencia comercial {1}% de descuento, Licencia empresarial {2}% de descuento . Si renueva su licencia {3} dias después de la fecha de vencimiento de su licencia, el precio de renovación será el mismo que el precio de compra de la licencia y no habrá descuento en su renovación.", "TrialPlan": "¿Tiene un plan de prueba?", "DoYouAcceptBankWireTransfer": "¿Aceptan transferencia bancaria?", "DoYouAcceptBankWireTransferExplanation": "Sí, aceptamos transferencia bancaria.
Después de enviar la tarifa de la licencia mediante transferencia bancaria, envíenos un correo electrónico a accounting@abp.io con su recibo y el tipo de licencia solicitada. Nuestra información de cuenta bancaria internacional:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json index c2b09e4c5b..bc8bd81c8f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json @@ -9,15 +9,18 @@ "QuestionCount": "Jäljellä olevat/yhteensä kysymykset", "Unlimited": "Rajoittamaton", "Owners": "Omistajat", + "Owner": "Omistaja", "AddMember": "Lisää jäsen", - "AddOwner": "Lisää omistaja", - "AddDeveloper": "Lisää kehittäjä", + "AddNewOwner": "Lisää uusi omistaja", + "AddNewDeveloper": "Lisää uusi kehittäjä", "UserName": "Käyttäjätunnus", "Name": "Nimi", "EmailAddress": "Sähköpostiosoite", "Developers": "Kehittäjät", "LicenseType": "Lisenssi-tyyppi", "Manage": "Hallitse", + "SetDefault": "Aseta oletukseksi", + "DefaultOrganization": "Oletus", "StartDate": "Aloituspäivämäärä", "EndDate": "Päättymispäivä", "Modules": "Moduulit", @@ -60,8 +63,6 @@ "Themes": "Teemat", "JoinOurNewsletter": "Liity uutiskirjeemme", "Send": "Lähettää", - "Learn": "Oppia", - "AdditionalServices": "Lisäpalvelut", "WhatIsABPFramework": "MIKÄ ON ABP-KEHYS?", "OpenSourceBaseFramework": "Avoimen lähdekoodin peruskehys", "ABPFrameworkExplanation": "

ABP Commercial perustuu ABP Frameworkiin, avoimen lähdekoodin ja yhteisövetoiseen verkkosovelluskehykseen ASP.NET Core -sovellukselle.

ABP Framework tarjoaa erinomaisen infrastruktuurin ylläpitettävien, laajennettavien tiedostojen kirjoittamiseen. ja testattava koodi parhailla käytänteillä.

Rakennettu ja integroitu jo tunnettujen suosittujen työkalujen kanssa. Matala oppimiskäyrä, helppo sopeutuminen, mukava kehitys.

", @@ -127,6 +128,8 @@ "TellUsWhatYouNeed": "Kerro meille mitä tarvitset.", "YourMessage": "Viestisi", "YourFullName": "Koko nimesi", + "FirstNameField": "Etunimi", + "LastNameField": "Sukunimi", "EmailField": "Sähköpostiosoite", "YourEmailAddress": "Sähköpostiosoitteesi", "HowMayWeHelpYou": "Kuinka voimme auttaa sinua?", @@ -141,7 +144,7 @@ "ApplicationTemplateExplanation": "Sovelluksen käynnistysmallia käytetään uuden verkkosovelluksen luomiseen.", "EfCoreProvider": "Entity Framework (tukee SQL Serveriä, MySQL: ää, PostgreSQL: ää, Oracle ja muita )", "AlreadyIncludedInTemplateModules": "Seuraavat moduulit ovat jo mukana ja määritetty tähän malliin:", - "ApplicationTemplateArchitecture": "Tämä sovellusmalli tukee myös porrastettua arkkitehtuuria, jossa käyttöliittymäkerros, API-kerros ja todennuspalvelu on fyysisesti erotettu.", + "ApplicationTemplateArchitecture": "Tämä sovellusmalli tukee myös monikerros arkkitehtuuria, jossa käyttöliittymäkerros, API-kerros ja todennuspalvelu on fyysisesti erotettu.", "SeeTheGuideOrGoToTheLiveDemo": "Katso teknistä tietoa tästä mallista kehittäjän oppaasta tai siirry live-esittelyyn.", "DeveloperGuide": "Kehittäjän opas", "ModuleTemplate": "Moduulimalli", @@ -157,6 +160,8 @@ "SearchQuestionPlaceholder": "Hae usein kysyttyjä kysymyksiä", "WhatIsTheABPCommercial": "Mikä on ABP-kauppa?", "WhatAreDifferencesThanAbpFramework": "Mitä eroja on avoimen lähdekoodin ABP Frameworkilla ja ABP Commercialilla?", + "AbpCommercialMetaTitle": "ABP Commercial - täydellinen verkkokehitysalusta: {0} | ABP Commercial", + "AbpCommercialMetaDescription": "ABP Commercial on joukko valmiita sovellusmoduuleja, nopean kehityksen työkaluja, käyttöliittymäteemoja ja palveluita, jotka on rakennettu avoimen lähdekoodin ABP-kehyksen päälle.", "ABPCommercialExplanation": "ABP Commercial on joukko ensiluokkaisia moduuleja, työkaluja, teemoja ja palveluja, jotka on rakennettu avoimen lähdekoodin ABP-kehyksen päälle. ABP Commercial kehittää ja tukee samaa tiimiä ABP-kehyksen takana.", "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP-kehys on modulaarinen, teemoitettava, mikropalvelujen kanssa yhteensopiva sovelluskehys ASP.NET Core -sovellukselle. Se tarjoaa täydellisen arkkitehtuurin ja vahvan infrastruktuurin, joka saa sinut keskittymään omaan yrityskoodiin sen sijaan, että toistat itsesi jokaisessa uudessa projektissa. Se perustuu ohjelmistokehityksen parhaisiin käytäntöihin ja jo tiedettyihin suosittuihin työkaluihin.

ABP-kehykset ovat täysin ilmaisia, avoimen lähdekoodin ja yhteisölähtöisiä. Se tarjoaa myös ilmaisen teeman ja joitain valmiita moduuleja (esim. Henkilöllisyyden hallinta ja vuokralaisten hallinta).

", "VisitTheFrameworkVSCommercialDocument": "Vieraile seuraavalla linkillä saadaksesi lisätietoja {1} ", @@ -178,6 +183,7 @@ "ChangingLicenseType": "Voinko muuttaa lisenssityyppiäni tulevaisuudessa?", "ChangingLicenseTypeExplanation": "Voit aina lisätä uusia kehittäjiä samaan lisenssityyppiin. Katso myös \"Kuinka monta kehittäjää voi työskennellä ABP Commercialilla?\". Voit myös päivittää korkeampaan lisenssiin maksamalla lasketun hintaeron. Kun päivität korkeampaan lisenssisuunnitelmaan, saat uuden suunnitelman edut, mutta lisenssin päivitys ei muuta lisenssin voimassaolon päättymispäivää.", "LicenseExtendUpgradeDiff": "Mitä eroa on lisenssin laajennuksella ja päivityksellä?", + "LicenseExtendUpgradeDiffExplanation": "Pidentäminen: pidentämällä/uusimalla lisenssiä saat jatkossakin premium-tuen ja saat isoja tai pieniä päivityksiä moduuleille ja teemoille. Lisäksi voit jatkaa uusien projektien luomista. Ja voit silti käyttää ABP Suitea, joka nopeuttaa kehitystäsi. Kun jatkat lisenssiäsi, lisenssin voimassaolopäivään lisätään 1 vuosi.
Päivitys: Päivittämällä lisenssisi siirryt korkeampaan lisenssisuunnitelmaan, jonka avulla saat lisäetuja. Tutustu lisenssien vertailutaulukkoon nähdäksesi erot lisenssisuunnitelmien välillä. Toisaalta, kun päivität, lisenssisi viimeinen voimassaolopäivä ei muutu! Jos haluat pidentää lisenssin päättymispäivää, sinun on jatkettava lisenssiäsi.", "LicenseRenewalCost": "Mitkä ovat lisenssin uusimiskustannukset vuoden kuluttua?", "LicenseRenewalCostExplanation": "Standardin tiimilisenssin uusimishinta (pidennys) on ${0}, normaalin yrityslisenssin hinta on {1} $ ja normaalin yrityslisenssin hinta on {2} $. Jos olet jo asiakas, kirjaudu sisään tiliisi ja tarkista käytettävissä olevat uusimishinnat.", "HowDoIRenewMyLicense": "Kuinka uusin lisenssin?", @@ -189,9 +195,20 @@ "IsSourceCodeIncludedExplanation4": "

Moduulin lähdekoodin sisällyttäminen ratkaisuun antaa sinulle maksimaalisen vapauden mukauttaa moduulia. Tällöin moduulia ei voida päivittää automaattisesti, kun uusi versio julkaistaan.

Mikään lisensseistä ei sisällä ABP Suiten lähdekoodia, joka on ulkoinen työkalu, joka tuottaa koodia sinulle ja auttaa kehitykseen.

Katso muita lisenssityyppien eroja hinnoittelusivulta .

", "ChangingDevelopers": "Voinko muuttaa organisaationi rekisteröityneitä kehittäjiä tulevaisuudessa?", "ChangingDevelopersExplanation": "Uusien kehittäjien lisäämisen lisenssiin lisäksi voit myös muuttaa olemassa olevia kehittäjiä (voit poistaa kehittäjän ja lisätä uuden samalle paikalle) ilman lisäkustannuksia.", + "WhatHappensWhenLicenseEnds": "Mitä tapahtuu, kun lisenssikauteni päättyy?", + "WhatHappensWhenLicenseEndsExplanation1": "ABP Commercial -lisenssi on ikuinen lisenssi. Kun lisenssi päättyy, voit jatkaa projektisi kehittämistä. Etkä ole velvollinen uusimaan lisenssiäsi. Lisenssisi mukana tulee yhden vuoden päivitys- ja tukisuunnitelma suoraan pakkauksesta. Jotta voit jatkossakin saada uusia ominaisuuksia, suorituskykyparannuksia, vikakorjauksia, tukea ja jatkaa ABP Suiten käyttöä, sinun on uusittava lisenssi. Kun lisenssi päättyy;", + "WhatHappensWhenLicenseEndsExplanation2": "Et voi luoda uusia ratkaisuja ABP Commercialin avulla, mutta voit jatkaa olemassa olevien sovellusten kehittämistä ikuisesti.", + "WhatHappensWhenLicenseEndsExplanation3": "Voit saada päivityksiä moduuleihin ja teemoihin MINOR-versiossasi (lukuun ottamatta RC- tai Preview-versioita). Esimerkiksi: jos käytät moduulin v3.2.0 versiota, voit silti saada päivityksiä kyseisen moduulin v3.2.x versiolle (v3.2.1, v3.2.5... jne.). Mutta et voi saada päivityksiä seuraavaan pää- tai pienempään versioon (kuten v3.3.0, v3.3.3.3, 4.x.x.. jne.). Esimerkiksi, kun lisenssisi päättyi, uusin julkaisu oli v4.4.3, ja myöhemmin julkaistiin sekä 4.4.4.4 että 4.5.0-versio, voit käyttää v4.4.X-versiota, mutta et v4.5.X-versiota.", + "WhatHappensWhenLicenseEndsExplanation4": "Et voi asentaa uusia moduuleja ja teemoja, jotka on lisätty ABP Commercial -alustaan lisenssisi päätyttyä.", + "WhatHappensWhenLicenseEndsExplanation5": "Et voi käyttää ABP Suitea.", + "WhatHappensWhenLicenseEndsExplanation6": "Et voi enää saada premium-tukea.", + "WhatHappensWhenLicenseEndsExplanation7": "Voit jatkaa (uusia) lisenssiäsi, jos haluat jatkaa näiden etujen saamista. Jos jatkat lisenssiäsi {3} päivää kuluessa lisenssin vanhenemisesta, seuraavat alennukset sovelletaan: Tiimilisenssi {0}; Toimilupa {1}; Yrityslisenssi {2}.", + "discountForYears": "{0}% de remise pendant {1} an(s)", + "WhatHappensWhenLicenseEndsExplanation8": "Luomiasi ABP-projekteja ei tallenneta palvelimillemme. Siksi on sinun vastuullasi säilyttää lataamasi lähdekoodi. Kun lisenssisi vanhenee, luotua ABP-projektin lähdekoodia ei ole mahdollista saada.", "WhenShouldIRenewMyLicense": "Milloin minun pitäisi uusia lisenssini?", "WhenShouldIRenewMyLicenseExplanation": "Jos uusit lisenssisi 1 kuukauden kuluessa lisenssin vanhenemisesta, seuraavat alennukset sovelletaan: Team License {0} ; Business License {1} ; Enterprise License {2} ; . Jos uusit lisenssisi 1 kuukauden lisenssin päättymispäivän jälkeen, uusimishinta on sama kuin lisenssin ostohinta, eikä uusimisesta saa alennusta.", "TrialPlan": "Onko sinulla kokeilusuunnitelma?", + "TrialPlanExplanation": "Ei, ABP Commercialille ei ole kokeiluversiota. Voit tarkistaa yhteisön versiosta ymmärtääksesi koodin laadun ja lähestymistavat. Tarjoamme myös 30 päivän rahat takaisin -takuun Team-lisenssille ilman kysymyksiä! Voit pyytää hyvitystä ensimmäisten 30 päivän sisällä. Tarjoamme 60 %:n hyvityksen 30 päivän kuluessa Business- ja Enterprise-lisensseistä. Tämä johtuu siitä, että Business- ja Enterprise-lisenssit sisältävät kaikkien moduulien ja teemojen täyden lähdekoodin.", "DoYouAcceptBankWireTransfer": "Hyväksytkö pankkisiirron?", "DoYouAcceptBankWireTransferExplanation": "Kyllä, hyväksymme pankkisiirron.
Kun olet lähettänyt lisenssimaksun pankkisiirrolla, lähetä meille sähköposti osoitteeseen accounting@abp.io kuittisi ja pyydetty lisenssityyppi. Kansainväliset pankkitilitietomme:", "HowToUpgrade": "Kuinka päivittää olemassa olevia sovelluksia, kun uusi versio on saatavilla?", @@ -348,41 +365,463 @@ "WeWillSendYouADownloadLink": "Linkki e-kirjan latausta varten on lähetetty osoitteeseen {0}.
Tarkista postilaatikkosi/roskapostisi/roskapostilaatikot!", "InvalidFormInputs": "Ole hyvä ja kirjoita lomakkeessa ilmoitetut voimassa olevat tiedot.", "DDDBookEmailBody": "Kiitos.
Lataa kirjasi napsauttamalla tätä.", - "FreeDDDEBook": "Ilmainen DDD e-kirja", "StartFree": "Aloita ilmaiseksi", "FreeTrial": "Ilmainen kokeilu", "AcceptsMarketingCommunications": " Kyllä, haluaisin saada ABP Commercial -markkinointiviestintää.", "PurposeOfUsage": "Käytön tarkoitus", - "Industry": "Ala", "Choose": "- Valitse -", "CompanyOrganizationName": "Yrityksen/organisaation nimi", "CompanySize": "Yhtiön koko", "Next": "Seuraava", "StartTrial": "Aloita ilmainen kokeilujaksoni", - "ContactUsIssues": "Ota yhteyttä, jos sinulla on ongelmia", + "ContactUsQuestions": "Ota yhteyttä, jos sinulla on kysyttävää", "TrialActivatedWarning": "Käyttäjällä on oikeus vain yhteen ilmaiseen kokeilujaksoon. Olet jo käyttänyt kokeilujaksosi.", + "ActivationRequirement": "Olet viimeisen askeleen päässä kokeilujakson aloittamisesta.
Tarkistettuasi tietosi aktivoimme lisenssisi. Kun käyttölupasi on aktivoitu, lähetämme sähköpostin osoitteeseen {0}. Älä huoli, tämä prosessi ei vie kauan!", "SaveAndDownload": "Tallenna ja lataa", "CompanyNameValidationMessage": "Yrityksen nimi on liian pitkä!", "AddressValidationMessage": "Osoite on liian pitkä!", "TaxNoValidationMessage": "TAX/ALV-numero on liian pitkä!", "NotesValidationMessage": "Huomautuskenttä on liian pitkä!", "CheckYourBillingInfo": "Voit luoda laskun vain kerran! Tarkista laskutustietosi ennen laskun luomista.", - "Volo.AbpIo.Commercial:030000": "Olet jo käyttänyt kokeilujaksosi.", - "Volo.AbpIo.Commercial:030001": "Tämä organisaation nimi on jo olemassa.", "StartYourFreeTrial": "Aloita ilmainen kokeilujaksosi", "TrialLicenseModelInvalidErrorMessage": "Yksi seuraavista kentistä on virheellinen: maan nimi, yrityksen koko, toimiala tai käyttötarkoitus.", "Trial": "Oikeudenkäynti", "Purchased": "Osti", - "PurchaseLicense": "Osta {0} lisenssi", + "PurchaseNow": "Osta nyt", "PurchaseTrialLicenseMessage": "Lisenssisi viimeinen voimassaolopäivä on {0}.
Jos haluat jatkaa ilmaisen kokeilujakson aikana luomiesi projektien käyttöä, sinun on vaihdettava lisenssiavaimet appsettings.secrets.json-tiedostoissasi. Tässä on lisenssiavaimesi:", "TrialLicenseExpireMessage": "Käytät kokeiluversiota, ja kokeilukäyttölupasi vanhenee {0}.", "TryForFree": "Kokeile ilmaiseksi", "TrialLicenseExpiredInfo": "Kokeilulisenssijaksosi on umpeutunut!", - "CommercialNewsletterConfirmationMessage": "Hyväksyn käyttöehdot ja tietosuojakäytännön .", - "ContinueWithNewOrganization": "Jatka uudessa organisaatiossa", + "DowngradeLicensePlan": "Voinko tulevaisuudessa vaihtaa alempaan lisenssisuunnitelmaan?", + "DowngradeLicensePlanExplanation": "Et voi alentaa olemassa olevaa lisenssisuunnitelmaa. Voit kuitenkin ostaa uuden alemman lisenssisuunnitelman ja jatkaa kehitystyötäsi uudella lisenssillä. Kun olet ostanut alemman lisenssin, sinun tarvitsee vain kirjautua uuteen lisenssisuunnitelmaan ABP CLI -komennolla: ` abp login -o `.", + "LicenseTransfer": "Voiko lisenssin siirtää kehittäjältä toiselle?", + "LicenseTransferExplanation": "Kyllä! Kun ostat lisenssin, sinusta tulee lisenssin haltija, joten sinulla on pääsy organisaation hallintasivulle. Organisaatiolla on omistaja- ja kehittäjäroolit. Omistajat voivat hallita kehittäjäpaikkoja ja määrittää kehittäjiä. Kukin nimetty kehittäjä kirjautuu ABP CLI -komennolla järjestelmään, ja sillä on kehitys- ja tukioikeudet.", + "UserOwnerDescription": "Organisaation 'omistaja' on tämän tilin järjestelmänvalvoja. Hän johtaa organisaatiota ostamalla lisenssejä ja allokoimalla kehittäjiä. 'Omistaja' ei voi kirjoittaa koodia ABP Commercial -projekteihin, ladata ABP-näyteprojekteja eikä esittää kysymyksiä tukisivustolla. Jos haluat tehdä kaikki nämä, sinun on lisättävä itsesi myös kehittäjäksi.", + "UserDeveloperDescription": "'Kehittäjät' voivat kirjoittaa koodia ABP Commercial -projekteihin, ladata ABP-näyteprojekteja ja esittää kysymyksiä tukisivustolla. Toisaalta 'kehittäjät' eivät voi hallita tätä organisaatiota.", + "RemoveCurrentUserFromOrganizationWarningMessage": "Olet poistamassa itsesi omasta organisaatiostasi. Et voi enää hallinnoida tätä organisaatiota, vahvistatko?", + "RenewExistingOrganizationOrCreateNewOneMessage": "Voit uusia organisaatiosi lisenssin napsauttamalla alla olevaa \"Pidennä nyt\" -painiketta, jolloin voit pidentää lisenssin voimassaolopäivää yhdellä vuodella. Jos jatkat maksamista, sinulla on uusi organisaatio. Haluatko jatkaa uudessa organisaatiossa?", + "PurchaseTrialOrganizationOrCreateNewOneMessage": "Sinulla on koekäyttölupa. Voit ostaa kokeiluversion lisenssin napsauttamalla Osta nyt -painiketta. Jos jatkat maksamista, sinulla on uusi organisaatio. Haluatko jatkaa uudessa organisaatiossa?", + "ExtendNow": "Laajenna nyt", + "CreateNewOrganization": "Luo uusi organisaatio", "RenewLicenseEarly": "Jos uusin ajokorttini etuajassa, saanko koko vuoden?", "RenewLicenseEarylExplanation": "Kun uusit lisenssisi ennen lisenssin vanhenemispäivää, lisenssin voimassaolopäivään lisätään 1 vuosi. Jos lisenssisi vanhenee esimerkiksi {0}-06-06 ja uusit sen {0}-01-01, uusi lisenssisi päättymispäivä on {1}-06-06.", - "discountForYears": "{0}% de remise pendant {1} an(s)", - "BlackFridayDiscount": "Black Friday -alennus" + "OpenSourceWebApplication": "Avoimen lähdekoodin verkkosovellus", + "CompleteWebDevelopment": "Täydellinen verkkokehitys", + "ABPFrameworkDescription": "ABP Framework on täydellinen infrastruktuuri nykyaikaisten verkkosovellusten luomiseen noudattamalla ohjelmistokehityksen parhaita käytäntöjä ja käytäntöjä.", + "CommunityDescription": "Jaa kokemuksesi ABP Frameworkista!", + "GetStarted": "Aloita", + "Views": "näkymät", + "LatestPosts": "Uusimmat viestit", + "PreBuiltApplication": "Valmiiksi rakennettu sovellus", + "DatabaseProviders": "Tietokannan tarjoajat", + "UIFrameworks": "UI-kehykset", + "UsefulLinks": "Hyödyllisiä linkkejä", + "Platform": "Alusta", + "CoolestCompaniesUseABPCommercial": "Tyylikkäimmät yritykset käyttävät jo ABP Commercialia.", + "UserInterface": "Käyttöliittymä", + "APIGateway": "API-yhdyskäytävä", + "Microservice": "Mikropalvelu", + "Database": "Tietokanta", + "Architecture": "Arkkitehtuuri", + "MicroserviceArchitectureExplanation": "Tämä on täydellinen ratkaisuarkkitehtuuri, joka koostuu useista sovelluksista, API-yhdyskäytävistä, mikropalveluista ja tietokannoista, jotta voidaan rakentaa skaalautuva mikropalveluratkaisu uusimmalla tekniikalla.", + "BusinessLogic": "Liiketoimintalogiikka", + "DataAccessLayer": "Tietojen käyttökerros", + "Monolith": "Monoliitti", + "ModularArchitectureExplanation": "Tämä käynnistysmalli tarjoaa kerroksellisen, modulaarisen ja DDD-pohjaisen ratkaisuarkkitehtuurin puhtaan ja ylläpidettävän koodikannan luomiseksi.", + "SeeDetails": "Katso yksityiskohdat", + "SeeDocumentation": "Tutustu dokumentaatioon", + "Bs5Compatible": "Bootstrap 5 -yhteensopiva ammattiteema, täydellinen järjestelmänvalvojan verkkosivustollesi.", + "LeptonXTheme": "LeptonX teema", + "LeptonXDark": "LeptonX tumma", + "LeptonXLight": "LeptonX vaalea", + "LeptonXSemiDark": "LeptonX puolitumma", + "BuiltOnBs5Library": "Pohjautuu Bootstrap 5 -kirjastoon", + "FullyCompatibleWithBs5": "100 % yhteensopiva Bootstrap 5:n HTML-rakenteen ja CSS-luokkien kanssa", + "ResponsiveAndMobileCompatible": "Responsiivinen, mobiiliyhteensopiva, RTL-tuki", + "ProvidesStylesForDatatables": "Tarjoaa tyylejä tietotaulukoille", + "MultipleLayoutOptions": "Useita asetteluvaihtoehtoja", + "EasilyInstallAndUpgrade": "Asenna ja päivitä helposti", + "SupportForum": "Tukifoorumi", + "TrustedBy": "Luotettu", + "OurPricing": "Hinnoittelumme", + "Plans": "Suunnitelmat", + "NameSurname": "Nimi sukunimi", + "Unspecified": "Määrittelemätön", + "LicenceType": "Lisenssityyppi", + "LicenseDiscountWarning": "TÄMÄ ALENNUSSIVU KÄYTTÄÄ OLETUSALENNUSKOODIA JA VOLOSOFT-KEHITTÄJILLE. ALLA OLEVAT OSTOLINKIT EIVÄT TOIMI.", + "DiscountedLicenseExplanation": "Nämä lisenssihinnat ovat pienille startup-yrityksille, yksittäisille kehittäjille, opiskelijoille, voittoa tavoittelemattomille järjestöille ja projekteille!", + "General": "Yleiset", + "License": "Lisenssi", + "Development": "Kehitys", + "Payment": "Maksu", + "WatchExplainerVideo": "Tavataan! Katso selittävä video", + "LightDarkAndSemiDarkThemes": "Vaalea, tumma ja puolitumma", + "LeptonXThemeExplanation": "Lepton Theme voi muuttaa teemaasi järjestelmäasetustesi mukaan.", + "PRO": "PRO", + "WelcomeToABPCommercial": "Tervetuloa ABP Commercialiin!", + "YourAccountDetails": "Tilisi tiedot", + "OrganizationName": "Organisaation nimi", + "AddDevelopers": "Lisää kehittäjiä", + "StartDevelopment": "Aloita kehittäminen", + "CreateAndRunApplicationUsingStartupTemplate": "Opi luomaan ja suorittamaan uusi verkkosovellus ABP Commercial -käynnistysmallin avulla.", + "CommunityDescription2": "community.abp.io on paikka, jossa ihmiset voivat jakaa ABP-aiheisia artikkeleita. Etsi artikkeleita, opetusohjelmia, koodinäytteitä, tutkimuksia ja tapaa ihmisiä samalla taajuudella kuin sinä.", + "UseABPSuiteExplanation": "Lataa moduulien ja teemojen lähdekoodi ABP Suiten avulla.", + "ManageModulesWithSuite": "Voit myös hallita ABP-moduulejasi Suiten avulla.", + "LearnHowToInstallSuite": "Opi asentamaan ja käyttämään ABP Suitea.", + "SeeMore": "Katso lisää", + "SeeLess": "Katso Vähemmän", + "LayeredSolutionStructure": "Kerrostettu ratkaisurakenne", + "LayeredSolutionStructureExplanation": "Ratkaisu on kerrostettu Domain Driven Design -periaatteiden ja -mallien perusteella, jotta liiketoimintalogiikkasi voidaan eristää infrastruktuurista ja integraatioista ja maksimoida koodin ylläpidettävyys ja uudelleenkäytettävyys. ABP Framework tarjoaa jo abstraktioita, perusluokkia ja oppaita DDD:n toteuttamiseen sovelluksessasi.", + "MultipleUIOptions": "Useita käyttöliittymävaihtoehtoja", + "MultipleUIOptionsExplanation": "Rakastamme erilaisia tapoja luoda käyttöliittymä. Tämä käynnistysratkaisu tarjoaa kolme erilaista käyttöliittymäkehysvaihtoehtoa yrityssovelluksellesi.", + "MultipleDatabaseOptions": "Useita tietokantavaihtoehtoja", + "MultipleDatabaseOptionsExplanation": "Sinulla on kaksi tietokannan tarjoajavaihtoehtoa (sen lisäksi, että voit käyttää molempia yhdessä sovelluksessa). Käytä Entity Framework Corea työskennelläksesi minkä tahansa relaatiotietokannan kanssa ja käytä valinnaisesti Dapperia, kun sinun on kirjoitettava matalan tason kyselyitä parantaaksesi suorituskykyä. MongoDB on toinen vaihtoehto, jos haluat käyttää dokumenttipohjaista NoSQL-tietokantaa. Vaikka nämä palveluntarjoajat ovat hyvin integroituja, abstrakteja ja esikonfiguroituja, voit itse asiassa olla vuorovaikutuksessa minkä tahansa tietokantajärjestelmän kanssa, jota voit käyttää .NET:n kanssa.", + "ModularArchitectureExplanation2": "Modulaarisuus on ensiluokkainen kansalainen ABP.IO-alustalla. Kaikki sovelluksen toiminnot on jaettu hyvin eristettyihin valinnaisiin moduuleihin. Käynnistysratkaisussa on valmiiksi asennettuna perus ABP Commercial -moduulit. Voit myös luoda omia moduuleita rakentaaksesi modulaarisen järjestelmän omalle sovelluksellesi.", + "MultiTenancyForSaasBusiness": "Monivuokraus SaaS-yrityksellesi", + "MultiTenancyForSaasBusinessExplanation": "ABP Commercial tarjoaa täydellisen, päästä-päähän usean vuokrausjärjestelmän SaaS-järjestelmien (Software-as-a-Service) luomiseen. Sen avulla vuokralaiset voivat jakaa tai käyttää omia tietokantojaan tietokantojen luonti- ja siirtojärjestelmässä.", + "MicroserviceStartupSolution": "Mikropalvelun käynnistysratkaisu", + "MicroserviceArchitectureExplanation2": "Voit hankkia sen seuraavaan mikropalvelujärjestelmääsi hyödyntääksesi valmiiksi rakennetun perusratkaisun ja laadukkaan kokemuksen.", + "PreIntegratedTools": "Esiintegroitu suosittuihin työkaluihin", + "PreIntegratedToolsExplanation": "Ratkaisu on jo integroitu alan standardityökaluihin ja teknologioihin, mutta voit aina muuttaa niitä ja integroida suosikkityökaluihisi.", + "SingleSignOnAuthenticationServer": "Kertakirjautumisen todennuspalvelin", + "SingleSignOnAuthenticationServerExplanation": "Ratkaisussa on todennuspalvelinsovellus, jota muut sovellukset käyttävät kertakirjautumispalvelimena API-käyttöoikeuksien hallintaominaisuuksilla. Se perustuu IdentityServeriin.", + "WebAppsWithGateways": "2 verkkosovellusta kahdella API-yhdyskäytävällä", + "WebAppsWithGatewaysExplanation": "Ratkaisu sisältää kaksi verkkosovellusta, joista jokaisessa on oma API-yhdyskäytävä (BFF - Backend For Frontend -malli).", + "BackOfficeApplication": "Back Office -sovellus", + "BackOfficeApplicationExplanation": "Järjestelmäsi todellinen verkkosovellus, jossa on useita käyttöliittymäkehysvaihtoehtoja. Voit luoda minkä tahansa yrityssovelluksen.", + "LandingWebsite": "Julkinen sivusto", + "LandingWebsiteExplanation": "Yleinen etusivu/julkinen verkkosivusto, jota voidaan käyttää useisiin tarkoituksiin, kuten yrityksesi esittelyyn, tuotteiden myymiseen jne.", + "ABPFrameworkEBook": "Mastering ABP Framework e-kirja", + "MasteringAbpFrameworkEBookDescription": "Sisältyy ABP Commercial -lisenssiisi", + "FullName": "Koko nimi", + "LicenseTypeNotCorrect": "Lisenssityyppi ei ole oikea!", + "Trainings": "Koulutukset", + "ChooseTrainingPlaceholder": "Valitse koulutus...", + "DoYouNeedTrainings": "Tarvitsetko jotain näistä koulutuksista?", + "DoYouNeedTraining": "Tarvitsetko {0} koulutusta?", + "GetInTouchUs": "Ota yhteyttä meihin", + "ForMoreInformationClickHere": "Saat lisätietoja napsauttamalla tätä.", + "IsGetOnboardingTraining": "Haluaisitko perehdytys- ja verkkosovelluskehityskoulutukseen?", + "OnboardingWebApplicationDevelopmentTrainingMessage": "Voit ajoittaa koulutuskalenterisi ottamalla yhteyttä osoitteeseen {0} organisaation luomisen jälkeen", + "CustomPurchaseMessage": "Ota meihin yhteyttä napsauttamalla {0} seuraavaa vaihetta varten.", + "Note": "Huomautus", + "AdditionalNote": "Lisähuomautus", + "OnboardingTrainingFaqTitle": "Onko teillä ABP onboarding -koulutusta?", + "OnboardingTrainingFaqExplanation": "Kyllä, meillä on ABP-koulutuspalvelut, jotka auttavat sinua saamaan ABP-projektisi käyntiin nopeasti. Opit ABP:stä ABP:n ydintiimin jäseneltä ja saat valmiudet aloittaa ABP-projektisi. Perehdytyskoulutuksessa kerromme kuinka perustat kehitysympäristösi, asennat tarvittavat työkalut ja luot täysin toimivan CRUD-sivun. Koulutus toteutetaan livenä ja Zoom-sovellusta käytetään ja olemme avoimia muiden online-kokousalustojen käyttöön. Koulutuksen kieli on englanti. Voit myös esittää kysymyksiäsi ABP:stä istuntojen aikana. Molemmille osapuolille suunnitellaan sopiva aika ja päivämäärä. Saat lisätietoja ottamalla yhteyttä meihin osoitteessa info@abp.io.", + "AddBasket": "Lisää ostoskoriin", + "SendTrainingRequest": "Lähetä koulutuspyyntö", + "OnlyEnglishVersionOfThisDocumentIsTheRecentAndValid": "* Tämän asiakirjan englanninkielinen versio on ajan tasalla ja englanninkielinen versio toimii ensisijaisena kaikissa riita-asioissa.", + "Pricing_Page_Title": "Suunnitelmat ja hinnoittelu", + "Pricing_Page_Description": "Valitse yrityksesi tarvitsemat ominaisuudet ja toiminnot tänään. Osta ABP Commercial -lisenssi ja luo rajattomasti projekteja.", + "Pricing_Page_HurryUp": "Kiirehdi!", + "Pricing_Page_BuyLicense": "Osta lisenssi 2021 hinnoilla 16. tammikuuta asti!", + "Pricing_Page_ValidForExistingCustomers": "Koskee myös nykyisiä asiakkaita ja lisenssien uusimista.", + "Pricing_Page_Hint1": "Lisenssihinta sisältää tietyn määrän kehittäjäpaikkoja. Jos sinulla on enemmän kehittäjiä, voit aina ostaa lisää paikkoja.", + "Pricing_Page_Hint2": "Voit ostaa lisää kehittäjälisenssejä nyt tai tulevaisuudessa. Lisenssit ovat paikkaperusteisia, joten voit siirtää paikan kehittäjältä toiselle.", + "Pricing_Page_Hint3": "Voit kehittää rajoittamattoman määrän erilaisia tuotteita lisenssilläsi.", + "Pricing_Page_Hint4": "ABP Suite on työkalu, joka auttaa kehitystäsi parantamaan tuottavuuttasi. Se tukee CRUD-sivujen luomista ja uusien projektien luomista.", + "Pricing_Page_Hint5": "Voit käyttää kaikkia valmiita moduuleja sovelluksissasi.", + "Pricing_Page_Hint6": "Voit käyttää kaikkia valmiita teemoja sovelluksissasi.", + "Pricing_Page_Hint7": "Käynnistysmalli on Visual Studio -ratkaisu, jonka avulla pääset alkuun projektissasi. Kaikki perusmoduulit on lisätty ja valmiiksi määritetty sinua varten.", + "Pricing_Page_Hint8": "Mastering ABP Framework -e-kirja selittää, kuinka .NET-ratkaisuja toteutetaan parhaiden käytäntöjen avulla. Sitä myydään Amazon.com-sivustolla ja voit ladata kirjan ilmaiseksi lisenssisi puitteissa.", + "Pricing_Page_Hint9": "Voit ladata minkä tahansa moduulin lähdekoodin. Voit halutessasi lisätä lähdekoodin ratkaisuusi tehdäksesi radikaaleja muutoksia tai säilyttää sen itsellesi turvallisuussyistä.", + "Pricing_Page_Hint10": "Lisenssit ovat elinikäisiä. Tämä tarkoittaa, että voit jatkaa sovelluksesi kehittämistä ikuisesti. Uusimman version käyttö ja tuen saaminen myönnetään lisenssijakson sisällä (1 vuosi, ellet uusi sitä).", + "Pricing_Page_Hint11": "Ei rajoituksia käyttöönotolle! Voit ottaa käyttöön niin monelle palvelimelle kuin haluat, mukaan lukien pilvipalvelut tai paikan päällä.", + "Pricing_Page_Hint12": "Voit päivittää moduulit, teemat ja työkalut uusimpaan versioon aktiivisen lisenssijaksosi aikana. Kun lisenssisi vanhenee, sinun on uusittava se, jotta voit jatkaa päivitysten saamista virheenkorjauksista, uusista ominaisuuksista ja parannuksista.", + "Pricing_Page_Hint13": "Voit saada premium-tuen vuodeksi (voit uusia lisenssin jatkaaksesi sitä).", + "Pricing_Page_Hint14": "Team- ja Business-lisensseillä on tapausten/kysymysten määräraja. Jos ostat lisää kehittäjälisenssejä, tapahtumarajasi kasvaa {0} (Tiimilisenssi) tai {1} (Business License) kehittäjää kohden.", + "Pricing_Page_Hint15": "Vain Enterprise License sisältää yksityisen tuen. Voit lähettää sähköpostia suoraan ABP-tiimille tai esittää kysymyksiä osoitteessa support.abp.io yksityisellä lippuvaihtoehdolla. Yksityiset liput eivät ole yleisön nähtävissä.", + "Pricing_Page_Hint16": "Voit ladata kaikkien ABP-teemojen lähdekoodin. Voit halutessasi lisätä lähdekoodin ratkaisuusi tehdäksesi radikaaleja muutoksia tai säilyttää sen itsellesi turvallisuussyistä.", + "Pricing_Page_Testimonial_1": "ABP Commercial antoi SC Venturesille mahdollisuuden toimittaa pankkitason usean vuokralaisen siilotietokanta SaaS-alustan yhdeksässä kuukaudessa tukemaan myyntisaamisten / ostovelkojen toimitusketjun rahoitusta merkittävien arvolaskujen kautta useilta integroiduilta ankkureilta. ABP:n modulaarisuus mahdollisti sen, että tiimi toimitti ennätysajassa, läpäisi kaiken VAPT:n ja ottaa käyttöön konttimuotoisen mikropalvelupinon täyden CI/CD:n ja putkien kautta tuotantoon.", + "Pricing_Page_Testimonial_2": "Näemme ABP Commercialin käytön arvon mukautettujen kehitysprojektien yleiskustannusten vähentämiseen. Ja tiimi pystyy yhdistämään koodimallin eri projektivirroissa. Näemme viitekehyksessä enemmän mahdollisuuksia rakentaa uusia ominaisuuksia nopeammin kuin ennen. Luotamme, että näemme jatkuvasti ABP Commercialin hyödyntämisen arvon.", + "Pricing_Page_Testimonial_3": "Rakastamme ABP:tä. Meidän ei tarvitse kirjoittaa kaikkea tyhjästä. Aloitamme valmiista ominaisuuksista ja keskitymme vain siihen, mitä todella tarvitsemme kirjoittaa. Lisäksi ABP on hyvin suunniteltu ja koodi on korkealaatuista ja siinä on vähemmän bugeja. Jos joutuisimme kirjoittamaan kaiken tarvitsemamme itse, joudumme ehkä viettämään vuosia. Jälleen kerran pidämme siitä, että uusi versio, ongelmankorjaus tai parannus ilmestyy hyvin pian joka toinen viikko. Emme odota liian kauan.", + "Pricing_Page_Testimonial_4": "ABP Commercial on loistava tuote, jota suosittelen. Kaupalliset tuotteet markkinoille asiakkaillemme yhdellä konfiguroitavalla alustalla. Kehyksen ja työkalujen tarjoama aloitus jokaiselle joukkueelle on jokaisen sentin arvoinen. ABP Commercial sopi parhaiten tarpeisiimme.", + "Pricing_Page_Testimonial_5": "ABP Framework ei ole vain viitekehys, vaan se on myös opas projektin kehittämiseen/hallintaan, koska se tarjoaa DDD-, GenericRepository-, DI-, Microservice- ja Modularity-koulutusta. Vaikka et itse käyttäisikään kehystä, voit kehittää itseäsi docs.abp.io:lla, joka on hyvin ja ammattimaisesti valmisteltu (OpenIddict, Redis, Quartz jne.). Koska monet asiat on rakennettu valmiiksi, se lyhentää projektin kehitysaikaa merkittävästi (kuten kirjautumissivu, poikkeusten käsittely, tietojen suodatus, kylvö, tarkastusloki, lokalisointi, automaattinen API-ohjain jne.). Esimerkkinä sovelluksestamme olen käyttänyt paikallista tapahtumaväylää varastonhallintaan. Pystyn siis hallitsemaan tilausliikkeitä kirjoittamalla varastokäsittelijäksi. On hienoa olla hukkaamatta aikaa CreationTimelle, CreatorId:lle. Ne täytetään automaattisesti.", + "Pricing_Page_Testimonial_6": "ABP Framework on hyvä kehys, mutta sen käyttämien eri kerrosten, luokkien ja kirjastojen (erityisesti ABP:n) ymmärtäminen vaatii aikaa. Käytin paljon aikaa koodikannan lukemiseen, mutta ABP Commercial säästää aikaa projektin erityiskokonaisuuksien (AR) ja kuhunkin niistä linkitetyn arkiston luomiseen. Pidin myös ABP:ssä käytetystä lähestymistavasta, joka on hyvin kypsä, sillä se perustuu DDD:hen ja monoliittisuuteen.", + "AbpBookDownloadArea_ClaimYourEBook": "Lunasta Mastering ABP Framework -e-kirja", + "AddMemberModal_Warning_1": "Jos käyttäjätunnusta, jota yrität lisätä, ei ole järjestelmässä, pyydä tiimisi jäsentä rekisteröitymään osoitteessa {0} ja jakaa hänen tilinsä käyttäjätunnus kanssasi.", + "MyOrganizations_Detail_WelcomeMessage": "Tervetuloa organisaatioosi, {0}", + "MyOrganizations_Detail_OrganizationManagement": "Organisaation hallinta", + "OrganizationDisplayName": "Organisaation näyttönimi", + "MyOrganizations_Detail_EditDisplayName": "Muokkaa näyttönimeä", + "MyOrganizations_Detail_UpgradeYourLicense": "Päivitä lisenssisi", + "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_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?", + "MyOrganizations_Detail_PricePerYear": "{0} / vuosi", + "MyOrganizations_Detail_PurchaseDeveloperSeats": "Osta kehittäjäistuimet", + "Invoices": "Laskut", + "RequestInvoice": "Pyydä lasku", + "OrderNumber": "Tilausnumero", + "Date": "Päivämäärä", + "Products": "Tuotteet", + "TotalPrice": "Kokonaishinta", + "ThereIsNoInvoice": "Ei ole laskua", + "MyOrganizations_Detail_PaymentProviderInfo": "Jos olet ostanut käyttöluvan {0}-yhdyskäytävän kautta, se lähettää PDF-laskun sähköpostiosoitteeseesi, katso {0}-laskutus. ", + "MyOrganizations_Detail_PayUInfo": "Jos olet ostanut PayU-yhdyskäytävän kautta, napsauta \"Pyydä lasku\" -painiketta ja täytä laskutustiedot.", + "MyOrganizations_Detail_ConclusionInfo": "Laskupyyntösi saatetaan päätökseen {0} arkipäivän kuluessa.", + "ExtendYourLicense": "Laajenna {0}-lisenssiäsi", + "Continue": "Jatka", + "PurchaseLicense": "Osta {0} lisenssi", + "DownloadInvoiceModal_DownloadInvoice": "Lataa lasku", + "DownloadInvoiceModal_SaveInformationOnlyOnce": "Voit tallentaa laskutustietosi vain kerran.", + "InvoiceModal_EnterCompanyName": "Anna yrityksesi virallinen nimi...", + "InvoiceModal_EnterCompanyAddress": "Anna laillinen yrityksesi osoite...", + "InvoiceModal_EnterTaxNumber": "Anna vero-/alv-numerosi, jos se on saatavilla...", + "RequestInvoiceModal_EnterNotes": "Kirjoita lisäviestisi laskustasi...", + "PrePayment_PayWithIyzico": "Maksat Iyzicolla", + "ContinueToCheckout": "Jatka Checkoutiin", + "PrePayment_IyzicoRedirectionInfo": "Sinut ohjataan Iyzico Payment Gatewaylle viimeistelemään ostoksesi turvallisesti.", + "PrePayment_IyzicoAcceptVisaAndMasterCard": "Iyzico hyväksyy Visa- ja MasterCard-kortit.", + "Purchase": "Osta", + "AcceptTermsAndConditions": "Olen lukenut, ymmärtänyt ja hyväksyn tietosuojakäytännön, käyttöehdot ja EULA:n.", + "AcceptTermsAndConditionsWarningMessage": "Hyväksy tietosuojakäytäntö ja ehdot", + "SelectGatewayToContinue": "Valitse yhdyskäytävä jatkaaksesi!", + "GatewaySelection_SelectGateway": "Valitse maksuyhdyskäytävä", + "GatewaySelection_RedirectionMessage": "Seuraavaksi sinut ohjataan tapahtumaa varten valitun maksuyhdyskäytävän verkkosivustolle.", + "PaymentSucceed_PaymentSuccessMessage": "Maksu suoritettu", + "PaymentSucceed_ThanksForPurchase": "Kiitos ostoksestasi!", + "PaymentSucceed_CreateYourOrganization": "Luo organisaatiosi", + "PaymentSucceed_AddMeAsDeveloper": "Olen myös kehittäjä, lisää minut kehittäjäksi organisaatiooni.", + "PaymentSucceed_CreateOrganization": "Luo organisaatio", + "PaymentSucceed_OrganizationDescription": "Organisaatio koostuu kehittäjistä ja omistajista. Kehittäjät ovat käyttäjiä, jotka kirjoittavat koodia ABP-projektiin ja hyötyvät {1}-verkkosivustosta. Omistajat ovat käyttäjiä, jotka jakavat kehittäjäpaikkoja ja hallinnoivat lisensointia.", + "PaymentSucceed_ViewOrganization": "Napsauta tästä nähdäksesi organisaation", + "Purchase_TotalAnnualPrice": "YHTEENSÄ (vuosimaksu)", + "Purchase_TrainingPrice": "Koulutuksen hinta", + "Purchase_OnboardingTraining": "ABP:n perehdytys ja verkkosovelluskehitys live-koulutus", + "TotalDeveloperPrice": "Kehittäjän kokonaishinta", + "Purchase_PricePerDeveloper": "{0} {1} kehittäjää kohden", + "Purchase_IncludedDeveloperInfo": "{0} {1} mukana.", + "Purchase_LicenseExtraDeveloperPurchaseMessage": "{0} lisenssi sisältää {1} kehittäjää. Voit lisätä uusia kehittäjiä nyt tai myöhemmin.", + "StartupTemplates_Page_Title": "Käynnistysmallit", + "StartupTemplates_Page_Description": "ABP Commercialin avulla voit rakentaa minkä tahansa monimutkaisia ratkaisuja. Se tarjoaa kaksi pääasiallista valmiiksi rakennettua käynnistysratkaisua. Voit valita tarpeitasi vastaavan ja rakentaa oman mukautetun ratkaisun sen päälle.", + "MicroserviceStartupSolutionForDotnet": "Mikropalvelu käynnistysmalli .NET:ille", + "MonolithSolutionForDotnet": "Monoliitti (modulaarinen) Ratkaisu .NET:ille", + "TrainingDetailsHeaderInfo_TrainingHour": "{0} tunti(a)", + "Trainings_Content": "Koulutuksen sisältö", + "Trial_Page_StartYourFreeTrial": "Aloita ilmainen kokeilujaksosi", + "TrialLicenseFeatures": "Voit hyötyä kaikista ABP:n kaupallisista ominaisuuksista", + "TrialPeriodDays": "Sinulla on {0} päivän tiimilisenssi", + "TrialForumSupportIncident": "Sinulla on {0} keskustelupalstan tukitapausta", + "Contact_Page_Title": "Ota yhteyttä ABP:n kehitystiimiin", + "Contact_Page_Description": "Ota yhteyttä ABP:n kehitystiimiin, jos tarvitset apua tai kerro ajatuksesi ja mielipiteesi! ABP-tukitiimi on valmis auttamaan.", + "Demo_Page_Title": "Luo demo", + "Demo_Page_Description": "Luo ilmainen demo nähdäksesi esimerkkisovelluksen, joka on luotu käyttämällä ABP Commercial -käynnistysmallia. Älä toista itseäsi yleisten hakemusvaatimusten suhteen.", + "Discounted_Page_Title": "Alennettu hinnoittelu", + "Discounted_Page_Description": "Valitse yrityksesi tänään tarvitsemat ominaisuudet ja toiminnot. Osta ABP Commercial -lisenssi ja luo rajattomasti projekteja", + "Faq_Page_Title": "Usein kysytyt kysymykset (FAQ)", + "Faq_Page_Description": "Onko sinulla kysymyksiä? Hae usein kysyttyjä kysymyksiä tai kysy meiltä yhteydenottolomakkeella.", + "Faq_Page_SwiftCode": "Swift-koodi", + "Faq_Page_BankName": "Pankin nimi", + "Faq_Page_AccountName": "Tilin nimi", + "Faq_Page_AccountNumber": "Tilinumero", + "Faq_Page_Currency": "Valuutta", + "Faq_Page_VatNumber": "ALV-numero", + "Faq_Page_OtherCurrenciesInfo": "Jos haluat lisätietoja muista valuutoista, katso kaikki tilit", + "ModuleDetail_Page_Title": "Moduulin tiedot - {0}", + "ProjectCreatedSuccess_Page_Title": "Projektisi on luotu", + "ProjectCreatedSuccess_Page_Description": "ABP-projektisi luotu onnistuneesti!", + "Suite_Page_Title": "ABP Suite - Luo CRUD-sivuja", + "Suite_Page_Description": "ABP Commercial tarjoaa nopeat sovelluskehitystyökalut kehittäjien tuottavuuden lisäämiseksi. ABP Suiten avulla voit luoda CRUD-sivuja helposti.", + "Themes_Page_Title": "Modernit ja toimivat käyttöliittymäteemat", + "Themes_Page_Description": "ABP Commercial tarjoaa useita ammattimaisia, moderneja käyttöliittymäteemoja. Luo ilmainen demo nähdäksesi nopeasti, miltä käyttöliittymä näyttää.", + "Tools_Page_Title": "Nopeat sovelluskehitystyökalut", + "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", + "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", + "TrialLicensePaymentInfoSection_Description": "Osta käyttölupa: Ostamalla lisenssin saat edelleen premium-tuen. Voit myös saada suurempia tai pieniä päivityksiä moduuleille ja teemoille. Voit jatkaa uusien projektien luomista. Voit edelleen käyttää ABP Suitea, joka nopeuttaa kehitystäsi.
Katso käyttölupien vertailutaulukko, jolla voit tarkistaa lisenssityyppien väliset erot.", + "SelectTargetLicense": "Valitse kohdelisenssi", + "UpgradePaymentInfoSection_ExtendMyLicenseForOneYear": "Kyllä, jatka lisenssini voimassaolopäivää 1 vuodella.", + "UpgradePaymentInfoSection_WantToExtendLicense": "Haluatko jatkaa lisenssiäsi vielä {0} vuodella?", + "UpgradePaymentInfoSection_UpgradingWillNotExtendLicense": "Päivitys ei pidennä lisenssisi vanhenemispäivää!", + "UpgradePaymentInfoSection_LicenseUpgradeDescription": "Päivittämällä lisenssisi ylennät korkeampaan lisenssityyppiin, mikä antaa sinulle lisäetuja. Katso lisenssityyppien väliset erot lisenssivertailutaulukosta.", + "Landing_Page_CustomerStories": "Asiakkaiden tarinoita", + "Landing_Page_OurGreatCustomers": "Hienot asiakkaamme", + "Landing_Page_WebApplicationFramework": "Web Application Framework", + "Landing_Page_WebDevelopmentPlatform": "Web-kehitysalusta", + "Landing_Page_CompleteWebDevelopmentPlatform": "Täydellinen Web-kehitysalusta", + "Landing_Page_TryFreeDemo": "Kokeile ilmaista demoa", + "Landing_Page_StartingPointForWebApplications": "Lähtökohta ASP.NET Core -pohjaisille verkkosovelluksille! Se perustuu parhaan verkkokehityksen ABP-kehykseen.", + "Landing_Page_AbpProvidesSoftwareInfrastructure": "ABP Framework tarjoaa ohjelmistoinfrastruktuurin erinomaisten verkkosovellusten kehittämiseen parhaiden käytäntöjen kanssa.", + "Landing_Page_MicroserviceCompatibleArchitecture": "Microservice-yhteensopiva arkkitehtuuri", + "Landing_Page_PreBuiltApplicationModulesAndThemes": "Valmiiksi rakennetut sovellusmoduulit ja teemat", + "Landing_Page_MultiTenantArchitecture": "Monivuokraus arkkitehtuuri", + "Landing_Page_MultiTenancyDescription": "SaaS-sovellukset on tehty helpoksi! Integroitu monivuokraus tietokannasta käyttöliittymään.", + "Landing_Page_DDDIntroduction": "Suunniteltu ja kehitetty DDD-mallien ja -periaatteiden perusteella. Tarjoaa kerrostetun mallin sovelluksellesi.", + "Landing_Page_CrossCuttingConcernsInfo": "Täydellinen infrastruktuuri valtuutukseen, validointiin, poikkeusten käsittelyyn, välimuistiin, tarkastuslokiin, tapahtumien hallintaan ja muuhun.", + "Landing_Page_PreBuiltApplicationModules": "Valmiiksi rakennetut sovellusmoduulit, jotka sisältävät yleisimmät verkkosovellusvaatimukset.", + "Landing_Page_ChatModule": "Keskustelut", + "Landing_Page_DocsModule": "Asiakirjat", + "Landing_Page_FileManagementModule": "Tiedostonhallinta", + "Landing_Page_CustomerStory_1": "ABP Commercial antoi SC Venturesille mahdollisuuden toimittaa pankkitason usean vuokralaisen siilotietokanta SaaS-alustan yhdeksässä kuukaudessa tukemaan myyntisaamisten / ostovelkojen toimitusketjun rahoitusta merkittävien arvolaskujen kautta useilta integroiduilta ankkureilta. ABP:n modulaarisuus mahdollisti sen, että tiimi toimitti ennätysajassa, läpäisi kaiken VAPT:n ja siirsi konttipohjaisen mikropalvelupinon täyden CI/CD:n ja putkien kautta tuotantoon.", + "Landing_Page_CustomerStory_2": "Näemme ABP Commercialin käytön arvon mukautettujen kehitysprojektien yleiskustannusten vähentämiseen. Ja tiimi pystyy yhdistämään koodimallin eri projektivirroissa. Näemme viitekehyksessä enemmän mahdollisuuksia rakentaa uusia ominaisuuksia nopeammin kuin ennen. Luotamme, että näemme jatkuvasti ABP Commercialin hyödyntämisen arvon.", + "Landing_Page_CustomerStory_3": "Rakastamme ABP:tä. Meidän ei tarvitse kirjoittaa kaikkea tyhjästä. Aloitamme valmiista ominaisuuksista ja keskitymme vain siihen, mitä todella tarvitsemme kirjoittaa. Lisäksi ABP on hyvin suunniteltu ja koodi on korkealaatuista ja siinä on vähemmän bugeja. Jos joutuisimme kirjoittamaan kaiken tarvitsemamme itse, joudumme ehkä viettämään vuosia. Jälleen kerran pidämme siitä, että uusi versio, ongelmankorjaus tai parannus julkaistaan hyvin pian\n joka toinen viikko. Emme odota liian kauan.", + "Landing_Page_CustomerStory_4": "ABP Commercial on loistava tuote, jota suosittelen. Kaupalliset tuotteet markkinoille asiakkaillemme yhdellä konfiguroitavalla alustalla. Kehyksen ja työkalujen tarjoama aloitus jokaiselle joukkueelle on jokaisen sentin arvoinen. ABP Commercial sopi parhaiten tarpeisiimme.", + "Landing_Page_AdditionalServices": "Mukautettu tai volyymilisenssi, perehdytys, suora koulutus ja tuki, mukautettu projektikehitys, olemassa olevien projektien siirtäminen ja paljon muuta...", + "Landing_Page_IncludedDeveloperLicenses": "Mukana {0} kehittäjälisenssi", + "Landing_Page_SeeOnDemo": "Katso Demosta", + "Landing_Page_LeptonThemes": "Lepton-teemat", + "Landing_Page_AccountModuleDescription_1": "Tämä moduuli toteuttaa sovelluksen todennusjärjestelmän;", + "Landing_Page_AccountModuleDescription_2": "Tarjoaa kirjautumissivun, jossa on käyttäjätunnus ja salasana", + "Landing_Page_AccountModuleDescription_3": "Tarjoaa rekisteröintisivun uuden tilin luomista varten.", + "Landing_Page_AccountModuleDescription_4": "Tarjoaa unohdin salasanan -sivun salasanan palautus -linkin lähettämistä varten sähköpostitse.", + "Landing_Page_AccountModuleDescription_5": "Tarjoaa sähköpostivahvistustoiminnon käyttöliittymän kanssa.", + "Landing_Page_AccountModuleDescription_6": "Toteuttaa kaksivaiheisen todennuksen (tekstiviesti ja sähköposti).", + "Landing_Page_AccountModuleDescription_7": "Toteuttaa käyttäjän lukituksen (lukitsee tilin määritetyksi ajaksi, kun tietty määrä epäonnistuneita kirjautumisia tapahtuu virheellisten tunnistetietojen vuoksi tietyn ajanjakson sisällä).", + "Landing_Page_AccountModuleDescription_8": "Toteuttaa Identity Server -todennuspalvelimen käyttöliittymän ja toiminnot.", + "Landing_Page_AccountModuleDescription_9": "Mahdollistaa vaihtamisen vuokralaisten välillä usean vuokralaisen ympäristössä.", + "Landing_Page_AccountModuleDescription_10": "Mahdollistaa sovelluksen käyttöliittymän kielen muuttamisen.", + "Landing_Page_AuditLoggingModuleDescription_1": "Tämä moduuli tarjoaa tarkastuslokin raportoinnin käyttöliittymän valvontainfrastruktuurille. Mahdollistaa tarkastuslokimerkintöjen ja entiteettimuutoslokien etsimisen, suodattamisen ja näyttämisen.", + "Landing_Page_AuditLoggingModuleDescription_2": "Tarkastuslokikirjaus sisältää tärkeitä tietoja jokaisesta asiakaspyynnöstä:", + "Landing_Page_AuditLoggingModuleDescription_3": "URL, selain, IP-osoite, asiakkaan nimi", + "Landing_Page_AuditLoggingModuleDescription_4": "Käyttäjä", + "Landing_Page_AuditLoggingModuleDescription_5": "HTTP-metodi, HTTP-vastauksen tilakoodi", + "Landing_Page_AuditLoggingModuleDescription_6": "Onnistuminen/epäonnistuminen, poikkeustiedot, jos saatavilla", + "Landing_Page_AuditLoggingModuleDescription_7": "Pyynnön suoritusaika", + "Landing_Page_AuditLoggingModuleDescription_8": "Entiteetit on luotu, poistettu tai päivitetty tässä pyynnössä (muuttunein ominaisuuksin).", + "Landing_Page_BloggingModuleDescription_1": "Tämä moduuli lisää yksinkertaisen blogin ABP-sovellukseesi;", + "Landing_Page_BloggingModuleDescription_2": "Mahdollistaa useiden blogien luomisen yhdessä sovelluksessa.", + "Landing_Page_BloggingModuleDescription_3": "Tukee Markdown-formaattia.", + "Landing_Page_BloggingModuleDescription_4": "Mahdollistaa kommentin kirjoittamisen viestiin.", + "Landing_Page_BloggingModuleDescription_5": "Mahdollistaa tunnisteiden liittämisen blogikirjoituksiin.", + "Landing_Page_BloggingModuleDescription_6": "Katso blog.abp.io-verkkosivusto elävänä esimerkkinä blogimoduulista.", + "Landing_Page_ChatModuleDescription_1": "Tätä moduulia käytetään reaaliaikaiseen viestintään sovelluksen käyttäjien välillä.", + "Landing_Page_ChatModuleDescription_2": "Reaaliaikainen viestintä chat-sivulla.", + "Landing_Page_ChatModuleDescription_3": "Hae käyttäjiltä uusia keskusteluja sovelluksessa.", + "Landing_Page_ChatModuleDescription_4": "Yhteystiedot viimeaikaisista keskusteluista.", + "Landing_Page_ChatModuleDescription_5": "Uusi viesti-ilmoitukset, kun käyttäjä katselee toista sivua.", + "Landing_Page_ChatModuleDescription_6": "Lukemattomien viestien kokonaismäärä -merkki valikkokuvakkeessa.", + "Landing_Page_ChatModuleDescription_7": "Lukemattomien viestien määrä jokaisessa keskustelussa.", + "Landing_Page_ChatModuleDescription_8": "Lazy Load -keskustelut.", + "Landing_Page_DocsModuleDescription_1": "Tätä moduulia käytetään teknisen dokumentaation web-sivustojen luomiseen;", + "Landing_Page_DocsModuleDescription_2": "Sisäänrakennettu GitHub-integraatio: Kirjoita ja hallitse asiakirjoja suoraan GitHubissa.", + "Landing_Page_DocsModuleDescription_3": "Versiointi-tuki integroitu suoraan GitHub-julkaisuihin.", + "Landing_Page_DocsModuleDescription_4": "Tukee monia kieltä (varatuki oletuskielelle).", + "Landing_Page_DocsModuleDescription_5": "Tukee Markdown- ja HTML-formaatteja.", + "Landing_Page_DocsModuleDescription_6": "Tarjoaa navigointi- ja ääriviivat-osion.", + "Landing_Page_DocsModuleDescription_7": "Mahdollistaa useiden projektien dokumentaation yhdessä sovelluksessa.", + "Landing_Page_DocsModuleDescription_8": "Linkit tiedostoon GitHubissa, jotta kuka tahansa voi helposti osallistua klikkaamalla Muokkaa-linkkiä.", + "Landing_Page_DocsModuleDescription_9": "GitHub-lähteen lisäksi mahdollistaa tavallisen kansion käytön dokumentaatiolähteenä.", + "Landing_Page_FileManagementModuleDescription_1": "Lataa, lataa ja järjestä tiedostoja hierarkkisessa kansiorakenteessa.", + "Landing_Page_FileManagementModuleDescription_2": "Tätä moduulia käytetään tiedostojen lataamiseen, lataamiseen ja järjestämiseen hierarkkisessa kansiorakenteessa. Se on myös yhteensopiva usean vuokrauksen kanssa, ja voit määrittää vuokralaisten kokonaiskokorajan.", + "Landing_Page_FileManagementModuleDescription_3": "Tämä moduuli perustuu BLOB-tallennusjärjestelmään, joten se voi käyttää eri tallennuspalveluita tiedoston sisällön tallentamiseen.", + "Landing_Page_IdentityModuleDescription_1": "Tämä moduuli toteuttaa sovelluksen käyttäjä- ja roolijärjestelmän;", + "Landing_Page_IdentityModuleDescription_2": "Luotu käyttäen Microsoftin ASP.NET Core Identity -kirjastoa.", + "Landing_Page_IdentityModuleDescription_3": "Hallinnoi rooleja ja käyttäjiä järjestelmässä. Käyttäjällä voi olla useita rooleja.", + "Landing_Page_IdentityModuleDescription_4": "Aseta käyttöoikeudet rooli- ja käyttäjätasoilla.", + "Landing_Page_IdentityModuleDescription_5": "Ota käyttöön tai poista käytöstä kaksivaihetodennus ja käyttäjän lukitus käyttäjää kohti.", + "Landing_Page_IdentityModuleDescription_6": "Hallinnoi perus käyttäjäprofiilia ja salasanaa.", + "Landing_Page_IdentityModuleDescription_7": "Hallitse vaatimustyyppejä järjestelmässä, aseta vaatimuksia rooleille ja käyttäjille.", + "Landing_Page_IdentityModuleDescription_8": "Asetussivu salasanan monimutkaisuuden, käyttäjän kirjautumisen, tilin ja lukituksen hallintaa varten.", + "Landing_Page_IdentityModuleDescription_9": "Tukee LDAP-todennusta.", + "Landing_Page_IdentityModuleDescription_10": "Tarjoaa sähköpostin ja puhelinnumeron vahvistuksen.", + "Landing_Page_IdentityModuleDescription_11": "Tukee sosiaalisen kirjautumisen integraatioita (Twitter, Facebook, GitHub jne.).", + "Landing_Page_IdentityModuleDescription_12": "Hallinnoi järjestelmän organisaatioyksiköitä.", + "Landing_Page_PaymentModuleDescription_1": "Tarjoaa integroinnin eri maksuyhdyskäytäville.", + "Landing_Page_PaymentModuleDescription_2": "Tämä moduuli integroi maksuyhdyskäytäviä, joten saat helposti maksuja asiakkailtasi.", + "Landing_Page_PaymentModuleDescription_3": "Tämä moduuli tukee seuraavia maksuyhdyskäytäviä", + "Welcome_Page_UseSameCredentialForCommercialWebsites": "Käytä samoja kirjautumistietoja sekä commercial.abp.io- että support.abp.io.", + "WatchCrudPagesVideo": "Katso \"CRUD-sivujen luominen ABP Suiten avulla\" -video!", + "WatchGeneratingFromDatabaseVideo": "Katso \"ABP Suite: CRUD-sivujen luominen olemassa olevista tietokantataulukoista\" -video!", + "WatchTakeCloserLookVideo": "Katso \"Katso tarkemmin koodin sukupolvea: ABP Suite\" -video!", + "ConfirmedEmailAddressRequiredToStartTrial": "Sinulla tulee olla vahvistettu sähköpostiosoite, jotta voit aloittaa kokeilukäyttöoikeuden.", + "EmailVerificationMailNotSent": "Sähköpostivahvistusviestiä ei voitu lähettää.", + "GetConfirmationEmail": "Klikkaa tätä saadaksesi vahvistussähköpostin, jos et ole saanut sitä aiemmin.", + "WhichLicenseTypeYouAreInterestedIn": "Mistä lisenssityypistä olet kiinnostunut?", + "DontTakeOurWordForIt": "Älä luota sanaamme...", + "ReadAbpCommercialUsersWantYouToKnow": "Lue, mitä ABP Commercialin käyttäjät haluavat sinun tietävän", + "Testimonial_ShortDescription_1": "ABP:n modulaarisuus mahdollisti tiimin toimituksen ajoissa.", + "Testimonial_ShortDescription_2": "Rakenna uusia ominaisuuksia nopeammin kuin ennen.", + "Testimonial_ShortDescription_3": "Aloitamme valmiista ominaisuuksista ja keskitymme vain siihen, mitä todella tarvitsee kirjoittaa.", + "Testimonial_ShortDescription_4": "ABP Commercial sopi parhaiten tarpeisiimme.", + "OnlineReviewersOnAbpCommercial": "Online-arvostelut ABP Commercialista", + "SeeWhatToldAboutAbpCommercial": "Katso, mitä ABP Commercialista on kerrottu, ja kirjoita ajatuksesi, jos haluat.", + "BlazoriseLicense": "Pitääkö meidän ostaa Blazorise-lisenssi?", + "BlazoriseLicenseExplanation": "Meillä on Volosoftin ja Megabitin välinen sopimus, jonka mukaan Blazorise-lisenssi on niputettu ABP Commercial -tuotteisiin, joten asiakkaidemme ei tarvitse ostaa ylimääräistä Blazorise-lisenssiä.", + "ExtendPaymentInfoSection_DeveloperPrice": "{0}x lisäkehittäjä(ä)", + "ExtendPaymentInfoSection_DiscountRate": "Alennus {0} %", + "TotalNetPrice": "Nettohinta yhteensä", + "EFCore": "Entity Framework Core", + "All": "Kaikki", + "Mvc": "MVC", + "DataBaseProvider": "Tietojen tarjoaja", + "UIFramework": "UI Framework", + "LeptonXThemeForDashboard": "LeptonX-teema järjestelmänvalvojan hallintapaneelillesi", + "AbpPlatform": "ABP-alusta", + "YouDeserveGoodUXUI": "Ansaitset hyvän käyttöliittymän ja paremman UX:n. ABP:n LeptonX Theme on täällä palvelemassa sitä.", + "ViewLiveDemo": "Katso live-teeman esittely", + "GetLeptonX": "Hanki LeptonX nyt", + "SeeLeptonXDocumentation": "Katso LeptonX-dokumentaatio", + "SimplifiedMenu": "Yksinkertaistettu valikko", + "SimplifiedMenuDescription": "Löydät etsimäsi sivun helposti suodattamalla valikkoa", + "YourFavoritePages": "Suosikkisivusi ulottuvillasi", + "YourFavoritePagesDescription": "Lisää tai poista sivu helposti suosikeista napsauttamalla tähtikuvaketta sivun oikeassa yläkulmassa.", + "BreadCrumbs": "Leivänmurut (Breadcrumbs) saumattomaan sivun vaihtamiseen", + "BreadCrumbsDescription": "Breadcrumbin avulla voit siirtyä samalla tasolla oleville sivuille yhdellä napsautuksella, vaikka vasen valikko olisi suljettu, ja se toimii sekä tabletilla että mobiililaitteella responsiivisesti!", + "YourMenu": "Valikko kuten haluat", + "YourMenuDescription": "Mukauta käyttäjävalikon suoraan napsautettavat kuvakkeet ja avattavat ruudut haluamallasi tavalla. Käyttäjävalikko on täysin muokattavissa tarpeidesi mukaan", + "RtlSupport": "RTL-tuki kielellesi", + "RtlSupportDescription": "LeptonX Theme tukee RTL:ää kielelläsi. Kielivaihtoehdot ovat asetusvalikossa, jotta voit vaihtaa kieltä.", + "YourColors": "Värit hallintapaneelin käyttöliittymässä", + "YourColorsDescription": "LeptonX Theme toimii järjestelmäasetustesi mukaan, ja siinä on kojelaudan vaalea teema, kojelaudan tumma teema ja kojelaudan puolitumma teema.", + "ArrangeContentWidth": "Järjestä sisällön leveys helposti", + "ArrangeContentWidthDescription": "Muuta helposti sisältöalueen leveyttä.", + "LeptonXCompatibleWith": "LeptonX-teema on yhteensopiva", + "MobileResponsiveTemplate": "Mobiiliresponsiivinen malli", + "MobileResponsiveTemplateDescription1": "Käytä LeptonX-hallintapaneelia miltä tahansa haluamaltasi laitteelta.", + "MobileResponsiveTemplateDescription2": "Se on suunniteltu käytettäväksi helposti kaikissa laitteissasi. Se on responsiivinen mobiililaitteissa ja tablet-koossa.", + "TopMenuLayoutOption": "Ylävalikon asetteluvaihtoehto", + "TopMenuLayoutOptionDescription1": "Jos haluat määrittää verkkosivustollesi saman järjestelmänvalvojan hallintapaneelin, voit tehdä sen LeptonX-teemalla!", + "TopMenuLayoutOptionDescription2": "Kokeile vain LeptonX:n ylävalikkoasettelua, jotta se tapahtuu!", + "EasilyCustomizable": "Helposti muokattavissa brändisi väreihin", + "EasilyCustomizableDescription1": "Voit mukauttaa LeptonX-teemaa vain muutamalla SCSS-muuttujalla. Ei ohittamista, ei ylimääräistä CSS-kuormaa!", + "EasilyCustomizableDescription2": "LeptonX:n avulla voit järjestää järjestelmänvalvojan kojelautasi haluamallasi tavalla.", + "IndependentLayout": "Itsenäinen ulkoasu ja sisältöalue", + "IndependentLayoutDescription1": "LeptonX:n asetteluinfrastruktuuri suunniteltiin täysin erillään sisällöstä.", + "IndependentLayoutDescription2": "Tämä tarkoittaa, että voit vapaasti suunnitella projektisi muulla sisältörakenteella kuin Bootstrapilla, jos haluat.", + "MostUsedLibraries": "Useimmat käytetyt LeptonX:ään integroidut kirjastot", + "MostUsedLibrariesDescription1": "LeptonX sisältää eniten käytetyt kirjastosi. Sen avulla voit käyttää vaivattomasti kirjastoja, kuten ApexCharts, DataTables, DropZone, FullCalender, JSTree, Select2, Toast.", + "MostUsedLibrariesDescription2": "LeptonX tukee myös MVC Angular- ja Blazor-spesifisiä kirjastoja.", + "CreateAndCustomize": "Luo ja mukauta tarvitsemasi sivut sekunneissa LeptonX mukautetuilla sivuilla", + "CreateAndCustomizeDescription": "Käyttämällä LeptonX-teemaa sinulla on myös pääsy monille valmiiksi tehdyille html-sivuille. Näitä ovat monet sivut, kuten kirjautumissivu, blogi, UKK, tilausluettelo, lasku, hinnoittelu, tiedostojen hallinta.", + "LeptonThemeForAdmin": "Lepton-teema järjestelmänvalvojan hallintapaneelillesi", + "LeptonThemeForAdminDescription": "Lepton-teema on edelleen saatavilla ja sitä ylläpidetään. Jos haluat siirtyä LeptonX-teemaan Lepton-teeman käyttäjänä, voit katsoa ohjeista ohjeita.", + "LeptonCompatibleWith": "Lepton-teema on yhteensopiva", + "BlackFridayDiscount": "Black Friday -alennus", + "UpgradePaymentInfoSection_DeveloperPrice": "{0} {1} lisäkehittäjälle", + "Upgrade": "Päivitä", + "Renewal": "Uusiminen", + "UpgradePaymentInfoSection_LicensePrice": "{0} lisenssi", + "UpgradePaymentInfoSection_LicenseRenewalPrice": "Lisenssin uusiminen", + "Total": "Kaikki yhteensä", + "SupportPolicyFaqTitle": "Mikä on tukipolitiikkanne?", + "SupportPolicyFaqExplanation": "Tuemme vain aktiivista ja edellistä pääversiota. Emme takaa korjausjulkaisua 3. ja vanhemmille pääversioille. Jos aktiivinen versio on esimerkiksi 7.0.0, julkaisemme korjaustiedostoja sekä versioista 6.x.x että 7.x.x. Lisäksi tarjoamme tukea vain ABP Frameworkiin ja ABP Commercialiin liittyville ongelmille. Tämä tarkoittaa, että tukea ei anneta kolmannen osapuolen sovelluksille, pilvipalveluille ja muille ABP-tuotteiden käyttämille oheiskirjastoille. Käytämme kaupallisesti kohtuullisia keinoja tarjotaksemme asiakkaillemme teknistä tukea \"Volosoft Bilisim A.S\"-yhtiön virallisina työaikoina. Toisaalta emme sitoudu palvelutasosopimuksen (SLA) mukaiseen vastausaikaan, mutta pyrimme vastaamaan teknisiin ongelmiin mahdollisimman nopeasti virallisten työaikojemme puitteissa. Ellei asiakkaan kanssa ole tehty erityistä sopimusta, tarjoamme tukea vain osoitteessa https://support.abp.io. Meillä on myös yksityinen sähköpostituki, joka on vain Enterprise-lisenssin haltijoiden käytettävissä.", + "TotalDevelopers": "Yhteensä {0} kehittäjää", + "CustomPurchaseExplanation": "Räätälöity sinun tarpeidesi mukaan", + "WhereDidYouHearAboutUs": "Mistä kuulit meistä?", + "Twitter": "Twitter", + "Facebook": "Facebook", + "Youtube": "YouTube", + "Google": "Google", + "Github": "GitHub", + "Friend": " Ystävältä", + "Other": "Muu", + "WhereDidYouHearAboutUs_explain": "Täsmennä ...", + "DeletingMemberWarningMessage": "\"{0}\" poistetaan kehittäjäluettelosta. Jos haluat, voit määrittää tämän tyhjän paikan myöhemmin toiselle kehittäjälle.", + "AdditionalInfo": "Jos kehittäjäistuimet ylittävät vaatimukset, voit vähentää niitä. Voit poistaa joitain kehittäjäpaikkojasi lähettämällä sähköpostia osoitteeseen info@abp.io. Käyttämättömien kehittäjäpaikkojen tyhjentäminen vähentää lisenssin uusimiskustannuksia. Voit halutessasi ostaa uudelleen lisää kehittäjäpaikkoja aktiivisen lisenssijaksosi aikana. Huomaa, että koska tässä lisenssipaketissa on {0} kehittäjää, et voi vähentää tätä määrää.", + "LinkExpiredErrorMessage": "Linkki, jota yrität käyttää, on vanhentunut.", + "ExpirationDate": "Viimeinen käyttöpäivä", + "SpringCampaignDiscount": "Kevään kampanja-alennus", + "WhyUseAbpIoPlatform": "Miksi minun pitäisi käyttää ABP.IO-alustaa sen sijaan, että luon uuden ratkaisun tyhjästä?", + "WhyUseAbpIoPlatformFaqExplanation": "Katso kyseisestä asiakirjasta yksityiskohtainen selitys siitä, miksi ABP.IO Platformin käyttäminen on huomattavasti edullisempaa kuin kaiken tekeminen itse." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json index 786485ae48..0588062ad8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Puis-je changer les développeurs enregistrés de mon organisation à l'avenir?", "ChangingDevelopersExplanation": "En plus d'ajouter de nouveaux développeurs à votre licence, vous pouvez également modifier les développeurs existants (vous pouvez supprimer un développeur et en ajouter un nouveau sur le même siège) sans aucun coût supplémentaire.", "WhenShouldIRenewMyLicense": "Quand dois-je renouveler ma licence?", - "WhenShouldIRenewMyLicenseExplanation": "Si vous renouvelez votre licence dans 1 mois après l'expiration de votre licence, les remises suivantes seront appliquées : licence d'équipe {0} ; licence commerciale {1} ; licence d'entreprise {2}. Toutefois, si vous renouveler votre licence après 1 mois depuis la date d'expiration de votre licence, le prix de renouvellement sera le même que le prix d'achat de la licence et il n'y aura pas de remise sur votre renouvellement.", + "WhenShouldIRenewMyLicenseExplanation": "Si vous renouvelez votre licence dans {3} jours après l'expiration de votre licence, les remises suivantes seront appliquées : licence d'équipe {0} ; licence commerciale {1} ; licence d'entreprise {2}. Toutefois, si vous renouveler votre licence après {3} jours depuis la date d'expiration de votre licence, le prix de renouvellement sera le même que le prix d'achat de la licence et il n'y aura pas de remise sur votre renouvellement.", "TrialPlan": "Avez-vous un plan d'essai?", "DoYouAcceptBankWireTransfer": "Acceptez-vous les virements bancaires?", "DoYouAcceptBankWireTransferExplanation": "Oui, nous acceptons les virements bancaires.
Après avoir envoyé les frais de licence par virement bancaire, envoyez-nous par e-mail à accounting@abp.io votre reçu et le type de licence demandé. Nos coordonnées bancaires internationales :", @@ -383,6 +383,24 @@ "RenewLicenseEarly": "Si je renouvelle ma licence plus tôt, obtiendrai-je l'année complète ?", "RenewLicenseEarylExplanation": "Lorsque vous renouvelez votre licence avant la date d'expiration de votre licence, 1 an sera ajouté à la date d'expiration de votre licence. Par exemple, si votre licence expire le {0}-06-06 et que vous la renouvelez le {0}-01-01, la nouvelle date d'expiration de votre licence sera le {1}-06-06.", "discountForYears": "{0} % de remise pendentif {1} an(s)", - "BlackFridayDiscount": "Remise Black Friday" + "BlackFridayDiscount": "Remise Black Friday", + "OnboardingTrainingFaqTitle": "Avez-vous une formation d'accueil ABP ?", + "OnboardingTrainingFaqExplanation": "Oui, nous avons des services de formation ABP pour vous aider à démarrer rapidement votre projet ABP. Vous en apprendrez plus sur l'ABP auprès d'un membre de l'équipe principale d'ABP et vous acquerrez les compétences nécessaires pour commencer votre projet ABP. Dans la formation d'intégration, nous vous expliquerons comment configurer votre environnement de développement, installer les outils requis, créer une page CRUD entièrement fonctionnelle. La formation sera en direct et l'application Zoom sera utilisée, et nous sommes ouverts à l'utilisation d'autres plateformes de réunion en ligne. La langue de la formation sera l'anglais. Vous pouvez également poser vos questions sur l'ABP pendant les séances. Une heure et une date convenables seront prévues pour les deux parties. Pour obtenir plus d'informations, contactez-nous à info@abp.io.", + "SupportPolicyFaqTitle": "Quelle est votre politique de soutien ?", + "SupportPolicyFaqExplanation": "Nous ne prenons en charge que la version active et la version majeure précédente. Nous ne garantissons pas la publication d'un correctif pour la troisième version majeure et la version majeure antérieure. Par exemple, si la version active est 7.0.0, nous publierons des correctifs pour les versions 6.x.x et 7.x.x. En outre, nous n'assurons le support que pour les problèmes liés à ABP Framework et ABP Commercial. Cela signifie qu'aucun support n'est fourni pour les applications tierces, les services cloud et les autres bibliothèques périphériques utilisées par les produits ABP. Nous ferons des efforts commercialement raisonnables pour fournir à nos clients une assistance technique pendant les heures de bureau officielles de \"Volosoft Bilisim A.S\". D'autre part, nous ne nous engageons pas à respecter un accord de niveau de service (SLA) sur le temps de réponse, mais nous essaierons de répondre aux problèmes techniques aussi rapidement que possible pendant nos heures de travail officielles. Sauf accord spécial avec le client, nous ne fournissons une assistance qu'à l'adresse https://support.abp.io. Nous disposons également d'une assistance privée par courrier électronique, qui n'est accessible qu'aux détenteurs d'une licence d'entreprise.", + "DowngradeLicensePlan": "Puis-je passer à un plan de licence inférieur à l'avenir ?", + "DowngradeLicensePlanExplanation": "Vous ne pouvez pas rétrograder votre plan de licence existant. Mais vous pouvez acheter un nouveau plan de licence inférieur et continuer votre développement sur la nouvelle licence. Après avoir acheté une licence inférieure, il vous suffit de vous connecter à votre nouveau plan de licence via la commande CLI d'ABP : ` abp login -o `.", + "LicenseTransfer": "Une licence peut-elle être transférée d'un développeur à un autre ?", + "LicenseTransferExplanation": "Oui ! Lorsque vous achetez une licence, vous en devenez le détenteur et vous avez donc accès à la page de gestion de l'organisation. Une organisation a des rôles de propriétaire et de développeur. Les propriétaires peuvent gérer les sièges des développeurs et leur assigner des développeurs. Chaque développeur assigné se connectera au système via la commande ABP CLI et disposera d'autorisations de développement et de support.", + "WhatHappensWhenLicenseEnds": "Que se passe-t-il à la fin de la période de validité de ma licence ?", + "WhatHappensWhenLicenseEndsExplanation1": "La licence commerciale ABP est une licence perpétuelle. Après l'expiration de votre licence, vous pouvez continuer à développer votre projet. Vous n'êtes pas obligé de renouveler votre licence. Votre licence est livrée avec un plan de mise à jour et d'assistance d'un an. Pour continuer à bénéficier des nouvelles fonctionnalités, des améliorations de performance, des corrections de bogues, de l'assistance et continuer à utiliser ABP Suite, vous devez renouveler votre licence. Lorsque votre licence expire ;", + "WhatHappensWhenLicenseEndsExplanation2": "Vous ne pouvez pas créer de nouvelles solutions à l'aide d'ABP Commercial, mais vous pouvez continuer à développer vos applications existantes pour toujours.", + "WhatHappensWhenLicenseEndsExplanation3": "Vous pourrez obtenir des mises à jour pour les modules et thèmes de votre version MINOR (à l'exception des versions RC ou Preview). Par exemple : si vous utilisez la version 3.2.0 d'un module, vous pouvez toujours obtenir des mises à jour pour la version 3.2.x (v3.2.1, v3.2.5... etc.) de ce module. Mais vous ne pouvez pas obtenir de mises à jour pour la prochaine version majeure ou mineure (comme v3.3.0, v3.3.3, 4.x.x.. etc.). Par exemple, lorsque votre licence a expiré, la dernière version était la v4.4.3, et plus tard, la version 4.4.4 et la version 4.5.0 ont été publiées, vous pourrez accéder à la v4.4.X mais vous ne pourrez pas accéder à la v4.5.X.", + "WhatHappensWhenLicenseEndsExplanation4": "Vous ne pouvez pas installer les nouveaux modules et thèmes ajoutés à la plateforme ABP Commercial après l'expiration de votre licence.", + "WhatHappensWhenLicenseEndsExplanation5": "Vous ne pouvez pas utiliser la suite ABP.", + "WhatHappensWhenLicenseEndsExplanation6": "Vous ne pouvez plus bénéficier du support premium.", + "WhatHappensWhenLicenseEndsExplanation7": "Vous pouvez prolonger (renouveler) votre licence si vous souhaitez continuer à bénéficier de ces avantages. Si vous prolongez votre licence dans {3} jours après l'expiration de votre licence, les remises suivantes seront appliquées : Licence d'équipe {0} ; Licence commerciale {1} ; Licence Entreprise {2}.", + "BlazoriseLicense": "Faut-il acheter une licence Blazorise ?", + "BlazoriseLicenseExplanation": "Nous avons conclu un accord entre Volosoft et Megabit, dans le cadre duquel la licence Blazorise est intégrée aux produits ABP Commercial, de sorte que nos clients n'ont pas besoin d'acheter une licence Blazorise supplémentaire." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json index 1d420c4202..2d16ac121d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "क्या मैं भविष्य में अपने संगठन के पंजीकृत डेवलपर्स को बदल सकता हूं?", "ChangingDevelopersExplanation": "अपने लाइसेंस में नए डेवलपर्स को जोड़ने के अलावा, आप मौजूदा डेवलपर्स को भी बदल सकते हैं (आप एक डेवलपर को हटा सकते हैं और एक ही सीट पर एक नया जोड़ सकते हैं) बिना किसी अतिरिक्त लागत के।", "WhenShouldIRenewMyLicense": "मुझे अपना लाइसेंस कब नवीनीकृत करना चाहिए?", - "WhenShouldIRenewMyLicenseExplanation": "यदि आप अपने लाइसेंस की समय सीमा समाप्त होने के बाद 1 महीने के भीतर अपना लाइसेंस नवीनीकृत करते हैं, तो निम्नलिखित छूटें लागू होंगी: टीम लाइसेंस {0} ; व्यवसाय लाइसेंस {1} ; एंटरप्राइज़ लाइसेंस {2} . यदि आप अपने लाइसेंस की समाप्ति तिथि के बाद 1 महीने अपने लाइसेंस का नवीनीकरण करते हैं, तो नवीनीकरण मूल्य लाइसेंस खरीद मूल्य के समान होगा और आपके नवीनीकरण पर कोई छूट नहीं होगी।", + "WhenShouldIRenewMyLicenseExplanation": "यदि आप अपने लाइसेंस की समय सीमा समाप्त होने के बाद {3} दिन के भीतर अपना लाइसेंस नवीनीकृत करते हैं, तो निम्नलिखित छूटें लागू होंगी: टीम लाइसेंस {0} ; व्यवसाय लाइसेंस {1} ; एंटरप्राइज़ लाइसेंस {2} . यदि आप अपने लाइसेंस की समाप्ति तिथि के बाद {3} दिन अपने लाइसेंस का नवीनीकरण करते हैं, तो नवीनीकरण मूल्य लाइसेंस खरीद मूल्य के समान होगा और आपके नवीनीकरण पर कोई छूट नहीं होगी।", "TrialPlan": "क्या आपके पास एक परीक्षण योजना है?", "DoYouAcceptBankWireTransfer": "क्या आप बैंक वायर ट्रांसफर स्वीकार करते हैं?", "DoYouAcceptBankWireTransferExplanation": "हां, हम बैंक वायर ट्रांसफर स्वीकार करते हैं।
बैंक हस्तांतरण के माध्यम से लाइसेंस शुल्क भेजने के बाद, हमें अपनी रसीद और अनुरोधित लाइसेंस के प्रकार accounting@abp.io पर ईमेल करें। हमारे अंतरराष्ट्रीय बैंक खाते की जानकारी:", @@ -381,5 +381,25 @@ "CommercialNewsletterConfirmationMessage": "मैं नियम और शर्तों और गोपनीयता नीति से सहमत हूं .", "discountForYears": "{1}वर्ष(वर्षों) के लिए {0}% छूट", "BlackFridayDiscount": "ब्लैक फ्राइडे छूट", + "OnboardingTrainingFaqTitle": "क्या आपके पास एबीपी ऑनबोर्डिंग प्रशिक्षण है?", + "OnboardingTrainingFaqExplanation": "हां, आपके एबीपी प्रोजेक्ट को तेजी से शुरू करने में आपकी मदद करने के लिए हमारे पास एबीपी प्रशिक्षण सेवाएं हैं। आप ABP कोर टीम के सदस्य से ABP के बारे में जानेंगे और आपको अपना ABP प्रोजेक्ट शुरू करने का कौशल प्राप्त होगा। ऑनबोर्डिंग प्रशिक्षण में, हम समझाएंगे कि अपने विकास के माहौल को कैसे स्थापित करें, आवश्यक उपकरण कैसे स्थापित करें, पूरी तरह कार्यात्मक CRUD पेज कैसे बनाएं। प्रशिक्षण लाइव होगा और जूम एप्लिकेशन का उपयोग किया जाएगा, और हम अन्य ऑनलाइन मीटिंग प्लेटफॉर्म का उपयोग करने के लिए तैयार हैं। प्रशिक्षण की भाषा अंग्रेजी होगी। आप सत्रों के दौरान ABP के बारे में अपने प्रश्न भी पूछ सकते हैं। दोनों पक्षों के लिए एक सुविधाजनक समय और तारीख की योजना बनाई जाएगी। अधिक जानकारी प्राप्त करने के लिए, info@abp.io पर हमसे संपर्क करें।", + "SupportPolicyFaqTitle": "आपकी समर्थन नीति क्या है?", + "SupportPolicyFaqExplanation": "हम केवल सक्रिय और पिछले प्रमुख संस्करण का समर्थन करते हैं। हम तीसरे और पुराने प्रमुख संस्करणों के लिए पैच रिलीज़ की गारंटी नहीं देते हैं। उदाहरण के लिए, यदि सक्रिय संस्करण 7.0.0 है, तो हम 6.x.x और 7.x.x दोनों के लिए पैच रिलीज़ जारी करेंगे। इसके अलावा, हम केवल ABP फ्रेमवर्क और ABP कमर्शियल संबंधित मुद्दों के लिए समर्थन प्रदान करते हैं। इसका मतलब है कि तीसरे पक्ष के अनुप्रयोगों, क्लाउड सेवाओं और एबीपी उत्पादों द्वारा उपयोग किए जाने वाले अन्य परिधीय पुस्तकालयों के लिए कोई समर्थन नहीं दिया गया है। हम अपने ग्राहकों को \"Volosoft Bilisim A.S\" के आधिकारिक व्यावसायिक घंटों के दौरान तकनीकी सहायता प्रदान करने के लिए व्यावसायिक रूप से उचित प्रयासों का उपयोग करेंगे। दूसरी ओर, हम सर्विस-लेवल एग्रीमेंट (SLA) प्रतिक्रिया समय के लिए प्रतिबद्ध नहीं हैं, लेकिन हम अपने आधिकारिक कामकाजी घंटों के भीतर जितनी जल्दी हो सके तकनीकी मुद्दों पर प्रतिक्रिया देने का प्रयास करेंगे। जब तक ग्राहक के साथ कोई विशेष समझौता नहीं किया जाता है, हम केवल https://support.abp.io पर सहायता प्रदान करते हैं। हमारे पास निजी ईमेल समर्थन भी है, जो केवल एंटरप्राइज़ लाइसेंस धारकों के लिए उपलब्ध है।", + "DowngradeLicensePlan": "क्या मैं भविष्य में कम लाइसेंस योजना में डाउनग्रेड कर सकता हूँ?", + "DowngradeLicensePlanExplanation": "आप अपनी मौजूदा लाइसेंस योजना को डाउनग्रेड नहीं कर सकते। लेकिन आप नया लोअर लाइसेंस प्लान खरीद सकते हैं और नए लाइसेंस पर अपना विकास जारी रख सकते हैं। आपके द्वारा कम लाइसेंस खरीदने के बाद, आपको एबीपी सीएलआई कमांड के माध्यम से अपनी नई लाइसेंस योजना में प्रवेश करने की आवश्यकता है: `एबीपी लॉगिन <उपयोगकर्ता नाम> -ओ <संगठन>`।", + "LicenseTransfer": "क्या लाइसेंस एक डेवलपर से दूसरे डेवलपर को ट्रांसफर किया जा सकता है?", + "LicenseTransferExplanation": "हाँ! जब आप लाइसेंस खरीदते हैं, तो आप लाइसेंस धारक बन जाते हैं, इसलिए आपके पास संगठन प्रबंधन पृष्ठ तक पहुंच होगी। एक संगठन में मालिक और डेवलपर की भूमिकाएँ होती हैं। मालिक डेवलपर सीटों का प्रबंधन कर सकते हैं और डेवलपर्स को असाइन कर सकते हैं। प्रत्येक असाइन किया गया डेवलपर सिस्टम में ABP CLI कमांड के माध्यम से लॉगिन करेगा और उसके पास विकास और समर्थन अनुमतियाँ होंगी।", + "RenewLicenseEarly": "अगर मैं अपना लाइसेंस जल्दी रिन्यू करता हूं, तो क्या मुझे पूरा साल मिलेगा?", + "RenewLicenseEarylExplanation": "जब आप अपनी लाइसेंस समाप्ति तिथि से पहले अपने लाइसेंस का नवीनीकरण करते हैं, तो आपकी लाइसेंस समाप्ति तिथि में 1 वर्ष जोड़ दिया जाएगा। उदाहरण के लिए, यदि आपका लाइसेंस {0}-06-06 को समाप्त हो रहा है और आप इसे {0}-01-01 को नवीनीकृत करते हैं, तो आपकी नई लाइसेंस समाप्ति तिथि {1}-06-06 होगी।", + "WhatHappensWhenLicenseEnds": "मेरी लाइसेंस अवधि समाप्त होने पर क्या होता है?", + "WhatHappensWhenLicenseEndsExplanation1": "ABP वाणिज्यिक लाइसेंस एक स्थायी लाइसेंस है। आपका लाइसेंस समाप्त होने के बाद, आप अपना प्रोजेक्ट विकसित करना जारी रख सकते हैं। और आप अपने लाइसेंस को नवीनीकृत करने के लिए बाध्य नहीं हैं। आपका लाइसेंस एक साल के अपडेट और आउट ऑफ बॉक्स सपोर्ट प्लान के साथ आता है। नई सुविधाएँ, प्रदर्शन संवर्द्धन, बग फिक्स, समर्थन और ABP सूट का उपयोग जारी रखने के लिए, आपको अपने लाइसेंस को नवीनीकृत करने की आवश्यकता है। जब आपका लाइसेंस समाप्त हो जाता है;", + "WhatHappensWhenLicenseEndsExplanation2": "आप ABP कमर्शियल का उपयोग करके नए समाधान नहीं बना सकते, लेकिन आप अपने मौजूदा एप्लिकेशन को हमेशा के लिए विकसित करना जारी रख सकते हैं।", + "WhatHappensWhenLicenseEndsExplanation3": "आप अपने लघु संस्करण (आरसी या पूर्वावलोकन संस्करणों को छोड़कर) के भीतर मॉड्यूल और थीम के लिए अपडेट प्राप्त करने में सक्षम होंगे। उदाहरण के लिए: यदि आप किसी मॉड्यूल के v3.2.0 का उपयोग कर रहे हैं, तब भी आप उस मॉड्यूल के v3.2.x (v3.2.1, v3.2.5... आदि) के लिए अपडेट प्राप्त कर सकते हैं। लेकिन आप अगले प्रमुख या लघु संस्करण (जैसे v3.3.0, v3.3.3, 4.x.x.. आदि) के लिए अपडेट प्राप्त नहीं कर सकते। उदाहरण के लिए, जब आपका लाइसेंस समाप्त हो गया था, तो नवीनतम रिलीज़ v4.4.3 थी, और बाद में, इसने 4.4.4 संस्करण और 4.5.0 संस्करण दोनों को प्रकाशित किया, आप v4.4.X का उपयोग करने में सक्षम होंगे, लेकिन आप नहीं होंगे v4.5.X तक पहुंचें।", + "WhatHappensWhenLicenseEndsExplanation4": "आपका लाइसेंस समाप्त होने के बाद आप ABP कमर्शियल प्लेटफॉर्म में जोड़े गए नए मॉड्यूल और थीम इंस्टॉल नहीं कर सकते।", + "WhatHappensWhenLicenseEndsExplanation5": "आप एबीपी सूट का उपयोग नहीं कर सकते।", + "WhatHappensWhenLicenseEndsExplanation6": "अब आप प्रीमियम समर्थन प्राप्त नहीं कर सकते।", + "WhatHappensWhenLicenseEndsExplanation7": "यदि आप इन लाभों को प्राप्त करना जारी रखना चाहते हैं तो आप अपने लाइसेंस का विस्तार (नवीनीकरण) कर सकते हैं। यदि आप अपना लाइसेंस समाप्त होने के बाद {3} दिन के भीतर अपना लाइसेंस बढ़ाते हैं, तो निम्नलिखित छूट लागू होंगी: टीम लाइसेंस {0}; व्यवसाय लाइसेंस {1}; उद्यम लाइसेंस {2}।", + "BlazoriseLicense": "क्या हमें ब्लेज़ोराइज़ लाइसेंस खरीदने की ज़रूरत है?", + "BlazoriseLicenseExplanation": "हमारे पास Volosoft और Megabit के बीच एक समझौता है, इस समझौते के साथ Blazorise लाइसेंस को ABP वाणिज्यिक उत्पादों के साथ बंडल किया गया है, इसलिए हमारे ग्राहकों को एक अतिरिक्त Blazorise लाइसेंस खरीदने की आवश्यकता नहीं है।" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json index b144988670..9df49a3b0a 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json @@ -160,7 +160,7 @@ "SearchQuestionPlaceholder": "Keressen a gyakran ismételt kérdések között", "WhatIsTheABPCommercial": "Mi az az ABP Commercial?", "WhatAreDifferencesThanAbpFramework": "Mi a különbség a nyílt forráskódú ABP Framework és az ABP Commercial között?", - "AbpCommercialMetaTitle": "ABP Commercial – Teljes webfejlesztési platform: {0} | ABP Commercial", + "AbpCommercialMetaTitle": "{0} | ABP Commercial", "AbpCommercialMetaDescription": "Az ABP Commercial a nyílt forráskódú ABP keretrendszerre épülő előre beépített alkalmazásmodulok, gyorsfejlesztő eszközök, UI témák és szolgáltatások készlete.", "ABPCommercialExplanation": "Az ABP Commercial prémium modulok, eszközök, témák és szolgáltatások készlete a nyílt forráskódú ABP keretrendszerre épül fel. Az ABP Commercial-t ugyanaz a csapat fejleszti és támogatja az ABP keretrendszer mögött.", "WhatAreDifferencesThanABPFrameworkExplanation": "

Az ABP-keretrendszer egy moduláris, tematikus, mikroszolgáltatásokkal kompatibilis alkalmazásfejlesztési keretrendszer az ASP.NET Core számára. Teljes architektúrát és erős infrastruktúrát biztosít ahhoz, hogy a saját üzleti kódjára összpontosítson, ahelyett, hogy megismételné magát minden új projektnél. A szoftverfejlesztés bevált gyakorlatain és a már ismert népszerű eszközökön alapul.

Az ABP keretrendszer teljesen ingyenes, nyílt forráskódú és közösségvezérelt. Ingyenes témát és néhány előre beépített modult is biztosít (pl. személyazonosság-kezelés és bérlőkezelés).

", @@ -206,9 +206,9 @@ "discountForYears": "{0}% kedvezmény {1} évre", "WhatHappensWhenLicenseEndsExplanation8": "Az Ön által generált ABP projekteket nem tároljuk a szervereinken. Ezért az Ön felelőssége a letöltött forráskód megőrzése. Amikor a licensze lejár, nincs mód a generált ABP projekt forráskódjának lekérésére.", "WhenShouldIRenewMyLicense": "Mikor kell megújítanom a jogosítványomat?", - "WhenShouldIRenewMyLicenseExplanation": "Ha a licenc lejártát követő 1 hónapon belül megújítja a licencet, a következő kedvezmények érvényesek: Csapatlicenc {0}; Üzleti engedély {1}; Vállalati licenc {2}. Ha azonban a licenc lejárati dátuma óta 1 hónap után megújítja a licencet, a megújítási ár megegyezik a licenc vásárlási árával, és nem jár kedvezmény a megújításra.", + "WhenShouldIRenewMyLicenseExplanation": "Ha a licenc lejártát követő {3} nap megújítja a licencet, a következő kedvezmények érvényesek: Csapatlicenc {0}; Üzleti engedély {1}; Vállalati licenc {2}. Ha azonban a licenc lejárati dátuma óta 1 hónap után megújítja a licencet, a megújítási ár megegyezik a licenc vásárlási árával, és nem jár kedvezmény a megújításra.", "TrialPlan": "Van próbaterv?", - "TrialPlanExplanation": "14 napos próbaidővel rendelkezik az ABP Commercial csapat licenszéhez. További információért látogasson el ide . Továbbá a Team licenszekre 30 napos pénz-visszafizetési garanciát biztosítunk. Az első 30 napban csak visszatérítést kérhet. A Business és Enterprise licenszek esetén 30 napon belül 60%-os visszatérítést biztosítunk. Ennek az az oka, hogy a Business és Enterprise licenszek tartalmazzák az összes modul és téma teljes forráskódját.", + "TrialPlanExplanation": "Nem, az ABP Commercialhoz nincs próbaverzió. Tekintse meg a közösségi kiadást, hogy megértse a kód minőségét és megközelítéseit. A Team licencre 30 napos pénz-visszafizetési garanciát is vállalunk, kérdés nélkül! Az első 30 napon belül kérheti a visszatérítést. Üzleti és vállalati licencek esetén 60% visszatérítést biztosítunk 30 napon belül. Ennek az az oka, hogy a Business és Enterprise licencek tartalmazzák az összes modul és téma teljes forráskódját.", "DoYouAcceptBankWireTransfer": "Elfogadja a banki átutalást?", "DoYouAcceptBankWireTransferExplanation": "Igen, elfogadunk banki átutalást.
Miután banki átutalással elküldte a licencdíjat, küldje el nekünk e-mailben az accounting@abp.io címre nyugtát és a kért engedély típusát. Nemzetközi bankszámlánk információi:", "HowToUpgrade": "Hogyan lehet frissíteni a meglévő alkalmazásokat, ha új verzió érhető el?", @@ -538,6 +538,7 @@ "Pricing_Page_Testimonial_3": "Szeretjük az ABP-t. Nem kell mindent a nulláról írnunk. A beépített funkciókból indulunk ki, és csak arra koncentrálunk, amit valóban meg kell írnunk. Ezenkívül az ABP jól felépített, és a kód kiváló minőségű, kevesebb hibával. Ha magunknak kellene megírnunk mindent, amire szükségünk van, akkor lehet, hogy éveket kellene töltenünk. Még egyszer, amit szeretünk, az az, hogy az új verzió, a hibajavítás vagy a fejlesztés nagyon hamar, minden második héten megjelenik. Nem várunk túl sokáig.", "Pricing_Page_Testimonial_4": "Az ABP Commercial egy fantasztikus termék, amelyet ajánlunk. Kereskedelmi termékek, amelyeket ügyfeleink számára egyetlen konfigurálható platformon értékesíthetnek. Az ugrásszerű indítás, amelyet a keret és az eszközök biztosítanak bármely csapat számára, minden centet megér. Az ABP Commercial volt a legjobban megfelelő az igényeinknek.", "Pricing_Page_Testimonial_5": "Az ABP Framework nem csak keretrendszer, hanem útmutató is a projektfejlesztéshez/menedzsmenthez, mert DDD, GenericRepository, DI, Microservice és Modularity képzést biztosít. Ha magát a keretrendszert nem is használja, fejlesztheti magát a docs.abp.io-val, amely jól és professzionálisan elkészített (OpenIddict, Redis, Quartz stb.) leírás. Mivel sok minden előre be van építve, jelentősen lerövidíti a projektfejlesztési időt (például bejelentkezési oldal, kivételkezelés, adatszűrés, aéapadatok, audit naplózás, lokalizáció, automatikus API vezérlő stb.). Alkalmazásunkból példaként a Helyi Event Bus-t használtam az állomány karbantartására. Így a rendelési mozgásokat eseményekkel tudom a készlethez igazítani. Csodálatos, hogy nem veszítünk időt a CreationTime-ra, a CreatorId-re. Automatikusan feltöltődnek.", + "Pricing_Page_Testimonial_6": "Az ABP Framework egy jó keretrendszer, de időre van szükség a különböző rétegek, osztályok és könyvtárak (különösen az ABP) megértéséhez. Sok időt töltöttem a kódbázis elolvasásával, de az ABP Commercial időt takarít meg nekünk a projekt speciális entitások (AR) és a mindegyikhez kapcsolódó tároló létrehozására. Tetszett az ABP-ben használt megközelítés is nagyon érett, tudjuk, hogy a DDD-n és a monoliton alapul.", "AbpBookDownloadArea_ClaimYourEBook": "Igényelje Mastering ABP Framework e-könyvét", "AddMemberModal_Warning_1": "Ha a hozzáadni kívánt felhasználónév nem létezik a rendszerben, kérje meg csapattagját, hogy regisztráljon a (z) {0} webhelyen, és ossza meg fiókja felhasználónevét Önnel.", "MyOrganizations_Detail_WelcomeMessage": "Üdvözöljük szervezetében, {0}", @@ -623,7 +624,6 @@ "Faq_Page_Currency": "Valuta", "Faq_Page_VatNumber": "Adószám", "Faq_Page_OtherCurrenciesInfo": "A többi pénznemhez lásd az összes fiókot", - "ModuleDetail_Page_Title": "Modul részletei – {0}", "ProjectCreatedSuccess_Page_Title": "A projekt létrehozva", "ProjectCreatedSuccess_Page_Description": "ABP projektje sikeresen létrejött!", "Suite_Page_Title": "ABP Suite – CRUD oldalak létrehozása", @@ -750,4 +750,4 @@ "TotalNetPrice": "Total Net Price", "BlackFridayDiscount": "Black Friday Kedvezmény" } -} +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json index 7e5c856f4e..ff0c6cc417 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Get ég breytt skráðum forriturum fyrirtækisins míns í framtíðinni?", "ChangingDevelopersExplanation": "Til viðbótar við að bæta nýjum verktaka við leyfi þitt geturðu einnig breytt núverandi forriturum (þú getur fjarlægt verktaka og bætt nýjum við) án aukakostnaðar.", "WhenShouldIRenewMyLicense": "Hvenær ætti ég að endurnýja leyfið mitt?", - "WhenShouldIRenewMyLicenseExplanation": "Ef þú endurnýjar leyfið þitt innan eins mánaðar eftir að leyfið þitt rennur út verða eftirfarandi afslættir notaðir: Team Leyfi {0}% afsláttur, Business License {1}% afsláttur, Enterprise License {2}% afsláttur . Ef þú endurnýjar leyfið þitt 1 mánuði eftir að leyfið rennur út, verður endurnýjunarverðið það sama og kaupverð leyfisins og enginn afsláttur af endurnýjun þinni.", + "WhenShouldIRenewMyLicenseExplanation": "Ef þú endurnýjar leyfið þitt innan {3} dagar eftir að leyfið þitt rennur út verða eftirfarandi afslættir notaðir: Team Leyfi {0}% afsláttur, Business License {1}% afsláttur, Enterprise License {2}% afsláttur . Ef þú endurnýjar leyfið þitt {3} dagar eftir að leyfið rennur út, verður endurnýjunarverðið það sama og kaupverð leyfisins og enginn afsláttur af endurnýjun þinni.", "TrialPlan": "Ertu með prufuáætlun?", "DoYouAcceptBankWireTransfer": "Samþykki þið bankamillifærslu?", "DoYouAcceptBankWireTransferExplanation": "Já, við tökum við bankamillifærslu.
Eftir að hafa sent leyfisgjaldið með millifærslu skaltu senda okkur tölvupóst á accounting@abp.io kvittun þína og tegund leyfis sem óskað er eftir. Upplýsingar um alþjóðlega bankareikninginn okkar:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json index 76637fee4b..ccd74fd005 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Posso cambiare gli sviluppatori registrati della mia organizzazione in futuro?", "ChangingDevelopersExplanation": "Oltre ad aggiungere nuovi sviluppatori alla tua licenza, puoi anche Modifica gli sviluppatori esistenti (puoi rimuovere uno sviluppatore e aggiungerne uno nuovo alla stessa postazione) senza alcun costo aggiuntivo.", "WhenShouldIRenewMyLicense": "Quando devo rinnovare la mia licenza?", - "WhenShouldIRenewMyLicenseExplanation": "Se rinnovi la licenza entro 1 mese dopo la scadenza della licenza, verranno applicati i seguenti sconti: Licenza Team {0} ; Licenza Business {1} ; Licenza Enterprise {2} . Se rinnovi la licenza 1 mese dopo la data di scadenza della licenza, il prezzo di rinnovo sarà lo stesso del prezzo di acquisto della licenza e non ci saranno sconti sul rinnovo.", + "WhenShouldIRenewMyLicenseExplanation": "Se rinnovi la licenza entro {3} giorni dopo la scadenza della licenza, verranno applicati i seguenti sconti: Licenza Team {0} ; Licenza Business {1} ; Licenza Enterprise {2} . Se rinnovi la licenza {3} giorni dopo la data di scadenza della licenza, il prezzo di rinnovo sarà lo stesso del prezzo di acquisto della licenza e non ci saranno sconti sul rinnovo.", "TrialPlan": "Hai un piano di prova?", "DoYouAcceptBankWireTransfer": "Accettate bonifici bancari?", "DoYouAcceptBankWireTransferExplanation": "Sì, accettiamo bonifico bancario.
Dopo aver inviato il canone tramite bonifico bancario, inviaci un'e-mail a accounting@abp.io con la ricevuta e il tipo di licenza richiesta. Le nostre informazioni sul conto bancario internazionale:", @@ -380,6 +380,26 @@ "TrialLicenseExpiredInfo": "Il periodo della tua licenza di prova è scaduto!", "CommercialNewsletterConfirmationMessage": "Accetto i Termini e condizioni e la Informativa sulla privacy .", "discountForYears": "{0}% di sconto per {1} anno/i", - "BlackFridayDiscount": "Sconto Black Friday" + "BlackFridayDiscount": "Sconto Black Friday", + "OnboardingTrainingFaqTitle": "Avete un corso di formazione ABP per l'onboarding?", + "OnboardingTrainingFaqExplanation": "Sì, abbiamo i servizi di formazione ABP per aiutarti a far partire rapidamente il tuo progetto ABP. Imparerai a conoscere ABP da un membro del core team ABP e otterrai le competenze per iniziare il tuo progetto ABP. Nella formazione onboarding, spiegheremo come configurare il tuo ambiente di sviluppo, installare gli strumenti richiesti, creare una pagina CRUD completamente funzionante. La formazione sarà in diretta e verrà utilizzata l'applicazione Zoom e siamo aperti all'utilizzo di altre piattaforme di riunioni online. La lingua della formazione sarà l'inglese. Puoi anche porre le tue domande sull'ABP durante le sessioni. Verrà pianificata una data e un orario convenienti per entrambe le parti. Per ulteriori informazioni, contattaci all'indirizzo info@abp.io.", + "SupportPolicyFaqTitle": "Qual è la vostra politica di assistenza?", + "SupportPolicyFaqExplanation": "Supportiamo solo la versione principale attiva e quella precedente. Non garantiamo il rilascio di patch per la terza e la precedente versione principale. Ad esempio, se la versione attiva è la 7.0.0, rilasceremo patch sia per la 6.x.x che per la 7.x.x. Inoltre, forniamo supporto solo per i problemi relativi ad ABP Framework e ABP Commercial. Ciò significa che non viene fornito alcun supporto per le applicazioni di terze parti, i servizi cloud e altre librerie periferiche utilizzate dai prodotti ABP. Faremo tutto il possibile per fornire ai nostri clienti assistenza tecnica durante gli orari di lavoro ufficiali di Volosoft Bilisim A.S.. D'altra parte, non ci impegniamo a rispettare i tempi di risposta di un accordo sul livello di servizio (SLA), ma cercheremo di rispondere ai problemi tecnici il più rapidamente possibile entro i nostri orari di lavoro ufficiali. A meno che non venga stipulato un accordo speciale con il cliente, forniamo assistenza solo all'indirizzo https://support.abp.io. Disponiamo anche di un supporto privato via e-mail, disponibile solo per i titolari di licenza Enterprise.", + "DowngradeLicensePlan": "Posso passare a un piano di licenza inferiore in futuro?", + "DowngradeLicensePlanExplanation": "Non è possibile effettuare il downgrade del piano di licenza esistente. È però possibile acquistare un nuovo piano di licenza inferiore e continuare lo sviluppo con la nuova licenza. Dopo aver acquistato una licenza inferiore, è sufficiente effettuare il login al nuovo piano di licenza tramite il comando ABP CLI: abp login -o `.", + "LicenseTransfer": "È possibile trasferire una licenza da uno sviluppatore a un altro?", + "LicenseTransferExplanation": "Sì! Quando si acquista una licenza, si diventa il titolare della licenza e quindi si ha accesso alla pagina di gestione dell'organizzazione. Un'organizzazione ha ruoli di proprietario e di sviluppatore. I proprietari possono gestire i posti di sviluppatore e assegnare gli sviluppatori. Ogni sviluppatore assegnato accederà al sistema tramite il comando ABP CLI e avrà i permessi di sviluppo e di assistenza.", + "RenewLicenseEarly": "Se rinnovo la mia licenza in anticipo, avrò l'intero anno?", + "RenewLicenseEarylExplanation": "Quando si rinnova la licenza prima della data di scadenza, viene aggiunto 1 anno alla data di scadenza della licenza. Ad esempio, se la licenza scade il {0}-06-06 e viene rinnovata il {0}-01-01, la nuova data di scadenza della licenza sarà {1}-06-06.", + "WhatHappensWhenLicenseEnds": "Cosa succede quando termina il periodo di licenza?", + "WhatHappensWhenLicenseEndsExplanation1": "La licenza commerciale ABP è una licenza perpetua. Dopo la scadenza della licenza, potete continuare a sviluppare il vostro progetto. Non siete obbligati a rinnovare la licenza. La licenza viene fornita con un piano di aggiornamento e supporto di un anno. Per continuare a ottenere nuove funzionalità, miglioramenti delle prestazioni, correzioni di bug, supporto e continuare a utilizzare ABP Suite, è necessario rinnovare la licenza. Quando la licenza scade;", + "WhatHappensWhenLicenseEndsExplanation2": "Non è possibile creare nuove soluzioni utilizzando ABP Commercial, ma è possibile continuare a sviluppare le applicazioni esistenti per sempre.", + "WhatHappensWhenLicenseEndsExplanation3": "Sarà possibile ottenere gli aggiornamenti per i moduli e i temi della propria versione MINOR (ad eccezione delle versioni RC o Preview). Ad esempio, se si utilizza la versione 3.2.0 di un modulo, è ancora possibile ottenere gli aggiornamenti per la versione 3.2.x (v3.2.1, v3.2.5... ecc.) di quel modulo. Ma non è possibile ottenere aggiornamenti per la versione maggiore o minore successiva (come v3.3.0, v3.3.3, 4.x.x... ecc.). Ad esempio, quando la vostra licenza è scaduta, l'ultima release era la v4.4.3 e in seguito sono state pubblicate sia la versione 4.4.4 che la versione 4.5.0, sarete in grado di accedere alla v4.4.X ma non alla v4.5.X.", + "WhatHappensWhenLicenseEndsExplanation4": "Non è possibile installare nuovi moduli e temi aggiunti alla piattaforma ABP Commercial dopo la scadenza della licenza.", + "WhatHappensWhenLicenseEndsExplanation5": "Non è possibile utilizzare la suite ABP.", + "WhatHappensWhenLicenseEndsExplanation6": "Non è più possibile ottenere il supporto premium.", + "WhatHappensWhenLicenseEndsExplanation7": "Puoi estendere (rinnovare) la tua licenza se desideri continuare a ottenere questi vantaggi. Se estendi la licenza entro {3} giorni dalla scadenza della licenza, verranno applicati i seguenti sconti: Licenza Team {0}; Licenza commerciale {1}; Licenza aziendale {2}.", + "BlazoriseLicense": "Dobbiamo acquistare la licenza di Blazorise?", + "BlazoriseLicenseExplanation": "Abbiamo un accordo tra Volosoft e Megabit, con il quale la licenza di Blazorise viene fornita in bundle con i prodotti commerciali ABP, pertanto i nostri clienti non hanno bisogno di acquistare una licenza Blazorise aggiuntiva." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json index b2c2caec7f..cc7a076848 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Kan ik de geregistreerde ontwikkelaars van mijn organisatie in de toekomst wijzigen?", "ChangingDevelopersExplanation": "Naast het toevoegen van nieuwe ontwikkelaars aan uw licentie, kunt u ook de bestaande ontwikkelaars wijzigen (u kunt een ontwikkelaar verwijderen en een nieuwe toevoegen aan dezelfde stoel) zonder extra kosten.", "WhenShouldIRenewMyLicense": "Wanneer moet ik mijn licentie verlengen?", - "WhenShouldIRenewMyLicenseExplanation": "Als u uw licentie verlengt binnen 1 maand nadat uw licentie is verlopen, worden de volgende kortingen toegepast: Teamlicentie {0}% korting, Zakelijke licentie {1}% korting, Enterprise-licentie {2}% korting . Als u uw licentie 1 maand na de vervaldatum van uw licentie verlengt, is de verlengingsprijs gelijk aan de aankoopprijs van de licentie en wordt er geen korting op uw verlenging gegeven.", + "WhenShouldIRenewMyLicenseExplanation": "Als u uw licentie verlengt binnen {3} dagen nadat uw licentie is verlopen, worden de volgende kortingen toegepast: Teamlicentie {0}% korting, Zakelijke licentie {1}% korting, Enterprise-licentie {2}% korting . Als u uw licentie {3} dagen na de vervaldatum van uw licentie verlengt, is de verlengingsprijs gelijk aan de aankoopprijs van de licentie en wordt er geen korting op uw verlenging gegeven.", "TrialPlan": "Heb je een proefplan?", "DoYouAcceptBankWireTransfer": "Accepteert u bankoverschrijvingen?", "DoYouAcceptBankWireTransferExplanation": "Ja, we accepteren bankoverschrijvingen.
Nadat u de licentievergoeding via bankoverschrijving heeft verzonden, stuurt u een e-mail naar accounting@abp.io met uw kwitantie en het type licentie dat u heeft aangevraagd. Onze internationale bankrekeninggegevens:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json index a640fe8f4f..4aa4f6616f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Czy mogę w przyszłości zmienić zarejestrowanych programistów mojej organizacji?", "ChangingDevelopersExplanation": "Oprócz dodawania nowych programistów do swojej licencji możesz również zmieniać istniejących programistów (możesz usunąć programistę i dodać nowego do tego samego stanowiska) bez żadnych dodatkowych kosztów.", "WhenShouldIRenewMyLicense": "Kiedy powinienem odnowić licencję?", - "WhenShouldIRenewMyLicenseExplanation": "Jeśli odnowisz licencję w ciągu 1 miesiąca po wygaśnięciu licencji, zostaną zastosowane następujące rabaty: licencja zespołowa {0}% rabatu, licencja biznesowa {1}% rabatu, licencja Enterprise {2}% rabatu . Jeśli odnowisz licencję 1 miesiąc po dacie wygaśnięcia licencji, cena odnowienia będzie taka sama jak cena zakupu licencji i nie będzie rabatu na odnowienie.", + "WhenShouldIRenewMyLicenseExplanation": "Jeśli odnowisz licencję w ciągu {3} dni po wygaśnięciu licencji, zostaną zastosowane następujące rabaty: licencja zespołowa {0}% rabatu, licencja biznesowa {1}% rabatu, licencja Enterprise {2}% rabatu . Jeśli odnowisz licencję 1 miesiąc po dacie wygaśnięcia licencji, cena odnowienia będzie taka sama jak cena zakupu licencji i nie będzie rabatu na odnowienie.", "TrialPlan": "Czy masz plan próbny?", "DoYouAcceptBankWireTransfer": "Czy akceptujesz przelew bankowy?", "DoYouAcceptBankWireTransferExplanation": "Tak, akceptujemy przelew bankowy.
Po wysłaniu opłaty licencyjnej przelewem bankowym wyślij nam e-mail na adres accounting@abp.io z potwierdzeniem odbioru i rodzajem żądanej licencji. Informacje o naszych międzynarodowych kontach bankowych:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json index 4dd117e52a..4e06b40112 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json @@ -178,6 +178,7 @@ "ChangingLicenseType": "Posso atualizar meu tipo de licença mais tarde?", "ChangingLicenseTypeExplanation": "Você pode atualizar para uma licença superior pagando a diferença dentro do período de sua licença ativa. Ao atualizar para um plano de licença superior, você obtém os benefícios do novo plano, mas a atualização da licença não altera a data de expiração da licença. Além disso, você também pode adicionar novas licenças de desenvolvedor à sua licença existente, consulte \"Quantos desenvolvedores podem trabalhar no comercial ABP?\"", "LicenseExtendUpgradeDiff": "Qual é a diferença entre extensão de licença e atualização?", + "LicenseExtendUpgradeDiffExplanation": "Extensão: ao estender/renovar sua licença, você continuará a obter suporte premium e obter atualizações principais ou secundárias para os módulos e temas. Além disso, você poderá continuar criando novos projetos. E você ainda poderá utilizar o ABP Suite que agiliza seu desenvolvimento. Ao estender sua licença, 1 ano é adicionado à data de expiração da licença.
Atualização: Ao atualizar sua licença, você será promovido para um plano de licença superior que lhe permitirá obter benefícios adicionais. Confira a tabela de comparação de licenças para ver as diferenças entre os planos de licença. Por outro lado, quando você atualizar, a data de expiração de sua licença não será alterada! Para estender a data de término de sua licença, você precisa estender sua licença.", "LicenseRenewalCost": "Qual é o custo de renovação da licença após 1 ano?", "LicenseRenewalCostExplanation": "O preço de renovação (extensão) da Licença de equipe padrão é $ {0}, a Licença comercial padrão é $ {1} e a Licença corporativa padrão é $ {2}. Se você já é um cliente, faça login em sua conta para verificar os preços de renovação disponíveis.", "HowDoIRenewMyLicense": "Como eu renovo minha licença?", @@ -190,7 +191,7 @@ "ChangingDevelopers": "Posso mudar os desenvolvedores registrados da minha organização no futuro?", "ChangingDevelopersExplanation": "Além de adicionar novos desenvolvedores à sua licença, você também pode alterar os desenvolvedores existentes (você pode remover um desenvolvedor e adicionar um novo ao mesmo assento) sem nenhum custo adicional.", "WhenShouldIRenewMyLicense": "Quando devo renovar minha licença?", - "WhenShouldIRenewMyLicenseExplanation": "Se você renovar sua licença em 1 mês após a expiração da licença, os seguintes descontos serão aplicados: Licença de equipe {0} ; Licença de negócios {1} ; Licença empresarial {2} . Se você renovar sua licença 1 mês após a data de expiração de sua licença, o preço de renovação será o mesmo que o preço de compra da licença e não haverá desconto em sua renovação.", + "WhenShouldIRenewMyLicenseExplanation": "Se você renovar sua licença em {3} dias após a expiração da licença, os seguintes descontos serão aplicados: Licença de equipe {0} ; Licença de negócios {1} ; Licença empresarial {2} . Se você renovar sua licença {3} dias após a data de expiração de sua licença, o preço de renovação será o mesmo que o preço de compra da licença e não haverá desconto em sua renovação.", "TrialPlan": "Você tem um plano experimental?", "DoYouAcceptBankWireTransfer": "Você aceita transferência bancária?", "DoYouAcceptBankWireTransferExplanation": "Sim, aceitamos transferência bancária.
Após enviar a taxa de licença por transferência bancária, envie-nos um e-mail para accounting@abp.io com seu recibo e o tipo de licença solicitada. Nossas informações de conta bancária internacional:", @@ -380,6 +381,27 @@ "TrialLicenseExpiredInfo": "Seu período de licença de teste expirou!", "CommercialNewsletterConfirmationMessage": "Eu concordo com os Termos e Condições e a Política de Privacidade ", "discountForYears": "{0}% de desconto por {1} ano(s)", - "BlackFridayDiscount": "Desconto de Black Friday" + "BlackFridayDiscount": "Desconto de Black Friday", + "WhyUseAbpIoPlatform": "Por que devo usar a plataforma ABP.IO em vez de criar uma nova solução a partir do zero?", + "WhyUseAbpIoPlatformFaqExplanation": "Veja esse documento para uma explicação detalhada do porquê de usar a Plataforma ABP.IO tem uma vantagem significativa sobre fazer tudo você mesmo.", + "OnboardingTrainingFaqTitle": "Você tem treinamento de ABP a bordo?", + "SupportPolicyFaqTitle": "Qual é sua política de apoio?", + "SupportPolicyFaqExplanation": "Nós apoiamos apenas a versão ativa e a versão principal anterior. Não garantimos o lançamento de um patch para a 3ª e mais antigas versões principais. Por exemplo, se a versão ativa for a 7.0.0, lançaremos correções tanto para a 6.x.x como para a 7.x.x.x. Além disso, fornecemos suporte somente para questões relacionadas ao ABP Framework e ABP Commercial. Isso significa que nenhum suporte é dado para as aplicações de terceiros, serviços de nuvem e outras bibliotecas periféricas usadas pelos produtos ABP. Usaremos esforços comercialmente razoáveis para fornecer suporte técnico a nossos clientes durante o horário comercial oficial da \"Volosoft Bilisim A.S\". Por outro lado, não nos comprometemos com um acordo de nível de serviço (SLA) de tempo de resposta, mas tentaremos responder às questões técnicas o mais rápido possível dentro de nosso horário oficial de trabalho. A menos que um acordo especial seja feito com o cliente, fornecemos suporte somente em https://support.abp.io. Também temos suporte privado por e-mail, que só está disponível para os detentores de licenças empresariais.", + "DowngradeLicensePlan": "Posso baixar para um plano de licença mais baixo no futuro?", + "DowngradeLicensePlanExplanation": "Você não pode rebaixar seu plano de licença existente. Mas você pode adquirir um novo plano de licença inferior e continuar seu desenvolvimento com a nova licença. Após adquirir uma licença inferior, você só precisa fazer o login em seu novo plano de licença via comando ABP CLI: abp login -o `.", + "LicenseTransfer": "Uma licença pode ser transferida de um desenvolvedor para outro?", + "LicenseTransferExplanation": "Sim! Ao adquirir uma licença, você se torna o detentor da licença, portanto, você terá acesso à página de gerenciamento da organização. Uma organização tem funções de proprietário e desenvolvedor. Os proprietários podem gerenciar os cargos de desenvolvedor e designar desenvolvedores. Cada desenvolvedor designado fará login via comando ABP CLI no sistema e terá permissões de desenvolvimento e suporte.", + "BlazoriseLicense": "Precisamos comprar a licença Blazorise?", + "BlazoriseLicenseExplanation": "Temos um acordo entre a Volosoft e a Megabit, com este acordo a licença Blazorise é agregada aos produtos comerciais da ABP, portanto, nossos clientes não precisam comprar uma licença Blazorise extra.", + "RenewLicenseEarly": "Se eu renovar minha licença mais cedo, terei o ano todo", + "RenewLicenseEarylExplanation": "Quando você renovar sua licença antes da data de expiração, 1 ano será adicionado à data de expiração de sua licença. Por exemplo, se sua licença expirar em {0}-06-06 e você a renovar em {0}-01-01, sua nova data de expiração será {1}-06-06.", + "WhatHappensWhenLicenseEnds": "O que acontece quando meu período de licença termina?", + "WhatHappensWhenLicenseEndsExplanation1": "A licença comercial da ABP é uma licença perpétua. Após a expiração de sua licença, você pode continuar desenvolvendo seu projeto. E você não é obrigado a renovar sua licença. Sua licença vem com uma atualização de um ano e um plano de suporte fora da caixa. A fim de continuar a obter novos recursos, melhorias de desempenho, correção de bugs, suporte e continuar usando o ABP Suite, você precisa renovar sua licença. Quando sua licença expirar;", + "WhatHappensWhenLicenseEndsExplanation2": "Você não pode criar novas soluções usando o ABP Commercial, mas pode continuar desenvolvendo suas aplicações existentes para sempre.", + "WhatHappensWhenLicenseEndsExplanation3": "Você poderá obter atualizações para os módulos e temas dentro de sua versão MINOR (exceto as versões RC ou Preview). Por exemplo: se você estiver usando a v3.2.0 de um módulo, você ainda poderá obter atualizações para a v3.2.x (v3.2.1, v3.2.5... etc.) desse módulo. Mas você não pode obter atualizações para a próxima versão maior ou menor (como v3.3.0, v3.3.3, 4.x.x... etc.). Por exemplo, quando sua licença expirou, a última versão foi a v4.4.3, e mais tarde, publicou tanto a versão 4.4.4 quanto a 4.5.0, você poderia acessar a v4.4.X, mas não poderia acessar a v4.5.X.", + "WhatHappensWhenLicenseEndsExplanation4": "Você não pode instalar novos módulos e temas adicionados à plataforma comercial da ABP após o término de sua licença.", + "WhatHappensWhenLicenseEndsExplanation5": "Você não pode usar o ABP Suite", + "WhatHappensWhenLicenseEndsExplanation6": "Você não pode mais obter o apoio de premium.", + "WhatHappensWhenLicenseEndsExplanation7": "Você pode estender (renovar) sua licença se quiser continuar obtendo esses benefícios. Se você estender sua licença dentro de {3} dias após a expiração de sua licença, os seguintes descontos serão aplicados: Licença de equipe {0}; Licença Comercial {1}; Licença empresarial {2}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json index c1eeae7448..358bd87038 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Pe viitor, pot schimba dezvoltatorii ataşaţi organizaţiei mele?", "ChangingDevelopersExplanation": "În plus faţă de adăugarea de noi dezvoltatori la licenţa dumneavoastră, puteţi schimba şi dezvoltatorii existenţi(puteţi elimina un dezvoltator şi adăuga unul nou în locul lui) fără costuri suplimentare.", "WhenShouldIRenewMyLicense": "Când ar trebui să-mi reînnoiesc licenţa?", - "WhenShouldIRenewMyLicenseExplanation": "Dacă vă reînnoiți licența în termen de o lună de la expirarea licenței, se vor aplica următoarele reduceri: Licență de echipă {0}% reducere, Licență de afaceri {1}% reducere, Licență Enterprise {2}% reducere . Dacă vă reînnoiți licența la 1 lună după data de expirare a licenței, prețul de reînnoire va fi același cu prețul de achiziție a licenței și nu va exista nicio reducere la reînnoirea dvs.", + "WhenShouldIRenewMyLicenseExplanation": "Dacă vă reînnoiți licența în termen de {3} de zile de la expirarea licenței, se vor aplica următoarele reduceri: Licență de echipă {0}% reducere, Licență de afaceri {1}% reducere, Licență Enterprise {2}% reducere . Dacă vă reînnoiți licența la {3} de zile după data de expirare a licenței, prețul de reînnoire va fi același cu prețul de achiziție a licenței și nu va exista nicio reducere la reînnoirea dvs.", "TrialPlan": "Aveţi un plan de încercare?", "DoYouAcceptBankWireTransfer": "Acceptaţi transfer bancar?", "DoYouAcceptBankWireTransferExplanation": "Da, acceptăm transfer bancar.
După ce ați trimis taxa de licență prin transfer bancar, trimiteți-ne un e-mail la accounting@abp.io chitanța dvs. și tipul de licență solicitat. Informațiile noastre internaționale despre contul nostru bancar:", @@ -381,4 +381,4 @@ "CommercialNewsletterConfirmationMessage": "Sunt de acord cu Termenii și condițiile și cu Politica de confidențialitate .", "BlackFridayDiscount": "Black Friday Discount" } -} +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json index 7a0427083e..8c53bc9ea8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ru.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Могу ли я сменить зарегистрированных разработчиков моей организации в будущем?", "ChangingDevelopersExplanation": "Помимо добавления новых разработчиков к вашей лицензии, вы также можете изменить существующих разработчиков (вы можете удалить разработчика и добавить нового на то же место) без каких-либо дополнительных затрат.", "WhenShouldIRenewMyLicense": "Когда мне следует продлить лицензию?", - "WhenShouldIRenewMyLicenseExplanation": "Если вы продлите лицензию в течение 1 месяца после истечения срока действия лицензии, будут применяться следующие скидки: групповая лицензия {0}% скидка, бизнес-лицензия {1}% скидка, корпоративная лицензия {2}% скидка . Если вы продлеваете лицензию через 1 месяц после даты истечения срока действия лицензии, цена продления будет такой же, как цена покупки лицензии, и при продлении скидки не будет.", + "WhenShouldIRenewMyLicenseExplanation": "Если вы продлите лицензию в течение {3} дней после истечения срока действия лицензии, будут применяться следующие скидки: групповая лицензия {0}% скидка, бизнес-лицензия {1}% скидка, корпоративная лицензия {2}% скидка . Если вы продлеваете лицензию {3} дней после даты истечения срока действия лицензии, цена продления будет такой же, как цена покупки лицензии, и при продлении скидки не будет.", "TrialPlan": "У вас есть пробный план?", "DoYouAcceptBankWireTransfer": "Вы принимаете банковский перевод?", "DoYouAcceptBankWireTransferExplanation": "Да, мы принимаем банковский перевод.
После отправки платы за лицензию банковским переводом отправьте нам электронное письмо по адресу accounting@abp.io, квитанцию и тип запрошенной лицензии. Информация о нашем международном банковском счете:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json index 0bb203a2ca..b0a6d6490e 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Môžem v budúcnosti zmeniť registrovaných vývojárov svojej organizácie?", "ChangingDevelopersExplanation": "Okrem pridávania nových vývojárov do licencie môžete tiež meniť existujúcich vývojárov (môžete odstrániť vývojára a pridať nového na to isté miesto) bez akýchkoľvek ďalších nákladov.", "WhenShouldIRenewMyLicense": "Kedy si mám obnoviť licenciu?", - "WhenShouldIRenewMyLicenseExplanation": "Ak si licenciu obnovíte do 1 mesiaca po vypršaní platnosti licencie, budú sa uplatňovať tieto zľavy: Tímová licencia {0} ; Obchodná licencia {1} ; Enterprise licencia {2} . Ak si licenciu obnovíte 1 mesiac po dátume skončenia platnosti licencie, cena za obnovenie bude rovnaká ako cena za nákup licencie a na obnovenie nebude poskytnutá žiadna zľava.", + "WhenShouldIRenewMyLicenseExplanation": "Ak si licenciu obnovíte do 30 dní po vypršaní platnosti licencie, budú sa uplatňovať tieto zľavy: Tímová licencia {0} ; Obchodná licencia {1} ; Enterprise licencia {2} . Ak si licenciu obnovíte 30 dní po dátume skončenia platnosti licencie, cena za obnovenie bude rovnaká ako cena za nákup licencie a na obnovenie nebude poskytnutá žiadna zľava.", "TrialPlan": "Máte skúšobný plán?", "DoYouAcceptBankWireTransfer": "Prijímate bankový prevod?", "DoYouAcceptBankWireTransferExplanation": "Áno, akceptujeme bankový prevod.
Po odoslaní licenčného poplatku bankovým prevodom nám pošlite e-mail na adresu accounting@abp.io svoje potvrdenie a požadovaný typ licencie. Informácie o našom medzinárodnom bankovom účte:", @@ -380,6 +380,24 @@ "TrialLicenseExpiredInfo": "Vaše skúšobné licenčné obdobie vypršalo!", "CommercialNewsletterConfirmationMessage": "I agree to the Terms & Conditions and Privacy Policy.", "discountForYears": "{0} % odpusteného prívesku {1} an(ov)", - "BlackFridayDiscount": "Black Friday zľava" + "BlackFridayDiscount": "Black Friday zľava", + "OnboardingTrainingFaqTitle": "Máte školenie ABP onboarding?", + "OnboardingTrainingFaqExplanation": "Áno, máme školiace služby ABP, ktoré vám pomôžu rýchlo spustiť váš projekt ABP. Dozviete sa o ABP od hlavného člena tímu ABP a získate zručnosti na začatie vášho projektu ABP. Na onboardingovom školení vám vysvetlíme, ako nastaviť vaše vývojové prostredie, nainštalovať požadované nástroje, vytvoriť plne funkčnú stránku CRUD. Školenie bude prebiehať naživo a bude sa používať aplikácia Zoom a sme otvorení využívaniu ďalších platforiem online stretnutí. Jazykom školenia bude angličtina. Svoje otázky o ABP môžete klásť aj počas sedení. Pre obe strany bude naplánovaný vhodný čas a dátum. Ak chcete získať ďalšie informácie, kontaktujte nás na adrese info@abp.io.", + "SupportPolicyFaqTitle": "Aká je vaša politika podpory?", + "SupportPolicyFaqExplanation": "Podporujeme iba aktívnu a predchádzajúcu hlavnú verziu. Nezaručujeme vydanie opravy pre 3. a staršiu hlavnú verziu. Napríklad, ak je aktívna verzia 7.0.0, vydáme opravné verzie pre 6.x.x aj 7.x.x. Okrem toho poskytujeme podporu len pre problémy súvisiace s ABP Framework a ABP Commercial. To znamená, že neposkytujeme podporu pre aplikácie tretích strán, cloudové služby a iné periférne knižnice používané produktmi ABP. Vynaložíme komerčne primerané úsilie, aby sme našim zákazníkom poskytli technickú podporu počas oficiálnej pracovnej doby spoločnosti \"Volosoft Bilisim A.S\". Na druhej strane sa nezaväzujeme k času odozvy podľa dohody o úrovni služieb (SLA), ale budeme sa snažiť reagovať na technické problémy čo najrýchlejšie v rámci našej oficiálnej pracovnej doby. Ak sa so zákazníkom nedohodnete inak, poskytujeme podporu len na adrese https://support.abp.io. Máme aj súkromnú e-mailovú podporu, ktorá je k dispozícii len držiteľom licencie Enterprise.", + "DowngradeLicensePlan": "Môžem v budúcnosti prejsť na nižší licenčný plán?", + "DowngradeLicensePlanExplanation": "Existujúci licenčný plán nemôžete znížiť. Môžete si však zakúpiť nový nižší licenčný plán a pokračovať vo vývoji s novou licenciou. Po zakúpení nižšej licencie sa stačí prihlásiť do nového licenčného plánu prostredníctvom príkazu ABP CLI: abp login -o `.", + "LicenseTransfer": "Môže sa licencia preniesť z jedného vývojára na druhého?", + "LicenseTransferExplanation": "Áno! Keď si zakúpite licenciu, stanete sa jej držiteľom, a teda budete mať prístup na stránku správy organizácie. Organizácia má roly vlastníka a vývojára. Vlastníci môžu spravovať miesta pre vývojárov a priraďovať vývojárov. Každý pridelený vývojár sa prihlási do systému prostredníctvom príkazu ABP CLI a bude mať oprávnenia na vývoj a podporu.", + "WhatHappensWhenLicenseEnds": "Čo sa stane po skončení licenčného obdobia?", + "WhatHappensWhenLicenseEndsExplanation1": "Komerčná licencia ABP je trvalá licencia. Po skončení platnosti licencie môžete pokračovať vo vývoji svojho projektu. A nie ste povinní licenciu obnovovať. Vaša licencia sa dodáva s ročným plánom aktualizácií a podpory už v balení. Ak chcete naďalej získavať nové funkcie, vylepšenia výkonu, opravy chýb, podporu a pokračovať v používaní balíka ABP Suite, musíte svoju licenciu obnoviť. Keď vaša licencia vyprší;", + "WhatHappensWhenLicenseEndsExplanation2": "Pomocou ABP Commercial nemôžete vytvárať nové riešenia, ale môžete navždy pokračovať vo vývoji existujúcich aplikácií.", + "WhatHappensWhenLicenseEndsExplanation3": "Budete môcť získať aktualizácie modulov a tém v rámci svojej verzie MINOR (okrem verzií RC alebo Preview). Napríklad: ak používate modul vo verzii 3.2.0, stále môžete získať aktualizácie pre verziu 3.2.x (v3.2.1, v3.2.5... atď.) tohto modulu. Nemôžete však získať aktualizácie pre ďalšiu hlavnú alebo vedľajšiu verziu (napríklad v3.3.0, v3.3.3, 4.x.x... atď.). Napríklad, keď vám vypršala licencia, posledná verzia bola v4.4.3 a neskôr bola zverejnená verzia 4.4.4 aj 4.5.0, budete mať prístup k verzii v4.4.X, ale nebudete mať prístup k verzii v4.5.X.", + "WhatHappensWhenLicenseEndsExplanation4": "Po skončení platnosti vašej licencie nemôžete inštalovať nové moduly a témy pridané do platformy ABP Commercial.", + "WhatHappensWhenLicenseEndsExplanation5": "Balík ABP Suite nemôžete používať.", + "WhatHappensWhenLicenseEndsExplanation6": "Už nemôžete získať prémiovú podporu.", + "WhatHappensWhenLicenseEndsExplanation7": "Ak chcete naďalej využívať tieto výhody, môžete si licenciu predĺžiť (obnoviť). Ak predĺžite svoju licenciu do 30 dní po vypršaní platnosti licencie, budú sa uplatňovať nasledujúce zľavy: Tímová licencia {0}; Obchodná licencia {1}; Podniková licencia {2}", + "BlazoriseLicense": "Musíme si kúpiť licenciu Blazorise?", + "BlazoriseLicenseExplanation": "Máme dohodu medzi spoločnosťami Volosoft a Megabit, na základe ktorej je licencia Blazorise pribalená k produktom ABP Commercial, preto si naši zákazníci nemusia kupovať ďalšiu licenciu Blazorise." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json index 5abffa2189..85acb70552 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Ali lahko v prihodnosti spremenim registrirane razvijalce svoje organizacije?", "ChangingDevelopersExplanation": "Poleg dodajanja novih razvijalcev vaši licenci lahko spremenite tudi obstoječe razvijalce (lahko odstranite razvijalca in dodate novega na isto mesto) brez dodatnih stroškov.", "WhenShouldIRenewMyLicense": "Kdaj naj podaljšam licenco?", - "WhenShouldIRenewMyLicenseExplanation": "Če licenco podaljšate v 1 mesecu po poteku licence, bodo uporabljeni naslednji popusti: licenca za ekipo {0} % popusta, poslovna licenca {1} % popusta, licenca za podjetje {2} % popusta . Če podaljšate licenco 1 mesec po datumu poteka veljavnosti licence, bo cena podaljšanja enaka nakupni ceni licence in pri podaljšanju ne bo popusta.", + "WhenShouldIRenewMyLicenseExplanation": "Če licenco podaljšate v {3} dni po poteku licence, bodo uporabljeni naslednji popusti: licenca za ekipo {0} % popusta, poslovna licenca {1} % popusta, licenca za podjetje {2} % popusta . Če podaljšate licenco {3} dni po datumu poteka veljavnosti licence, bo cena podaljšanja enaka nakupni ceni licence in pri podaljšanju ne bo popusta.", "TrialPlan": "Ali imate poskusni načrt?", "DoYouAcceptBankWireTransfer": "Ali sprejemate bančno nakazilo?", "DoYouAcceptBankWireTransferExplanation": "Da, sprejemamo bančno nakazilo.
Ko pošljete licenčnino prek bančnega nakazila, nam pošljite e-pošto na accounting@abp.io vaše potrdilo o prejemu in vrsto zahtevane licence. Naši podatki o mednarodnem bančnem računu:", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json index 9a21d6de0a..96375db1f6 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json @@ -95,7 +95,7 @@ "LanguageManagement": "Dil Yönetimi", "TextTemplateManagement": "Metin Şablonu Yönetimi", "See All Modules": "SeeAllModüller", - "ABPSuite": "ABP Süiti", + "ABPSuite": "ABP Suite", "AbpSuiteShortDescription": "ABP Suite, ABP Commercial için tamamlayıcı bir araçtır.", "AbpSuiteExplanation": "Birkaç dakika içinde web sayfaları oluşturmanıza olanak tanır. Komut satırından yüklenebilen bir .NET Core Global aracıdır. Yeni bir ABP çözümü oluşturabilir, veritabanından ön uca kadar CRUD sayfaları oluşturabilir.", "Details": "Detaylar", @@ -193,7 +193,7 @@ "ChangingDevelopers": "Gelecekte kuruluşumun kayıtlı geliştiricilerini değiştirebilir miyim?", "ChangingDevelopersExplanation": "Lisansınıza yeni geliştiriciler eklemenin yanı sıra mevcut geliştiricileri de herhangi bir ek ücret ödemeden değiştirebilirsiniz (bir geliştiriciyi kaldırıp aynı koltuğa yeni bir tane ekleyebilirsiniz).", "WhenShouldIRenewMyLicense": "Ehliyetimi ne zaman yenilemeliyim?", - "WhenShouldIRenewMyLicenseExplanation": "Lisansınızın süresi dolduktan sonra 1 ay içinde lisansınızı yenilerseniz, aşağıdaki indirimler uygulanacaktır: Takım Lisansı %{0} indirim, İşletme Lisansı %{1} indirim, Kurumsal Lisans %{2} indirim . Lisansınızın sona erme tarihinden 1 ay sonra lisansınızı yenilerseniz, yenileme fiyatı lisans satın alma fiyatı ile aynı olacak ve yenilemenizde indirim yapılmayacaktır.", + "WhenShouldIRenewMyLicenseExplanation": "Lisansınızın süresi dolduktan sonra {3} gün içinde lisansınızı yenilerseniz, aşağıdaki indirimler uygulanacaktır: Takım Lisansı %{0} indirim, İşletme Lisansı %{1} indirim, Kurumsal Lisans %{2} indirim . Lisansınızın sona erme tarihinden {3} gün sonra lisansınızı yenilerseniz, yenileme fiyatı lisans satın alma fiyatı ile aynı olacak ve yenilemenizde indirim yapılmayacaktır.", "TrialPlan": "Deneme planınız var mı?", "DoYouAcceptBankWireTransfer": "Banka havalesini kabul ediyor musunuz?", "DoYouAcceptBankWireTransferExplanation": "Evet, banka havalesini kabul ediyoruz.
Lisans ücretini banka havalesi yoluyla gönderdikten sonra, dekontunuzu ve talep edilen lisans türünü accounting@abp.io adresinden bize e-posta ile gönderin. Uluslararası banka hesap bilgilerimiz:", @@ -391,18 +391,18 @@ "AddNewDeveloper": "Yeni geliştirici ekle", "FirstNameField": "Ad", "LastNameField": "Soyad", - "AbpCommercialMetaTitle": "ABP Commercial - Eksiksiz Web Geliştirme Platformu : {0} | ABP Commercial", + "AbpCommercialMetaTitle": " {0} | ABP Commercial", "AbpCommercialMetaDescription": "ABP Commercial, açık kaynaklı ABP çerçevesinin üzerine inşa edilmiş önceden oluşturulmuş uygulama modülleri, hızlı geliştirme araçları, kullanıcı arayüzü temaları ve hizmetlerinden oluşan bir settir.", - "WhatHappensWhenLicenseEnds": "Lisans sürem sona erdiğinde ne olacak?", + "WhatHappensWhenLicenseEnds": "Lisans sürem sona erdiğinde ne olacak?", "WhatHappensWhenLicenseEndsExplanation1": "ABP Ticari lisansı kalıcı bir lisanstır. Lisansınızın süresi dolduktan sonra projenizi geliştirmeye devam edebilirsiniz. Ve lisansınızı yenilemek zorunda değilsiniz. Lisansınız kutudan bir yıllık güncelleme ve destek planı ile birlikte gelir. Yeni özellikler, performans geliştirmeleri, hata düzeltmeleri, destek almaya devam etmek ve ABP Suite'i kullanmaya devam etmek için lisansınızı yenilemeniz gerekir. Lisansınızın süresi dolduğunda aşağıdaki avantajlardan yararlanamazsınız:", "WhatHappensWhenLicenseEndsExplanation2": "ABP Ticari'yi kullanarak yeni çözümler oluşturamazsınız, ancak mevcut uygulamalarınızı sonsuza kadar geliştirmeye devam edebilirsiniz.", "WhatHappensWhenLicenseEndsExplanation3": "MINOR sürümünüzdeki modüller ve temalar için güncellemeleri alabileceksiniz (RC veya Önizleme sürümleri hariç). Örneğin: bir modülün v3.2.0 sürümünü kullanıyorsanız, bu modülün v3.2.x (v3.2.1, v3.2.5... vb.) sürümleri için güncellemeleri almaya devam edebilirsiniz. Ancak bir sonraki büyük veya küçük sürüm için güncelleme alamazsınız (v3.3.0, v3.3.3, 4.x.x... gibi). Örneğin, lisansınızın süresi dolduğunda, en son sürüm v4.4.3 idi ve daha sonra hem 4.4.4 sürümünü hem de 4.5.0 sürümünü yayınladı, v4.4.X'e erişebilirsiniz, ancak v4.5.X'e erişemezsiniz.", "WhatHappensWhenLicenseEndsExplanation4": "Lisansınız sona erdikten sonra ABP Ticari platformuna eklenen yeni modülleri ve temaları yükleyemezsiniz.", "WhatHappensWhenLicenseEndsExplanation5": "ABP Suite'i kullanamazsınız.", "WhatHappensWhenLicenseEndsExplanation6": "Artık premium desteği alamazsınız.", - "WhatHappensWhenLicenseEndsExplanation7": "Bu avantajlardan yararlanmaya devam etmek istiyorsanız lisansınızı uzatabilirsiniz (yenileyebilirsiniz). Lisansınızın süresi dolduktan sonra 1 ay içinde lisansınızı uzatırsanız, aşağıdaki indirimler uygulanacaktır: Takım Lisansı {0} % indirim, İşletme Lisansı %{1} indirim, Kurumsal Lisans %{2} indirim.", + "WhatHappensWhenLicenseEndsExplanation7": "Bu avantajlardan yararlanmaya devam etmek istiyorsanız lisansınızı uzatabilirsiniz (yenileyebilirsiniz). Lisansınızın süresi dolduktan sonra {3} gün içinde lisansınızı uzatırsanız, aşağıdaki indirimler uygulanacaktır: Takım Lisansı {0} % indirim, İşletme Lisansı %{1} indirim, Kurumsal Lisans %{2} indirim.", "WhatHappensWhenLicenseEndsExplanation8": "Oluşturduğunuz ABP projeleri sunucularımızda saklanmamaktadır. Bu nedenle indirdiğiniz kaynak kodunu saklamak sizin sorumluluğunuzdadır. Lisansınızın süresi dolduğunda, oluşturulan ABP proje kaynak kodunuzu almanın bir yolu yoktur.", - "TrialPlanExplanation": "ABP Ticari takım lisansı için 14 günlük deneme süresi var. Daha fazla bilgi için burayı ziyaret edin. Ayrıca, Takım lisansları için 30 günlük para iade garantisi veriyoruz. Sadece ilk 30 gün içinde geri ödeme talebinde bulunabilirsiniz. İşletme ve Kurumsal lisansları için 30 gün içinde %60 geri ödeme sağlıyoruz. Bunun nedeni, İşletme ve Kurumsal lisanslarının tüm modüllerin ve temaların tam kaynak kodunu içermesidir.", + "TrialPlanExplanation": "Hayır, ABP Commercial için deneme sürümü yoktur. Kod kalitesini ve yaklaşımları anlamak için topluluk sürümünü kontrol edebilirsiniz. Ayrıca, Takım lisansları için 30 günlük para iade garantisi veriyoruz. Sadece ilk 30 gün içinde geri ödeme talebinde bulunabilirsiniz. İşletme ve Kurumsal lisansları için 30 gün içinde %60 geri ödeme sağlıyoruz. Bunun nedeni, İşletme ve Kurumsal lisanslarının tüm modüllerin ve temaların tam kaynak kodunu içermesidir.", "ContactUsQuestions": "Herhangi bir sorunuz varsa bizimle iletişime geçin", "ActivationRequirement": "Denemenizi başlatmanıza son bir adım kaldı.
Bilgilerinizi kontrol ettikten sonra lisansınızı etkinleştireceğiz. Lisansınız etkinleştirildiğinde, {0} adresine bir e-posta göndereceğiz. Merak etmeyin bu süreç uzun sürmeyecek!", "PurchaseNow": "Şimdi satın al", @@ -417,9 +417,8 @@ "RenewLicenseEarly": "Lisansımı erken yenilersem, tüm yılı alacak mıyım?", "RenewLicenseEarylExplanation": "Lisansınızı lisans bitiş tarihinizden önce yenilediğinizde, lisans bitiş tarihinize 1 yıl eklenecektir. Örneğin, lisansınızın süresi {0}-06-06 tarihinde doluyorsa ve lisansınızı {0}-01-01 tarihinde yenilediyseniz, yeni lisans bitiş tarihiniz {1}-06-06 olacaktır.", "OpenSourceWebApplication": "Açık Kaynak Web Uygulaması", - "CompleteWebDevelopment": "Tam Web Geliştirme", "ABPFrameworkDescription": "ABP Framework, yazılım geliştirme ve sözleşmelerin en iyi uygulamalarını takip ederek modern web uygulamaları oluşturmak için eksiksiz bir altyapıdır.", - "CommunityDescription": "ABP Çerçevesi ile ilgili deneyimlerinizi paylaşın!", + "CommunityDescription": "ABP Çerçevesi ile ilgili deneyimlerinizi paylaşın!", "GetStarted": "Başlayın", "Views": "Görünümler", "LatestPosts": "Son Gönderiler", @@ -441,7 +440,7 @@ "ModularArchitectureExplanation": "Bu başlangıç şablonu, temiz ve sürdürülebilir bir kod tabanı oluşturmak için katmanlı, modüler ve DDD tabanlı bir çözüm mimarisi sağlar.", "SeeDetails": "Ayrıntıları Gör", "SeeDocumentation": "Belgelere göz atın", - "Bs5Compatible": "Bootstrap 5 uyumlu profesyonel tema, yönetici web siteniz için mükemmel.", + "Bs5Compatible": "Bootstrap 5 uyumlu profesyonel tema, yönetici web siteniz için mükemmel.", "LeptonXTheme": "LeptonX Tema", "LeptonXDark": "LeptonX Koyu", "LeptonXLight": "LeptonX Açık", @@ -454,7 +453,7 @@ "EasilyInstallAndUpgrade": "Kolay kurulum ve yükseltme", "SupportForum": "Destek Forumu", "TrustedBy": "Güvenenler", - "OurPricing": "Fiyatlandırmamız", + "OurPricing": "Fiyatlandırmamız", "Plans": "Planlar", "NameSurname": "Ad Soyad", "Unspecified": "Belirtilmemiş", @@ -465,7 +464,7 @@ "License": "Lisans", "Development": "Geliştirme", "Payment": "Ödeme", - "WatchExplainerVideo": "Hadi Tanışalım! Açıklayıcı Videoyu İzleyin", + "WatchExplainerVideo": "Hadi Tanışalım! Açıklayıcı Videoyu İzleyin", "LightDarkAndSemiDarkThemes": "Açık, koyu ve yarı koyu temalar", "LeptonXThemeExplanation": "Lepton Teması, temanızı sistem ayarlarınıza göre değiştirebilir.", "PRO": "PRO", @@ -522,7 +521,7 @@ "AddBasket": "Sepete Ekle", "SendTrainingRequest": "Eğitim Talebi Gönder", "OnlyEnglishVersionOfThisDocumentIsTheRecentAndValid": "* Bu belgenin İngilizce versiyonu en güncel olanıdır ve herhangi bir anlaşmazlıkta İngilizce versiyonu geçerli olacaktır.", - "Pricing_Page_Title": "Planlar ve Fiyatlandırma", + "Pricing_Page_Title": "Fiyatlandırma ve Planlar", "Pricing_Page_Description": "İşletmenizin bugün ihtiyaç duyduğu özellikleri ve işlevselliği seçin. Bir ABP Ticari lisansı satın alın ve sınırsız proje oluşturun.", "Pricing_Page_HurryUp": "Acele edin!", "Pricing_Page_BuyLicense": "16 Ocak'a kadar 2021 fiyatlarıyla lisans satın alın!", @@ -548,6 +547,7 @@ "Pricing_Page_Testimonial_3": "ABP'yi seviyoruz. Her şeyi sıfırdan yazmak zorunda kalmıyoruz. Kullanıma hazır özelliklerden başlıyoruz ve sadece gerçekten yazmamız gerekenlere odaklanıyoruz. Ayrıca, ABP iyi tasarlanmış ve kod daha az hata ile yüksek kalitede. İhtiyaç duyduğumuz her şeyi kendi başımıza yazmak zorunda kalsaydık, yıllarımızı harcamak zorunda kalabilirdik. Hoşumuza giden bir diğer şey de yeni sürümün, sorun düzeltmenin ya da iyileştirmenin iki haftada bir çıkması. Çok uzun süre beklemiyoruz.", "Pricing_Page_Testimonial_4": "ABP Commercial harika bir ürün, tavsiye ederim. Müşterilerimiz için ticari ürünleri tek bir yapılandırılabilir platformda pazara sunuyor. Çerçeve ve araçların herhangi bir ekibe sağladığı hızlı başlangıç her kuruşa değer. ABP Commercial ihtiyaçlarımız için en uygun üründü.", "Pricing_Page_Testimonial_5": "ABP Framework sadece bir framework değil, aynı zamanda bir proje geliştirme/yönetme rehberi, çünkü DDD, GenericRepository, DI, Microservice ve Modularity eğitimleri veriyor. Framework'ün kendisini kullanmayacak olsanız bile, iyi ve profesyonelce hazırlanmış docs.abp.io ile kendinizi geliştirebilirsiniz (OpenIddict, Redis, Quartz vb.). Birçok şey önceden hazır olduğu için proje geliştirme süresini önemli ölçüde kısaltıyor (Giriş sayfası, istisna işleme, veri filtreleme, tohumlama, denetim günlüğü, yerelleştirme, otomatik API denetleyicisi vb.) Uygulamamızdan bir örnek olarak, stok kontrolü için Local Event Bus kullandım. Böylece stok işleyicisi yazarak sipariş hareketlerini yönetebiliyorum. CreationTime, CreatorId için zaman kaybetmemek harika. Bunlar otomatik olarak dolduruluyor.", + "Pricing_Page_Testimonial_6": "ABP Framework iyi bir çerçeve ancak kullandığı farklı katmanları, sınıfları ve kütüphaneleri (özellikle ABP) anlamak için zaman gerekiyor. Kod tabanını okumak için çok zaman harcadım, ancak ABP Commercial, proje özel varlıklarını (AR) ve her birine bağlı depoyu oluşturmak için bize zaman kazandırdı. ABP'de kullanılan yaklaşımın çok olgun olduğunu da beğendim, DDD ve monolith'e dayandığını biliyoruz.", "AbpBookDownloadArea_ClaimYourEBook": "Mastering ABP Framework E-Kitabınızı talep edin", "AddMemberModal_Warning_1": "Eklemeye çalıştığınız kullanıcı adı sistemde yoksa, lütfen ekip üyenizden {0} adresine kaydolmasını ve hesabının kullanıcı adını sizinle paylaşmasını isteyin.", "MyOrganizations_Detail_WelcomeMessage": "Organizasyonunuza hoş geldiniz, {0}", @@ -607,7 +607,7 @@ "Purchase_PricePerDeveloper": "{0} {1} geliştirici başına", "Purchase_IncludedDeveloperInfo": "{0} {1} dahil.", "Purchase_LicenseExtraDeveloperPurchaseMessage": "{0} lisansı {1} geliştirici(ler) içerir. Şimdi veya daha sonra ek geliştiriciler ekleyebilirsiniz.", - "StartupTemplates_Page_Title": "Başlangıç Şablonları", + "StartupTemplates_Page_Title": "ABP Başlangıç Şablonları", "StartupTemplates_Page_Description": "ABP Commercial, her düzeyde karmaşıklığa sahip çözümler oluşturmanıza olanak tanır. Önceden oluşturulmuş iki ana başlangıç çözümü sunar. Gereksinimlerinize yakın olanı seçebilir ve bunun üzerine kendi özel çözümünüzü oluşturabilirsiniz.", "MicroserviceStartupSolutionForDotnet": ".NET için Mikro Hizmet Başlatma Çözümü", "MonolithSolutionForDotnet": ".NET için Monolith (modüler) Çözüm", @@ -632,12 +632,11 @@ "Faq_Page_Currency": "Para Birimi", "Faq_Page_VatNumber": "Vergi Numarası", "Faq_Page_OtherCurrenciesInfo": "Diğer para birimleri için tüm hesaplar bölümüne bakınız", - "ModuleDetail_Page_Title": "Modül Detayı - {0}", "ProjectCreatedSuccess_Page_Title": "Projeniz oluşturuldu", "ProjectCreatedSuccess_Page_Description": "ABP projeniz başarıyla oluşturuldu!", - "Suite_Page_Title": "ABP Suite - CRUD Sayfaları Oluşturun", + "Suite_Page_Title": "ABP Suite", "Suite_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.", - "Themes_Page_Title": "Modern ve İşlevsel Kullanıcı Arayüzü Temaları", + "Themes_Page_Title": "ABP Temaları", "Themes_Page_Description": "ABP Commercial birden fazla profesyonel, modern kullanıcı arayüzü teması sunar. Kullanıcı arayüzünün neye benzediğini hızlıca görmek için ücretsiz bir demo oluşturun.", "Tools_Page_Title": "Hızlı Uygulama Geliştirme Araçları", "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.", @@ -655,7 +654,7 @@ "UpgradePaymentInfoSection_LicenseUpgradeDescription": "Lisansınızı yükselterek, ek avantajlar elde etmenizi sağlayacak daha yüksek bir lisans türüne terfi edeceksiniz. Lisans türleri arasındaki farkları kontrol etmek için lisans karşılaştırma tablosuna bakın.", "Landing_Page_CustomerStories": "Müşteri Hikayeleri", "Landing_Page_OurGreatCustomers": "Büyük Müşterilerimiz", - "Landing_Page_WebApplicationFramework": "Web Uygulama Çerçevesi", + "Landing_Page_WebApplicationFramework": "Web Uygulama Çerçevesi", "Landing_Page_WebDevelopmentPlatform": "Web Geliştirme Platformu", "Landing_Page_CompleteWebDevelopmentPlatform": "Tam Web Geliştirme Platformu", "Landing_Page_TryFreeDemo": "Ücretsiz Demo Dene", @@ -722,7 +721,7 @@ "Landing_Page_DocsModuleDescription_9": "GitHub kaynağına ek olarak, dokümantasyon kaynağı olarak bir klasörün kullanılmasına izin verir.", "Landing_Page_FileManagementModuleDescription_1": "Dosyaları hiyerarşik bir klasör yapısı içinde yükleyin, indirin ve düzenleyin.", "Landing_Page_FileManagementModuleDescription_2": "Bu modül, dosyaları hiyerarşik bir klasör yapısında yüklemek, indirmek ve düzenlemek için kullanılır. Ayrıca çoklu kiracılığa uyumludur ve kiracılarınız için toplam boyut sınırını belirleyebilirsiniz.", - "Landing_Page_FileManagementModuleDescription_3": "Bu modül BLOB Depolama sistemine dayanmaktadır, bu nedenle dosya içeriklerini depolamak için farklı depolama sağlayıcıları kullanabilir.", + "Landing_Page_FileManagementModuleDescription_3": "Bu modül BLOB Depolama sistemine dayanmaktadır, bu nedenle dosya içeriklerini depolamak için farklı depolama sağlayıcıları kullanabilir.", "Landing_Page_IdentityModuleDescription_1": "Bu modül bir uygulamanın Kullanıcı ve Rol sistemini uygular;", "Landing_Page_IdentityModuleDescription_2": "Microsoft'un ASP.NET Core Identity kütüphanesi üzerine inşa edilmiştir.", "Landing_Page_IdentityModuleDescription_3": "Sistemdeki rolleri ve kullanıcıları yönetin. Bir kullanıcının birden çok role sahip olmasına izin verilir.", @@ -745,7 +744,67 @@ "ConfirmedEmailAddressRequiredToStartTrial": "Deneme lisansı başlatmak için onaylanmış bir e -posta adresiniz olmalı.", "EmailVerificationMailNotSent": "E-posta doğrulama postası gönderilemedi.", "GetConfirmationEmail": "Daha önce bir onay e-postası almadıysanız almak için buraya tıklayın.", - "WhichLicenseTypeYouAreInterestedIn": "Hangi lisans türüyle ilgileniyorsunuz?", - "BlackFridayDiscount": "Kara Cuma İndirimi" + "WhichLicenseTypeYouAreInterestedIn": "Hangi lisans türüyle ilgileniyorsunuz?", + "BlackFridayDiscount": "Kara Cuma İndirimi", + "EulaPageTitle": "Son Kullanıcı Lisans Sözleşmesi (EULA)", + "PrivacyPolicyPageTitle": "Gizlilik Politikası - Çerez Politikası", + "TermsConditionsPageTitle": "Şartlar ve Koşullar", + "TrainingsPageTitle": "ABP Eğitim Paketleri", + "ModulesPageTitle": "ABP Hazır Uygulama Modülleri", + "Testimonial_ShortDescription_1": "ABP'nin modülerliği, ekibin zamanında teslimat yapmasını mümkün kıldı.", + "Testimonial_ShortDescription_2": "Yeni özellikleri eskisinden daha hızlı oluşturun.", + "Testimonial_ShortDescription_3": "Kullanıma hazır özelliklerden başlıyoruz ve sadece yazmamız gerekenlere odaklanıyoruz.", + "Testimonial_ShortDescription_4": "ABP Commercial ihtiyaçlarımız için en uygun olanıydı.", + "DontTakeOurWordForIt": "Bizim sözümüze güvenmeyin...", + "ReadAbpCommercialUsersWantYouToKnow": "ABP Commercial kullanıcılarının bilmenizi istediklerini okuyun.", + "OnlineReviewersOnAbpCommercial": "ABP Commercial Hakkında Çevrimiçi Yorumlar", + "SeeWhatToldAboutAbpCommercial": "ABP Commercial hakkında neler söylendiğini görün ve isterseniz düşüncelerinizi yazın.", + "YouDeserveGoodUXUI": "İyi bir kullanıcı arayüzünü ve daha iyi bir kullanıcı deneyimini hak ediyorsunuz. ABP'nin LeptonX Teması size hizmet etmek için burada.", + "ViewLiveDemo": "Canlı Tema Demosunu Görüntüle", + "LeptonXThemeForDashboard": "Yönetici Kontrol Paneliniz için LeptonX Teması", + "GetLeptonX": "LeptonX'i Şimdi Alın", + "SimplifiedMenu": "Basitleştirilmiş menü", + "SimplifiedMenuDescription": "Menüyü filtreleyerek aradığınız sayfayı kolayca bulabilirsiniz", + "YourFavoritePages": "Favori sayfalarınız elinizin altında", + "YourFavoritePagesDescription": "Sayfanın sağ üst köşesindeki yıldız simgesine tıklayarak sayfayı kolayca favorilere ekleyin veya favorilerden kaldırın.", + "BreadCrumbs": "Kesintisiz geçiş için Breadcrumb", + "BreadCrumbsDescription": "Breadcrumb'ı kullanarak, sol menü kapalıyken bile tek tıklamayla aynı seviyedeki sayfalara geçebilirsiniz, üstelik tablet ve mobil uyumlu çalışır!", + "YourMenu": "Menünüz dilediğiniz gibi", + "YourMenuDescription": "Kullanıcı menüsündeki doğrudan tıklanabilir simgeleri ve açılır kutuları istediğiniz gibi özelleştirin. Kullanıcı menüsü ihtiyaçlarınıza göre tamamen özelleştirilebilir", + "RtlSupport": "Diliniz için RTL desteği", + "RtlSupportDescription": "LeptonX Teması, diliniz için RTL'yi destekler. Dili değiştirmeniz için dil seçenekleri ayarlar menüsündedir.", + "YourColors": "Yönetici kontrol paneli kullanıcı arayüzünüzdeki renkleriniz", + "YourColorsDescription": "LeptonX Tema, sistem tercihlerinize göre çalışır ve gösterge paneli açık tema, gösterge paneli koyu tema ve gösterge paneli yarı koyu tema seçeneklerine sahiptir.", + "ArrangeContentWidth": "İçerik genişliğinizi kolayca düzenleyin", + "ArrangeContentWidthDescription": "İçerik alanınızın genişliğini kolayca değiştirin.", + "LeptonXCompatibleWith": "LeptonX Teması aşağıdakilerle uyumludur", + "MobileResponsiveTemplate": "Mobil Uyumlu Şablon", + "MobileResponsiveTemplateDescription1": "LeptonX yönetici kontrol panelinize istediğiniz cihazdan erişin.", + "MobileResponsiveTemplateDescription2": "Her cihazınızda rahatlıkla kullanabilmeniz için tasarlanmıştır. Mobil cihazlara ve tablet boyutlarına duyarlıdır.", + "TopMenuLayoutOption": "Üst Menü Düzeni Seçeneği", + "TopMenuLayoutOptionDescription1": "Web sitenizi aynı yönetici kontrol paneliyle kurmak istiyorsanız, LeptonX Teması ile bunu yapmanız mümkün!", + "TopMenuLayoutOptionDescription2": "Bunu gerçekleştirmek için LeptonX üst menü düzenini deneyin!", + "EasilyCustomizable": "Marka renkleriniz için kolayca özelleştirilebilir", + "EasilyCustomizableDescription1": "LeptonX temasını sadece birkaç SCSS değişkeni kullanarak özelleştirebilirsiniz. Geçersiz kılma yok, ekstra CSS yükü yok!", + "EasilyCustomizableDescription2": "LeptonX ile yönetici panelinizi istediğiniz gibi düzenleyebilirsiniz.", + "IndependentLayout": "Bağımsız düzen ve içerik alanı", + "IndependentLayoutDescription1": "LeptonX'in yerleşim altyapısı içerikten tamamen ayrı olarak tasarlandı.", + "IndependentLayoutDescription2": "Bu, isterseniz projenizi Bootstrap dışında bir içerik yapısı ile özgürce tasarlayabileceğiniz anlamına gelir.", + "MostUsedLibraries": "LeptonX ile entegre edilmiş en çok kullanılan kütüphaneler", + "MostUsedLibrariesDescription1": "LeptonX en çok kullandığınız kütüphaneleri içerir. ApexCharts, DataTables, DropZone, FullCalender, JSTree, Select2, Toastr gibi kütüphaneleri zahmetsizce kullanmanızı sağlar.", + "MostUsedLibrariesDescription2": "LeptonX ayrıca MVC Angular ve Blazor'a özgü kütüphaneleri de destekler.", + "CreateAndCustomize": "LeptonX özel sayfaları ile ihtiyacınız olan sayfaları saniyeler içinde oluşturun ve özelleştirin", + "CreateAndCustomizeDescription": "LeptonX Temasını kullanarak önceden hazırlanmış birçok html sayfasına da erişebilirsiniz. Bunlar arasında giriş sayfası, blog, SSS, abonelik listesi, fatura, fiyatlandırma, dosya yönetimi gibi birçok sayfa bulunmaktadır.", + "LeptonThemeForAdmin": "Yönetici kontrol paneliniz için Lepton Teması", + "LeptonThemeForAdminDescription": "Lepton Teması hala kullanılabilir durumdadır ve bakımı yapılacaktır. Bir Lepton Teması kullanıcısı olarak LeptonX Temasına geçmek istiyorsanız, nasıl yapılacağını öğrenmek için belgelere bakabilirsiniz.", + "LeptonCompatibleWith": "Lepton Teması aşağıdakilerle uyumludur", + "SeeLeptonDocumentation": "Lepton Dokümantasyonuna Bakın", + "GetLepton": "Lepton'u Şimdi Alın", + "WhyUseAbpIoPlatform": "Sıfırdan yeni bir çözüm oluşturmak yerine neden ABP.IO Platformunu kullanmalıyım?", + "WhyUseAbpIoPlatformFaqExplanation": "ABP.IO Platformunu kullanmanın her şeyi kendiniz yapmaya göre neden önemli bir avantaja sahip olduğuna dair ayrıntılı bir açıklama için bu belgeye bakın.", + "SupportPolicyFaqTitle": "Destek politikanız nedir?", + "SupportPolicyFaqExplanation": "Yalnızca etkin ve önceki ana sürümü destekliyoruz. Üçüncü ve daha eski ana sürümler için bir yama sürümünü garanti etmiyoruz. Örneğin, etkin sürüm 7.0.0 ise, hem 6.x.x hem de 7.x.x için yama sürümleri yayınlayacağız. Ayrıca, yalnızca ABP Framework ve ABP Commercial ile ilgili sorunlar için destek sağlıyoruz. Bu, ABP ürünleri tarafından kullanılan 3. taraf uygulamalar, bulut hizmetleri ve diğer çevresel kütüphaneler için destek verilmediği anlamına gelir. Müşterilerimize \"Volosoft Bilişim A.Ş\"nin resmi çalışma saatleri içinde teknik destek sağlamak için ticari olarak makul çabayı göstereceğiz. Öte yandan, bir hizmet seviyesi anlaşması (SLA) yanıt süresi taahhüt etmiyoruz, ancak teknik sorunlara resmi çalışma saatlerimiz içinde mümkün olduğunca çabuk yanıt vermeye çalışacağız. Müşteri ile özel bir anlaşma yapılmadığı sürece, yalnızca https://support.abp.io adresinden destek sağlıyoruz. Ayrıca, yalnızca Kurumsal Lisans sahiplerinin kullanabildiği özel e-posta desteğimiz de bulunmaktadır.", + "BlazoriseLicense": "Blazorise lisansı satın almamız gerekiyor mu?", + "BlazoriseLicenseExplanation": "Volosoft ve Megabit arasında bir anlaşmamız var, bu anlaşma ile Blazorise lisansı ABP Ticari ürünleri ile birlikte geliyor, bu nedenle müşterilerimizin ekstra bir Blazorise lisansı satın almasına gerek kalmıyor." } -} +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json index 4d0666772a..e5ed696808 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json @@ -190,7 +190,7 @@ "ChangingDevelopers": "Tôi có thể thay đổi các nhà phát triển đã đăng ký của tổ chức của mình trong tương lai không?", "ChangingDevelopersExplanation": "Ngoài việc thêm các nhà phát triển mới vào giấy phép của mình, bạn cũng có thể thay đổi các nhà phát triển hiện có (bạn có thể xóa một nhà phát triển và thêm một nhà phát triển mới vào cùng một chỗ ngồi) mà không phải trả thêm bất kỳ chi phí nào.", "WhenShouldIRenewMyLicense": "Khi nào tôi nên gia hạn giấy phép của mình?", - "WhenShouldIRenewMyLicenseExplanation": "Nếu bạn gia hạn giấy phép của mình trong vòng 1 tháng sau khi giấy phép của bạn hết hạn, các chiết khấu sau sẽ được áp dụng: Giảm giá {0}% cho Giấy phép Nhóm, Giảm giá {1}% Giấy phép Kinh doanh, Giảm giá {2}% Giấy phép Doanh nghiệp . Nếu bạn gia hạn giấy phép 1 tháng sau ngày giấy phép hết hạn, giá gia hạn sẽ giống như giá mua giấy phép và sẽ không có chiết khấu khi gia hạn của bạn.", + "WhenShouldIRenewMyLicenseExplanation": "Nếu bạn gia hạn giấy phép của mình trong vòng {3} ngày sau khi giấy phép của bạn hết hạn, các chiết khấu sau sẽ được áp dụng: Giảm giá {0}% cho Giấy phép Nhóm, Giảm giá {1}% Giấy phép Kinh doanh, Giảm giá {2}% Giấy phép Doanh nghiệp . Nếu bạn gia hạn giấy phép {3} ngày sau ngày giấy phép hết hạn, giá gia hạn sẽ giống như giá mua giấy phép và sẽ không có chiết khấu khi gia hạn của bạn.", "TrialPlan": "Bạn có kế hoạch dùng thử không?", "DoYouAcceptBankWireTransfer": "Bạn có chấp nhận chuyển khoản ngân hàng không?", "DoYouAcceptBankWireTransferExplanation": "Có, chúng tôi chấp nhận chuyển khoản ngân hàng.
Sau khi gửi phí cấp phép qua chuyển khoản ngân hàng, hãy gửi email cho chúng tôi theo địa chỉ accounting@abp.io biên lai của bạn và loại giấy phép được yêu cầu. Thông tin tài khoản ngân hàng quốc tế của chúng tôi:", 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 be657892f7..d78d8469f8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json @@ -160,7 +160,7 @@ "SearchQuestionPlaceholder": "搜索常见的问题", "WhatIsTheABPCommercial": "什么是ABP商业版?", "WhatAreDifferencesThanAbpFramework": "ABP框架与ABP商业版有什么不同?", - "AbpCommercialMetaTitle": "ABP 商业版 - 完整的网页开发平台 : {0} | ABP 商业版 ", + "AbpCommercialMetaTitle": " {0} | ABP 商业版 ", "AbpCommercialMetaDescription": "ABP 商业版是在开源ABP框架之上构建的一组预构建应用程序模块、快速开发工具、UI主题和服务架构", "ABPCommercialExplanation": "ABP商业版是一套基于开源ABP框架之上的高级模块,工具,主题和服务. ABP商业版由ABP框架背后的同一团队开发和支持.", "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP框架是模块化,主题化,微服务兼容的ASP.NET Core应用程序开发框架. 它提供了一个完整的架构和强大的基础设施,让你专注于自己的业务代码而不是重复自己的每一个项目. 它基于软件开发的最佳实践和你已经知道的流行工具

ABP框架是完全免费,开源和由社区驱动的. 它还提供了一个免费的主题和一些预构建的模块 (如 identity管理和租户管理).

", @@ -202,13 +202,13 @@ "WhatHappensWhenLicenseEndsExplanation4": "你不能在你的许可证到期后安装ABP商业平台上添加的新模块和主题。", "WhatHappensWhenLicenseEndsExplanation5": "你不能使用ABP Suite。", "WhatHappensWhenLicenseEndsExplanation6": "你不能再获得高级支持。", - "WhatHappensWhenLicenseEndsExplanation7": "如果您想继续获得这些好处,您可以延长(续订)您的许可证。 如果您在许可证到期后 1 个月内延长许可证,将应用以下折扣:团队许可证 {0}; 营业执照{1}; 企业许可证 {2}。", + "WhatHappensWhenLicenseEndsExplanation7": "如果您想继续获得这些好处,您可以延长(续订)您的许可证。 如果您在许可证到期后 {3} 天内延长许可证,将应用以下折扣:团队许可证 {0}; 营业执照{1}; 企业许可证 {2}。", "discountForYears": "{0}% 折扣 {1} 年", "WhatHappensWhenLicenseEndsExplanation8": "您生成的 ABP 项目未存储在我们的服务器上。 因此,您有责任保留下载的源代码。 当您的许可证到期时,将无法获取您生成的 ABP 项目源代码。", "WhenShouldIRenewMyLicense": "我什么时候应该续订我的许可?", - "WhenShouldIRenewMyLicenseExplanation": "如果您在许可证到期后 1 个月 内续订许可证,将适用以下折扣:团队许可证 {0}; 营业执照{1}; 企业许可证 {2}。 但是,如果您在许可证到期后 1 个月 后续订许可证,则续订价格将与许可证购买价格相同,并且您的续订不会有任何折扣。", + "WhenShouldIRenewMyLicenseExplanation": "如果您在许可证到期后 {3} 天 内续订许可证,将适用以下折扣:团队许可证 {0}; 营业执照{1}; 企业许可证 {2}。 但是,如果您在许可证到期后 {3} 天 后续订许可证,则续订价格将与许可证购买价格相同,并且您的续订不会有任何折扣。", "TrialPlan": "你们有试用计划吗?", - "TrialPlanExplanation": "ABP商业团队许可证有14天的试用期。若要了解更多信息,请访问这里。此外,我们为团队许可证提供30天的金额返还保证。你只需要在30天内请求退款。商业和企业许可证将提供60%的金额返还保证。这是因为商业和企业许可证包含了所有模块和主题的全部源代码。", + "TrialPlanExplanation": "不,ABP商业版没有试用版。您可以通过查看社区版了解代码质量和方法。我们还为团队许可证提供30天无条件退款保证!您可以在前30天内申请退款。对于商业和企业许可证,我们在30天内提供60%的退款。这是因为商业和企业许可证包含所有模块和主题的完整源代码。", "DoYouAcceptBankWireTransfer": "你们接受银行电汇吗?", "DoYouAcceptBankWireTransferExplanation": "是的,我们接受银行电汇。
在通过银行转账发送许可费后,将您的收据和所需的许可类型通过电子邮件发送至accounting@abp.io。 我们的国际银行账户信息:", "HowToUpgrade": "可用新版本时如何升级现有应用程序?", @@ -369,7 +369,6 @@ "FreeTrial": "免费试用", "AcceptsMarketingCommunications": " 是的,我想接收 ABP 商业营销通讯。", "PurposeOfUsage": "使用目的", - "Industry": "行业", "Choose": "- 选择 -", "CompanyOrganizationName": "公司/组织名称", "CompanySize": "公司规模", @@ -512,7 +511,7 @@ "AddBasket": "添加到购物车", "SendTrainingRequest": "发送培训请求", "OnlyEnglishVersionOfThisDocumentIsTheRecentAndValid": "* 本文件的英文版本为最新版本,如有任何争议,以英文版本为准。", - "Pricing_Page_Title": "计划 & 定价", + "Pricing_Page_Title": "价格和计划", "Pricing_Page_Description": "现在就选择您的业务及需要的特性和功能。 购买 ABP 商业许可证创建无限量项目。", "Pricing_Page_HurryUp": "赶快行动吧!", "Pricing_Page_BuyLicense": "在 1 月 16 日前以 2021 年价格 购买许可证!", @@ -538,6 +537,7 @@ "Pricing_Page_Testimonial_3": "我们大爱 ABP。 我们不必从头开始编写所有内容。 我们从\"开箱即用\"的功能开始,只需关注我们真正需要编写的内容。 此外,ABP 架构良好,代码质量高,错误少。 如果我们需要自己来编写所需的一切,我们可能需要花费数年时间。 另一点让我们喜欢的是新版本、问题修复或改进每隔一周很快地就会出现。 我们不会等太久。", "Pricing_Page_Testimonial_4": "ABP 商业版 是一款很值得推荐的出色产品。 是在一个可配置的平台上为我们的客户推向市场的商业产品。 其框架和工具为任何团队提供的快速启动值得每一分钱。 ABP 商业版 最适合我们的需求。", "Pricing_Page_Testimonial_5": "ABP Framework 不仅是一个框架,它还是项目开发/管理的指南,因为它提供了 DDD、GenericRepository、DI、微服务和模块化培训。 即使你不打算使用框架本身,你也可以通过 docs.abp.io 进行自己的开发,该文档已经做好了专业的准备(OpenIddict、Redis、Quartz 等)。 因为很多东西都是预先构建的,它大大缩短了项目开发时间(例如登录页面、异常处理、数据过滤、种子、审计日志、本地化、自动 API 控制器等)。 作为我们应用程序的一个示例,我使用本地事件总线进行库存控制。 因此我可以通过编写库存处理程序来管理订单移动。 不为 CreationTime,CreatorId 浪费时间真是太好了。 它们正在自动填充。", + "Pricing_Page_Testimonial_6": "ABP Framework 是一个很好的框架,但它需要时间来理解它使用的不同层、类和库(特别是 ABP)。 我花了很多时间阅读代码库,但是 ABP Commercial 为我们节省了创建项目专业实体 (AR) 和链接到每个实体的存储库的时间。 我也喜欢 ABP 中使用的方法非常成熟,我们知道它基于 DDD 和单体。", "AbpBookDownloadArea_ClaimYourEBook": "领取您的掌握ABP框架电子书", "AddMemberModal_Warning_1": "如果您尝试添加的用户名在系统中不存在,请让您的团队成员在 {0} 并与您分享他/她帐户的用户名。", "MyOrganizations_Detail_WelcomeMessage": "欢迎加入您的组织,{0}", @@ -598,7 +598,7 @@ "Purchase_PricePerDeveloper": "{0} {1} 每个开发者", "Purchase_IncludedDeveloperInfo": "{0} {1} 包括在内。", "Purchase_LicenseExtraDeveloperPurchaseMessage": "{0} 许可 包含 {1} 个开发者。 您可以现在或以后添加其他开发人员。", - "StartupTemplates_Page_Title": "启动模板", + "StartupTemplates_Page_Title": "ABP启动模板", "StartupTemplates_Page_Description": "ABP 商业版 允许您构建任何复杂程度的解决方案。 它提供了两种主要的预构建启动解决方案。 您可以选择最接近您要求的解决方案,并在此基础上构建您自己的定制解决方案。", "MicroserviceStartupSolutionForDotnet": ".NET 微服务启动解决方案", "MonolithSolutionForDotnet": ".NET 的单体(模块化)解决方案", @@ -623,12 +623,11 @@ "Faq_Page_Currency": "货币", "Faq_Page_VatNumber": "增值税号", "Faq_Page_OtherCurrenciesInfo": "对于其他货币,请参阅所有账户", - "ModuleDetail_Page_Title": "模块详细信息 - {0}", "ProjectCreatedSuccess_Page_Title": "您的项目已创建", "ProjectCreatedSuccess_Page_Description": "您的 ABP 项目创建成功!", - "Suite_Page_Title": "ABP 套件 - 创建 CRUD 页面", + "Suite_Page_Title": "ABP Suite", "Suite_Page_Description": "ABP Commercial 提供快速应用程序开发工具以提高开发人员的工作效率。 ABP 套件 允许您轻松创建 CRUD 页面。", - "Themes_Page_Title": "现代和实用的 UI 主题", + "Themes_Page_Title": "ABP主题", "Themes_Page_Description": "ABP 商业版 提供多种专业、现代的 UI 主题。 创建免费演示以快速查看 UI 的外观。", "Tools_Page_Title": "快速应用程序开发工具", "Tools_Page_Description": "ABP 商业版 提供快速应用程序开发工具以提高开发人员的工作效率。 ABP 套件 允许您轻松创建 CRUD 页面。", @@ -804,6 +803,29 @@ "UpgradePaymentInfoSection_LicenseRenewalPrice": "许可证续订", "Total": "总计", "SupportPolicyFaqTitle": "您的支持政策是什么?", - "SupportPolicyFaqExplanation": "我们只支持有效的和以前的主要版本。 我们不保证为第 3 个和更早的主要版本发布补丁。 例如,如果有效版本是 7.0.0,我们将发布 6.x.x 和 7.x.x 的补丁版本。 此外,我们仅对 ABP Framework 和 ABP Commercial 相关问题提供支持。 这意味着不支持 ABP 产品使用的第 3 方应用程序、云服务和其他外围库。 我们将尽商业上合理的努力在“Volosoft Bilisim A.S”的正式营业时间内为我们的客户提供技术支持。 另一方面,我们不承诺服务级别协议 (SLA) 响应时间,但我们会尽量在我们的官方工作时间内尽快响应技术问题。 除非与客户达成特殊协议,否则我们仅在 https://support.abp.io 上提供支持。 我们还提供私人电子邮件支持,仅适用于企业许可证持有者。" + "SupportPolicyFaqExplanation": "我们只支持有效的和以前的主要版本。 我们不保证为第 3 个和更早的主要版本发布补丁。 例如,如果有效版本是 7.0.0,我们将发布 6.x.x 和 7.x.x 的补丁版本。 此外,我们仅对 ABP Framework 和 ABP Commercial 相关问题提供支持。 这意味着不支持 ABP 产品使用的第 3 方应用程序、云服务和其他外围库。 我们将尽商业上合理的努力在“Volosoft Bilisim A.S”的正式营业时间内为我们的客户提供技术支持。 另一方面,我们不承诺服务级别协议 (SLA) 响应时间,但我们会尽量在我们的官方工作时间内尽快响应技术问题。 除非与客户达成特殊协议,否则我们仅在 https://support.abp.io 上提供支持。 我们还提供私人电子邮件支持,仅适用于企业许可证持有者。", + "TotalDevelopers": "{0}位开发者", + "CustomPurchaseExplanation": "定制您的特定需求", + "WhereDidYouHearAboutUs": "您是从哪里了解到我们的?", + "Twitter": "Twitter", + "Facebook": "Facebook", + "Youtube": "YouTube", + "Google": "Google", + "Github": "GitHub", + "Friend": "朋友介绍", + "Other": "其他", + "WhereDidYouHearAboutUs_explain": "请说明...", + "DeletingMemberWarningMessage": "\"{0}\"将从开发者列表中删除。如果您愿意,您可以将此空位分配给另一个开发者。", + "AdditionalInfo": "如果开发人员席位超出您的要求,您可以减少它们。 您可以发送电子邮件至 info@abp.io 以删除您的一些开发人员席位。 清除未使用的开发人员席位将降低许可证续订成本。 如果需要,您可以在有效许可期限内重新购买额外的开发人员席位。 请注意,由于此许可证中有 {0} 个开发人员,因此您无法减少此数量。", + "LinkExpiredErrorMessage": "您正在尝试访问的链接已过期。", + "ExpirationDate": "过期时间", + "SpringCampaignDiscount": "春季促销折扣", + "WhyUseAbpIoPlatform": "为什么我应该使用 ABP.IO 平台而不是从头开始创建新的解决方案?\n", + "WhyUseAbpIoPlatformFaqExplanation": "请参阅该文件以详细解释为什么使用ABP.IO平台比自己做所有事情有显著的优势。", + "EulaPageTitle": "最终用户许可协议(EULA)", + "PrivacyPolicyPageTitle": "隐私政策 - Cookies政策", + "TermsConditionsPageTitle": "条款和条件", + "TrainingsPageTitle": "ABP培训套餐", + "ModulesPageTitle": "ABP内置的应用模块" } } 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 f3c9575cd2..19afb1a5bb 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json @@ -192,7 +192,7 @@ "ChangingDevelopers": "我將來可以更改我組織的註冊開發人員嗎?", "ChangingDevelopersExplanation": "除了將新的開發人員添加到你的許可中之外,你還可以更改現有的開發人員(可以刪除一個開發人員並將新的開發人員添加到同一位置),而無需任何額外費用.", "WhenShouldIRenewMyLicense": "我什麽時候應該續訂我的許可?", - "WhenShouldIRenewMyLicenseExplanation": "如果您在許可證到期後 1 個月內續訂許可證,將享受以下折扣:團隊許可證 {0} ; 商業許可證 {1} ;企業許可證 {2}. 如果您在許可證到期後 1 個月續訂許可證,續訂價格將與許可證購買價格相同,並且續訂不會有折扣。", + "WhenShouldIRenewMyLicenseExplanation": "如果您在許可證到期後 {3} 天內續訂許可證,將享受以下折扣:團隊許可證 {0} ; 商業許可證 {1} ;企業許可證 {2}. 如果您在許可證到期後 {3} 天續訂許可證,續訂價格將與許可證購買價格相同,並且續訂不會有折扣。", "TrialPlan": "你們有試用計劃嗎?", "DoYouAcceptBankWireTransfer": "你們接受銀行電匯嗎?", "DoYouAcceptBankWireTransferExplanation": "是的,我們接受銀行電匯。
在通過銀行轉賬發送許可費後,將您的收據和所需的許可類型通過電子郵件發送至accounting@abp.io。 我們的國際銀行賬戶信息:", @@ -384,6 +384,24 @@ "BlazoriseLicense": "我们是否需要购买Blazorise许可证?", "BlazoriseLicenseExplanation": "我公司Volosoft和公司Megabit之间有合作协议,根据此协议,购买将同时包含了Blazorise许可证与ABP商业产品,因此我们的客户不需要再额外购买Blazorise许可证。", "discountForYears": "{0}% 折扣 {1} 年", - "BlackFridayDiscount": "黑色星期五折扣" + "BlackFridayDiscount": "黑色星期五折扣", + "OnboardingTrainingFaqTitle": "你們有 ABP 入職培訓嗎?", + "OnboardingTrainingFaqExplanation": "是的,我們有 ABP 培訓服務來幫助您快速啟動 ABP 項目。您將從 ABP 核心團隊成員那裡了解 ABP,並獲得開始您的 ABP 項目的技能。在入職培訓中,我們將解釋如何設置您的開發環境、安裝所需的工具、創建功能齊全的 CRUD 頁面。培訓將進行直播並使用 Zoom 應用程序,我們對使用其他在線會議平台持開放態度。培訓語言為英語。您也可以在會議期間提出有關 ABP 的問題。將為雙方計劃一個方便的時間和日期。要獲取更多信息,請通過 info@abp.io 聯繫我們。", + "SupportPolicyFaqTitle": "您的支持政策是什麼?", + "SupportPolicyFaqExplanation": "我們只支持活動和以前的主要版本。我們不保證為第 3 個和更早的主要版本發布補丁。例如,如果活動版本是 7.0.0,我們將發布 6.x.x 和 7.x.x 的補丁版本。此外,我們僅對 ABP Framework 和 ABP Commercial 相關問題提供支持。這意味著不支持 ABP 產品使用的第 3 方應用程序、雲服務和其他外圍庫。我們將盡商業上合理的努力,在“Volosoft Bilisim A.S”的正式營業時間內為我們的客戶提供技術支持。另一方面,我們不承諾服務級別協議 (SLA) 響應時間,但我們會盡量在我們的官方工作時間內盡快響應技術問題。除非與客戶達成特殊協議,否則我們僅在 https://support.abp.io 上提供支持。我們還提供私人電子郵件支持,僅適用於企業許可證持有者。", + "DowngradeLicensePlan": "我以後可以降級到更低的許可計劃嗎?", + "DowngradeLicensePlanExplanation": "您不能降級現有的許可計劃。但是您可以購買新的較低許可計劃並在新許可上繼續您的開發。購買較低的許可證後,您只需通過 ABP CLI 命令登錄到新的許可證計劃:`abp login -o `。", + "LicenseTransfer": "許可證可以從一個開發商轉讓給另一個開發商嗎?", + "LicenseTransferExplanation": "是的!購買許可證後,您將成為許可證持有者,因此您可以訪問組織管理頁面。組織具有所有者和開發者角色。所有者可以管理開發者席位並分配開發者。每個指定的開發人員將通過 ABP CLI 命令登錄到系統,並將擁有開發和支持權限。", + "RenewLicenseEarly": "如果我提前更新我的駕照,我會得到一整年嗎?", + "RenewLicenseEarylExplanation": "當您在許可證到期日期之前續訂許可證時,您的許可證到期日期將增加 1 年。例如,如果您的許可證在 {0}-06-06 到期,而您在 {0}-01-01 續簽,則新的許可證到期日期將為 {1}-06-06。", + "WhatHappensWhenLicenseEnds": "當我的許可期限結束時會發生什麼?", + "WhatHappensWhenLicenseEndsExplanation1": "ABP 商業許可是永久許可。許可證到期後,您可以繼續開發您的項目。而且您沒有義務更新您的許可證。您的許可證附帶開箱即用的一年更新和支持計劃。為了繼續獲得新功能、性能增強、錯誤修復、支持和繼續使用 ABP Suite,您需要更新您的許可證。當您的許可證到期時;", + "WhatHappensWhenLicenseEndsExplanation2": "您無法使用 ABP Commercial 創建新的解決方案,但您可以永遠繼續開發現有的應用程序。", + "WhatHappensWhenLicenseEndsExplanation3": "您將能夠在您的次要版本(RC 或預覽版除外)中獲取模塊和主題的更新。例如:如果您正在使用模塊的 v3.2.0,您仍然可以獲得該模塊的 v3.2.x(v3.2.1、v3.2.5...等)的更新。但是您無法獲得下一個主要或次要版本的更新(如 v3.3.0、v3.3.3、4.x.x.. 等)。比如你的license過期了,最新發布的是v4.4.3,後來又發布了4.4.4和4.5.0兩個版本,你可以訪問v4.4.X,但是你就不行了訪問 v4.5.X。", + "WhatHappensWhenLicenseEndsExplanation4": "許可證到期後,您將無法安裝添加到 ABP 商業平台的新模塊和主題。", + "WhatHappensWhenLicenseEndsExplanation5": "您不能使用 ABP 套件。", + "WhatHappensWhenLicenseEndsExplanation6": "您無法再獲得高級支持。", + "WhatHappensWhenLicenseEndsExplanation7": "如果您想繼續獲得這些好處,您可以延長(更新)您的許可證。如果您在許可到期後 {3} 天 內延長許可,將應用以下折扣:團隊許可 {0};營業執照{1};企業許可證{2}。" } -} +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json index 0264fe4e31..84c3b34110 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json @@ -187,6 +187,7 @@ "Index_Page_CommunityIntroduction": "إن هذا محور لإطار عمل ABP و.NET وتطوير البرامج. يمكنك قراءة المقالات ومشاهدة مقاطع الفيديو التعليمية والحصول على معلومات حول تقدم تطوير ABP والأحداث المتعلقة بـ ABP ومساعدة المطورين الآخرين ومشاركة خبرتك مع منتدى ABP.", "TagsInArticle": "العلامات في المقال", "WelcomeToABP": "أهلا بكم في ABP", - "IConsentToMedium": ".https://medium.com/volosoft أوافق على نشر هذا المنشور على" + "IConsentToMedium": ".https://medium.com/volosoft أوافق على نشر هذا المنشور على", + "DiscordPageTitle": "مجتمع ABP Discord" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index 8cfb154295..24d07c54bf 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -184,6 +184,9 @@ "Layout_MetaDescription": "ABP Community is an environment where people can share posts about ABP framework and follows the projects.", "Index_Page_CommunityIntroduction": "This is a hub for ABP Framework, .NET and software development. You can read the articles, watch the video tutorials, get informed about ABP’s development progress and ABP-related events, help other developers and share your expertise with the ABP community.", "TagsInArticle": "Tags in article", - "IConsentToMedium": "I consent to the publication of this post at https://medium.com/volosoft." + "IConsentToMedium": "I consent to the publication of this post at https://medium.com/volosoft.", + "SearchResultsFor": "Search results for \"{0}\"", + "SeeMoreVideos": "See more videos", + "DiscordPageTitle": "ABP Discord Community" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json index be267cebc0..d090608518 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json @@ -2,21 +2,20 @@ "culture": "fi", "texts": { "Permission:CommunityPost": "Yhteisön artikkeli", - "Permission:Edit": "Muokata", + "Permission:Edit": "Muokkaus", "Waiting": "Odottaa", "Approved": "Hyväksytty", "Rejected": "Hylätty", - "Wait": "Odota", - "Approve": "Hyväksyä", - "Reject": "Hylätä", + "Wait": "Odottaa", + "Approve": "Hyväksy", + "Reject": "Hylkää", "ReadPost": "Lue artikkeli", "Status": "Tila", "ContentSource": "Sisältölähde", "Details": "Yksityiskohdat", - "Url": "URL-osoite", "Title": "Otsikko", "CreationTime": "Luomisaika", - "Save": "Tallentaa", + "Save": "Tallenna", "SameUrlAlreadyExist": "Sama URL-osoite on jo olemassa, jos haluat lisätä tämän artikkelin, vaihda URL-osoite!", "UrlIsNotValid": "URL-osoite ei kelpaa.", "UrlNotFound": "URL-osoitetta ei löydy.", @@ -29,14 +28,12 @@ "ContributionGuide": "Contribution Guide", "BugReport": "Virhe raportti", "SeeAllPosts": "Katso kaikki viestit", - "WelcomeToABPCommunity!": "Tervetuloa ABP Community!", - "MyProfile": "Profiilini", - "MyOrganizations": "Omat organisaatiot", + "WelcomeToABP": "Tervetuloa ABP:hen", "EmailNotValid": "Ole hyvä ja syötä toimiva sähköpostiosoite.", "FeatureRequest": "Ominaisuuspyyntö", "CreatePostTitleInfo": "Viestiluettelossa näytettävän viestin nimi.", "CreatePostSummaryInfo": "Lyhyt yhteenveto viestistä, joka näytetään postituslistalla.", - "CreatePostCoverInfo": "Lisää tehokkaan artikkelin luomiseksi kansikuva. Lataa 16:9 -kuvasuhteen kuvat parhaan näkymän saamiseksi. Tiedoston enimmäiskoko: 1MB.", + "CreatePostCoverInfo": "Lisää kansikuva, jotta voit luoda tehokkaan viestin. Lataa 16:9 -kuvasuhteen kuvat parhaan näkymän saamiseksi. Tiedoston enimmäiskoko: 1MB.", "ThisExtensionIsNotAllowed": "Tätä laajennusta ei sallita.", "TheFileIsTooLarge": "Tiedosto on liian suuri.", "GoToThePost": "Siirry artikkeliin", @@ -45,7 +42,7 @@ "Done": "Tehty", "Open": "Avata", "Closed": "Suljettu", - "LatestQuestionOnThe": "Viimeisin kysymys", + "RecentQuestionFrom": "Viimeisin kysymys henkilöltä {0}", "Stackoverflow": "Pinoaminen", "Votes": "ääntä", "Answer": "Vastaus", @@ -59,7 +56,7 @@ "QuestionItemErrorMessage": "Viimeisimmät kysymystiedot Stackoverflow'sta epäonnistui.", "Oops": "Oho!", "CreatePostSuccessMessage": "Artikkeli on lähetetty onnistuneesti. Se julkaistaan sivuston järjestelmänvalvojan tarkistuksen jälkeen.", - "ChooseCoverImage": "Valitse kansikuva...", + "Browse": "Selaa", "CoverImage": "Kansikuva", "ShareYourExperiencesWithTheABPFramework": "Jaa kokemuksesi ABP-puitteista!", "Optional": "Valinnainen", @@ -80,7 +77,7 @@ "LatestGithubAnnouncements": "Viimeisimmät Github-ilmoitukset", "SeeAllAnnouncements": "Katso kaikki ilmoitukset", "LatestBlogPost": "Viimeisin blogiviesti", - "Edit": "Muokata", + "Edit": "Muokkaa", "ProfileImageChange": "Vaihda profiilikuva", "BlogItemErrorMessage": "Viimeisimpiä blogiviestitietoja ei saatu ABP: ltä.", "PlannedReleaseDate": "Suunniteltu julkaisupäivä", @@ -88,6 +85,8 @@ "PostRequestFromGithubIssue": "Artikkelipyyntöjä ei ole nyt.", "LatestPosts": "Uusimmat viestit", "ArticleRequests": "Artikkelipyynnöt", + "ArticleRequestsDescription": "Haluatko nähdä tietyn sisällön täällä? Voit pyytää yhteisöä luomaan sen!", + "LatestContentRequests": "Uusimmat sisältöpyynnöt", "AllPostRequests": "Katso kaikki artikkelipyynnöt", "SubscribeToTheNewsletter": "Tilaa uutiskirje", "NewsletterEmailDefinition": "Hanki tietoa ABP: n tapahtumista, kuten uusista julkaisuista, ilmaisista lähteistä, artikkeleista ja muusta.", @@ -102,20 +101,19 @@ "Language": "Kieli", "CreatePostLanguageInfo": "Viestin sisällön kieli.", "VideoPost": "Videoposti", - "Post": "Artikla", - "Read": "Lukea", + "Post": "Artikkeli", + "Read": "Lue", "CreateGithubPostUrlInfo": "Artikkelin alkuperäinen GitHub-URL-osoite.", - "CreateVideoContentUrlInfo": "Viestin alkuperäinen Youtube-URL-osoite.", + "CreateVideoContentUrlInfo": "Artikkelin alkuperäinen Youtube-URL-osoite.", "CreateExternalPostUrlInfo": "Artikkelin alkuperäinen ulkoinen URL-osoite.", "VideoContentForm": "Lähetä video YouTubessa", "GithubPostForm": "Lähetä artikkeli GitHubista", "ExternalPostForm": "Lähetä ulkoinen sisältö", - "HowToPost": "Kuinka lähettää?", + "HowToPost": "Kuinka lähettää viesti?", "Posts": "Viestit", "VideoUrl": "Videon URL-osoite", "GithubPostUrl": "Github-artikkelien URL-osoite", "ExternalPostUrl": "Ulkoisen artikkelin URL-osoite", - "CreatePostCoverInfo": "Lisää kansikuva, jotta voit luoda tehokkaan viestin. Lataa 16:9 -kuvasuhteen kuvat parhaan näkymän saamiseksi. Tiedoston enimmäiskoko: 1MB.", "ThankYouForContribution": "Kiitos osallistumisesta ABP Community.", "GithubPost": "Github-artikkeli", "GithubPostSubmitStepOne": "1. Kirjoita artikkeli mistä tahansa julkisesta GitHub-arkistosta Markdown-muodossa. esimerkki ", @@ -144,6 +142,50 @@ "Volo.AbpIo.Domain:060002": "Artikkelin sisältö ei ole saatavilla Githubin (\"{PostUrl}\") -resurssista.", "Volo.AbpIo.Domain:060003": "Artikkelin sisältöä ei löytynyt!", "SeeMore": "Katso Lisää", - "IConsentToMedium": "Hyväksyn tämän viestin julkaisemisen osoitteessa https://medium.com/volosoft." + "JoinTheABPCommunity": "Liity ABP-yhteisöön", + "ABPCommunityTalks": "ABP Community Talks", + "LiveDemo": "Live-demo", + "GetLicense": "Hanki lisenssi", + "GetStarted": "Aloita", + "SourceCode": "Lähdekoodi", + "LeaveComment": "Jätä kommentti", + "ShowMore": "Näytä lisää", + "NoPublishedPostsYet": "Ei vielä julkaistuja viestejä.", + "Name": "Nimi", + "Surname": "Sukunimi", + "WebSite": "Verkkosivusto", + "FullURL": "Koko URL-osoite", + "JobTitle": "Työnimike", + "Prev": "Ed", + "Previous": "Edellinen", + "Next": "Seuraava", + "Share": "Jaa", + "SortBy": "Järjestä", + "NoPublishedEventsYet": "Ei vielä julkaistuja tapahtumia.", + "SubscribeYoutubeChannel": "Tilaa Youtube-kanava", + "Enum:EventType:0": "Keskustelut", + "MemberNotPublishedPostYet": "Tämä jäsen ei ole vielä julkaissut yhtään viestiä.", + "TimeAgo": "{0} sitten", + "Discord_Page_JoinCommunityMessage": "Liity ABP Discord -yhteisöön", + "Discord_Page_Announce": "Meillä on ilo julkistaa ABP Community Discord Server!", + "Discord_Page_Description_1": "ABP-yhteisö on kasvanut ensimmäisestä päivästä lähtien. Halusimme viedä sen seuraavaan vaiheeseen luomalla virallisen ABP Discord -palvelimen, jotta ABP-yhteisö voi olla vuorovaikutuksessa toistensa kanssa käyttämällä pikaviestinnän ihmeitä.", + "Discord_Page_Description_2": "ABP Community Discord Server on paikka, jossa voit esitellä luomuksiasi ABP Frameworkin avulla, jakaa sinulle toimivia vinkkejä, saada viimeisimmät uutiset ja ilmoitukset ABP Frameworkista, keskustella vain yhteisön jäsenten kanssa ideoiden vaihtamiseksi ja pitää hauskaa!", + "Discord_Page_Description_3": "Tämä ABP Community Discord -palvelin on virallinen, ja ABP Core Team on läsnä palvelimella valvomassa.", + "Discord_Page_JoinToServer": "Liity ABP Discord Serveriin", + "Events_Page_MetaTitle": "ABP-yhteisötapahtumat", + "Events_Page_MetaDescription": "ABP-tiimin isännöimät live-ohjelmat ovat rentoja istuntoja, jotka ovat täynnä yhteisöllistä sisältöä, demoja, kysymyksiä ja vastauksia sekä keskusteluja siitä, mitä ABP:ssä tapahtuu.", + "Events_Page_Title": "ABPyhteisön keskustelut", + "Members_Page_WritingFromUser": "Lue kirjoittajan {0} kirjoitus ABP-yhteisössä.", + "Post_Create_Page_MetaTitle": "Uusi viesti", + "Post_Create_Page_MetaDescription": "Luo viestisi, jotta voit jakaa kokemuksiasi ABP-kehyksestä ja osallistua ABP-yhteisöön.", + "Post_Create_Page_CreateNewPost": "Luo uusi viesti", + "Post_Index_Page_MetaDescription": "ABP Communityn tarkoituksena on luoda osallistumisen mahdollistava ympäristö ABP-kehystä käyttäville kehittäjille.", + "Layout_Title": "{0} | ABP-yhteisö", + "Layout_MetaDescription": "ABP Community on ympäristö, jossa ihmiset voivat jakaa julkaisuja ABP-kehyksestä ja seurata projekteja.", + "Index_Page_CommunityIntroduction": "Tämä on ABP Frameworkin, .NET:n ja ohjelmistokehityksen keskus. Voit lukea artikkeleita, katsoa opetusvideoita, saada tietoa ABP:n kehityksen edistymisestä ja ABP:hen liittyvistä tapahtumista, auttaa muita kehittäjiä ja jakaa asiantuntemustasi ABP-yhteisön kanssa.", + "TagsInArticle": "Tagit artikkelissa", + "IConsentToMedium": "Hyväksyn tämän viestin julkaisemisen osoitteessa https://medium.com/volosoft.", + "SearchResultsFor": "Hakutulokset haulle \"{0}\"", + "SeeMoreVideos": "Katso lisää videoita" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json index f3b7a791c8..2d52d01ed2 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json @@ -93,7 +93,6 @@ "NoThanks": "Hayır teşekkürler", "MaybeLater": "Belki sonra", "JoinOurPostNewsletter": "Makale bültenimize katılın", - "Community": "Toplum", "Marketing": "Pazarlama", "CommunityPrivacyPolicyConfirmation": "Şartlar ve Koşullar ile Gizlilik Politikası'nı kabul ediyorum.", "PostRequestMessageTitle": "Bu web sitesinde görmek istediğiniz bir makaleyi/eğiticiyi istemek için GitHub'da bir sorun açın.", @@ -143,7 +142,6 @@ "Volo.AbpIo.Domain:060002": "Makale İçeriği Github(\"{PostUrl}\") kaynağında mevcut değil.", "Volo.AbpIo.Domain:060003": "Makale içeriği bulunamadı!", "MemberNotPublishedPostYet": "Bu üye henüz bir gönderi yayınlamadı.", - "WelcomeToABP": "ABP'ye Hoşgeldiniz", "Browse": "Göz at", "ArticleRequestsDescription": "Burada belirli bir içerik mi görmek istiyorsunuz? Topluluktan bunu oluşturmasını isteyebilirsiniz!", "LatestContentRequests": "Son İçerik Talepleri", @@ -190,6 +188,7 @@ "Layout_Title": "{0} | ABP Topluluğu", "Layout_MetaDescription": "ABP Topluluğu, insanların ABP çerçevesi hakkında paylaşımlarda bulunabileceği ve projeleri takip edebileceği bir ortamdır.", "Index_Page_CommunityIntroduction": "Burası ABP Çerçevesi, .NET ve yazılım geliştirme için bir merkezdir. Makaleleri okuyabilir, eğitim videolarını izleyebilir, ABP'nin gelişim süreci ve ABP ile ilgili etkinlikler hakkında bilgi alabilir, diğer geliştiricilere yardımcı olabilir ve uzmanlığınızı ABP topluluğu ile paylaşabilirsiniz.", - "IConsentToMedium": "Bu yazının https://medium.com/volosoft adresinde yayınlanmasına izin veriyorum." + "IConsentToMedium": "Bu yazının https://medium.com/volosoft adresinde yayınlanmasına izin veriyorum.", + "DiscordPageTitle": "ABP Discord Topluluğu" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json index d460707b70..6d2083ed76 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json @@ -13,7 +13,6 @@ "Status": "状态", "ContentSource": "内容来源", "Details": "详情", - "Url": "url", "Title": "标题", "CreationTime": "创建时间", "Save": "保存", @@ -185,6 +184,9 @@ "Layout_MetaDescription": "ABP 社区是一个人们可以分享有关 ABP 框架的帖子并关注项目的环境。", "Index_Page_CommunityIntroduction": "这是 ABP 框架、.NET 和软件开发的中心。 您可以阅读文章,观看视频教程,了解 ABP 的开发进度和 ABP 相关事件,帮助其他开发人员并与 ABP 社区分享您的专业知识。", "TagsInArticle": "文章中的标签", - "IConsentToMedium": "我同意在 https://medium.com/volosoft 上发布这篇文章。" + "IConsentToMedium": "我同意在 https://medium.com/volosoft 上发布这篇文章。", + "SearchResultsFor": " span class=\"fw-bold\">\"{0}\"的搜索结果", + "SeeMoreVideos": "查看更多视频", + "DiscordPageTitle": "ABP Discord社区" } -} +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/fi.json new file mode 100644 index 0000000000..201c63e800 --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/fi.json @@ -0,0 +1,6 @@ +{ + "culture": "fi", + "texts": { + "Buy": "Osta" + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hans.json index df772fa60b..2bbfd5b749 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hans.json @@ -1,5 +1,6 @@ { "culture": "zh-Hans", "texts": { + "Buy": "购买" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/fi.json new file mode 100644 index 0000000000..87bd42a2cd --- /dev/null +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/fi.json @@ -0,0 +1,6 @@ +{ + "culture": "fi", + "texts": { + "FAQ": "FAQ" + } +} \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json index 791062cfbc..592665c698 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json @@ -404,6 +404,9 @@ "SeeTheScreenshot": "انظر الى الصورة", "Details": "التفاصيل", "ApplicationModuleExplanation1": "إنشاء حل وحدة تطبيق ذات طبقات كاملة وقابلة لإعادة الاستخدام.", - "ApplicationModuleExplanation2": "يمكنك استخدام هذا الخيار لإنشاء وحدات نمطية لتطبيقك المعياري." + "ApplicationModuleExplanation2": "يمكنك استخدام هذا الخيار لإنشاء وحدات نمطية لتطبيقك المعياري.", + "CreateSolutionFolder": "إنشاء مجلد الحل", + "CreateSolutionFolderOption": "يحدد ما إذا كان المشروع سيكون في مجلد جديد في مجلد الإخراج أو مجلد الإخراج مباشرة.", + "BooksPageTitle": "كتب ABP" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/cs.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/cs.json index 636bdf818f..7fa321b7b9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/cs.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/cs.json @@ -274,7 +274,8 @@ "FirstEdition": "První vydání", "ThankYou": "Děkuji!", "CheckboxMandatory": "Chcete-li pokračovat, musíte toto zaškrtnout!", - "SelectUITheme": "Vyberte téma uživatelského rozhraní" - + "SelectUITheme": "Vyberte téma uživatelského rozhraní", + "CreateSolutionFolder": "Vytvořit složku řešení", + "CreateSolutionFolderOption": "Určuje, zda bude projekt v nové složce ve výstupní složce nebo přímo výstupní složce." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/de.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/de.json index f978fb8784..28821200c8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/de.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/de.json @@ -274,7 +274,8 @@ "FirstEdition": "Erste Ausgabe", "ThankYou": "Dankeschön!", "CheckboxMandatory": "Sie müssen dies überprüfen, um fortzufahren!", - "SelectUITheme": "Wählen Sie UI-Design aus" - + "SelectUITheme": "Wählen Sie UI-Design aus", + "CreateSolutionFolder": "Lösungsordner erstellen", + "CreateSolutionFolderOption": "Gibt an, ob sich das Projekt in einem neuen Ordner im Ausgabeordner oder direkt im Ausgabeordner befindet." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index 35698cd39c..63e795efee 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -416,6 +416,9 @@ "CompanyInfo": "Company Info", "Date": "Date", "WhoWeAre_Partner": "Who We Are", - "WhoWeAre_Expert": "About Me" + "WhoWeAre_Expert": "About Me", + "CreateSolutionFolder": "Create Solution Folder", + "CreateSolutionFolderOption": "Specifies if the project will be in a new folder in the output folder or directly the output folder.", + "BooksPageTitle": "ABP Books" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/es.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/es.json index f63600d48a..88f28ede88 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/es.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/es.json @@ -274,7 +274,8 @@ "FirstEdition": "Primera edición", "ThankYou": "¡Gracias!", "CheckboxMandatory": "¡Debes marcar esto para continuar!", - "SelectUITheme": "Seleccione el tema de la interfaz de usuario" - + "SelectUITheme": "Seleccione el tema de la interfaz de usuario", + "CreateSolutionFolder": "Crear carpeta de soluciones", + "CreateSolutionFolderOption": "Especifica si el proyecto estará en una nueva carpeta en la carpeta de salida o directamente en la carpeta de salida." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fi.json index bcfa1901a6..c41f58399d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fi.json @@ -2,7 +2,7 @@ "culture": "fi", "texts": { "GetStarted": "Aloitus - Käynnistysmallit", - "Create": "Luoda", + "Create": "Luo", "NewProject": "Uusi projekti", "DirectDownload": "Suora lataus", "ProjectName": "Projektin nimi", @@ -14,7 +14,7 @@ "CreateNow": "Luo nyt", "TheStartupProject": "Käynnistysprojekti", "Tutorial": "Opetusohjelma", - "UsingCLI": "CLI: n käyttö", + "UsingCLI": "CLI:n käyttö", "SeeDetails": "Katso yksityiskohdat", "AbpShortDescription": "ABP Framework on täydellinen infrastruktuuri nykyaikaisten verkkosovellusten luomiseen noudattamalla ohjelmistokehityksen parhaita käytäntöjä ja käytäntöjä.", "SourceCodeUpper": "LÄHDEKOODI", @@ -23,9 +23,9 @@ "Architecture": "Arkkitehtuuri", "Modular": "Modulaarinen", "DontRepeatYourself": "Älä toista itseäsi", - "DeveloperFocused": "Kehittäjä kohdennettu", - "FullStackApplicationInfrastructure": "Täyden pinon sovellusinfrastruktuuri.", - "DomainDrivenDesign": "Toimialueohjattu suunnittelu", + "DeveloperFocused": "Kehittäjä-kohdennettu", + "FullStackApplicationInfrastructure": "Full stack sovellusinfrastruktuuri.", + "DomainDrivenDesign": "Domain Driven Design", "DomainDrivenDesignExplanation": "Suunniteltu ja kehitetty DDD-mallien ja -periaatteiden perusteella. Tarjoaa kerrostetun mallin sovelluksellesi.", "Authorization": "Valtuutus", "AuthorizationExplanation": "Edistynyt käyttöoikeudet käyttäjän, roolin ja tarkan käyttöjärjestelmän avulla. Rakennettu Microsoft Identity -kirjastoon.", @@ -64,7 +64,7 @@ "TransactionManagement": "Tapahtumien hallinta", "AuditLogging": "Tarkastusten kirjaaminen", "Caching": "Välimuisti", - "Multitenancy": "Monivärinen", + "Multitenancy": "Monivuokraus", "DataFiltering": "Tietojen suodatus", "ConventionOverConfiguration": "Kokoonpanon määritys", "ConventionOverConfigurationExplanation": "ABP toteuttaa oletusarvoisesti yleiset sovelluskäytännöt minimaalisella tai nolla-kokoonpanolla.", @@ -136,8 +136,8 @@ "ValueObject": "Arvo-objekti", "ApplicationService": "Sovelluspalvelu", "DataTransferObject": "Tiedonsiirtokohde", - "AggregateRootEntity": "Kokonaisjuuri, entiteetti", - "AutoRESTAPIsExplanation": "ABP voi määrittää sovelluspalvelut automaattisesti API-ohjaimiksi sopimuksen mukaan.", + "AggregateRootEntity": "Aggregate Root, entiteetti", + "AutoRESTAPIsExplanation": "ABP voi määrittää sovelluspalvelut automaattisesti API-kontrollereiksi sopimuksen mukaan.", "DynamicClientProxiesExplanation": "Kuluta helposti API: si JavaScript- ja C# -asiakkailta.", "DistributedEventBusWithRabbitMQIntegrationExplanation": "Julkaise ja kuluta jaettuja tapahtumia helposti käyttämällä sisäänrakennettua hajautettua tapahtumaväylää, jossa on käytettävissä RabbitMQ-integraatio.", "TestInfrastructureExplanation": "Kehys on kehitetty yksikkö- ja integraatiotestaus ajatellen. Tarjoaa sinulle perusluokkia helpottamaan. Käynnistysmalleissa on valmiiksi konfiguroitu testaus.", @@ -159,9 +159,9 @@ "UiFramework": "Käyttöliittymäkehys", "EmailAddress": "Sähköpostiosoite", "Mobile": "Matkapuhelin", - "ReactNative": "Reagoi Native", + "ReactNative": "React Native", "Strong": "Vahva", - "Complete": "Saattaa loppuun", + "Complete": "Valmis", "BasedLayeringModel": "Perustuva kerrosmalli", "Microservice": "Mikropalvelu", "Compatible": "Yhteensopiva", @@ -172,8 +172,9 @@ "DynamicClientProxyDocument": "Katso dynaamisen asiakkaan välityspalvelimen dokumentaatiot JavaScript ja C#.", "EmailSMSAbstractionsDocument": "Katso lisätietoja sähköpostitse ja tekstiviestien lähettäminen -asiakirjoista.", "CreateProjectWizard": "Tämä ohjattu toiminto luo uuden projektin käynnistysmallista, joka on määritetty oikein aloittamaan projekti.", - "TieredOption": "Luo porrastetun ratkaisun, jossa Web- ja Http-API-kerrokset erotetaan fyysisesti. Jos sitä ei ole valittu, luodaan kerrostettu ratkaisu, joka on vähemmän monimutkainen ja sopii useimpiin tilanteisiin.", + "TieredOption": "Luo monikerros ratkaisun, jossa Web- ja Http-API-kerrokset erotetaan fyysisesti. Jos sitä ei ole valittu, luodaan kerrostettu ratkaisu, joka on vähemmän monimutkainen ja sopii useimpiin tilanteisiin.", "SeparateIdentityServerOption": "Erottaa palvelinpuolen kahteen sovellukseen: Ensimmäinen on identiteettipalvelimelle ja toinen palvelinpuolen HTTP-sovellusliittymälle.", + "ProgressiveWebApplicationOption": "Määrittää projektin progressiiviseksi verkkosovellukseksi (PWA)", "UseslatestPreVersion": "Käyttää uusinta julkaisua edeltävää versiota", "ReadTheDocumentation": " Lue Dokumentaatio ", "Documentation": "Dokumentointi", @@ -214,7 +215,11 @@ "SeeDocs": "Katso Docs", "None": "Ei mitään", "Application": "Sovellus", + "ApplicationExplanation": "Luo täysin kerrostetun ratkaisun, joka perustuu Domain Driven Design -käytäntöihin. Suositellaan pitkäaikaisiin projekteihin, jotka tarvitsevat ylläpidettävän ja laajennettavan koodikannan.", + "ApplicationNoLayer": "Sovellus (yksi kerros)", + "ApplicationNoLayerExplanation": "Luo yksikerroksisen verkkosovelluksen. Suositellaan yksinkertaisemman ja helposti ymmärrettävän arkkitehtuurin sovelluksen rakentamiseen.", "Module": "Moduuli", + "ModuleExplanation": "Luo uudelleenkäytettävän, täysin kerrostetun sovellusmoduuliratkaisun. Voit käyttää tätä vaihtoehtoa luodaksesi moduuleja modulaariselle sovelluksellesi.", "PackageName": "Paketin nimi", "LicenseURL": "Lisenssin URL-osoite", "License": "Lisenssi", @@ -274,7 +279,145 @@ "FirstEdition": "Ensimmäinen painos", "ThankYou": "Kiitos!", "CheckboxMandatory": "Sinun on tarkistettava tämä jatkaaksesi!", - "SelectUITheme": "Valitse käyttöliittymän teema" - + "CreateSolutionFolder": "Luo ratkaisukansio", + "CreateSolutionFolderOption": "Määrittää, onko projekti tuloskansion uudessa kansiossa vai suoraan tulostekansiossa.", + "UserInterface": "Käyttöliittymä", + "APIGateway": "API-yhdyskäytävä", + "Database": "Tietokanta", + "Saas": "Saas", + "OpenSourceWebApp": "Avoimen lähdekoodin
verkkosovellus", + "Framework": "Framework", + "AuditLoggingExplanation": "Seuraa automaattisesti kaikkia järjestelmäsi toimintoja ja tietojen muutoksia.", + "AbpNewCommandExplanation": "Luo uusia ratkaisuja käyttämällä ABP-käynnistysmalleja.", + "AbpAddModuleCommandExplanation": "Asenna valmiiksi rakennetut sovellusmoduulit ratkaisuusi", + "AbpUpdateCommandExplanation": "Päivittää automaattisesti kaikki ABP:hen liittyvät NuGet- ja NPM-paketit ratkaisussasi.", + "ExploreAllCLICommands": "Tutustu kaikkiin CLI-komentoihin", + "ExploreDocumentationAndGuides": "Tutustu kattavaan dokumentaatioon ja oppaisiin.", + "Documentations": "Dokumentointi", + "Views": "Näkymät", + "EnterYouEmailToGetNews": "Kirjoita sähköpostiosoitteesi saadaksesi viimeisimmät uutiset ABP Frameworkista", + "Tiered": "Monikerros", + "SeparateIdentityServer": "Erillinen identiteettipalvelin", + "ProgressiveWebApplication": "Progressiivinen verkkosovellus", + "Preview": "Esikatsele", + "CreateANewSolution": "Luo uusi ratkaisu", + "ABPFrameworkFeatures": "ABP-kehyksen Ominaisuudet", + "Commercial": "Kaupallinen", + "ThirdPartyTools": "Kolmannen osapuolen työkalut", + "Back": "Takaisin", + "Community": "Yhteisö", + "SeeMore": "Katso lisää", + "DetailsOfTheEBook": "E-kirjan tiedot", + "JoinOurMarketingNewsletter": "Liity markkinointiuutiskirjeeseemme", + "FrameworkNewsletterConfirmationMessage": "Hyväksyn käyttöehdot ja tietosuojakäytäntö.", + "GetYourFreeEBook": "Hanki ilmainen DDD-e-kirjasi ", + "EverythingYouNeedToKnow": "Kaikki mitä sinun tarvitsee tietää.", + "PreOrderNow": "Ennakkotilaa nyt", + "UITheming": "UI Theming", + "UIThemingExplanation": "Luo uudelleenkäytettäviä käyttöliittymäteemoja ja asetteluja tai käytä jotakin valmiista käyttöliittymäteemoista.", + "DataFilteringExplanation2": "Suodata automaattisesti tietokannan kyselyt toteuttaaksesi helposti malleja, kuten pehmeän poiston ja usean vuokrauksen.", + "NeedHelp": "Tarvitsetko apua?", + "GiveYourProjectAName": "Anna projektillesi nimi", + "SelectProjectType": "Valitse Projektin tyyppi", + "SelectUIFramework": "Valitse UI Framework", + "SelectDatabaseProvider": "Valitse Tietokannan tarjoaja", + "SelectDatabaseManagementSystem": "Valitse Tietokannan hallintajärjestelmä", + "InstallingTheABPCLI": "ABP CLI:n asentaminen", + "CreateYourProjectNow": "Luo projektisi nyt", + "OrderOn": "Tilaa {0}", + "DownloadFreeDDDBook": "Lataa ilmainen DDD-kirja", + "WhatIsABPFramework": "Mikä on ABP-kehys?", + "TenantDatabase": "Vuokralaisen {0} tietokanta", + "SharedDatabase": "Jaettu tietokanta", + "ConnectionResolver": "Yhteyden ratkaisija", + "TenantBasedDataFilter": "Vuokralaispohjainen tietosuodatin", + "ApplicationCode": "Sovelluskoodi", + "TenantResolution": "Vuokralaisen päättely", + "TenantUser": "Vuokralaisen {0} käyttäjä", + "CardTitle": "Kortin otsikko", + "View": "Näytä", + "Model": "Malli", + "Email": "Sähköposti", + "Password": "Salasana", + "Address": "Osoite", + "Gender": "Sukupuoli", + "Male": "Mies", + "Female": "Nainen", + "Submit": "Lähetä", + "Unspecified": "Määrittelemätön", + "StaticFileMiddleware": "Staattisen tiedoston väliohjelmisto", + "RazorViewEngine": "Razor View Engine", + "PhysicalFiles": "Fyysiset tiedostot (wwwroot)", + "EmbeddedFiles": "Upotetut tiedostot (DLL)", + "DynamicFiles": "Dynaamiset tiedostot (muisti)", + "BuildSolutionsWithAbp": "Rakenna ylläpidettäviä .NET-ratkaisuja noudattamalla ohjelmistokehityksen parhaita käytäntöjä käyttämällä ABP:tä.", + "BuyOnAmazon": "Osta Amazonista", + "BuyOnPackt": "Osta Packtista", + "Discounted": "Alennettu", + "MasteringAbpFramework_Book_KeyFeatures": "Avainominaisuudet", + "MasteringAbpFramework_Book_Key_Features_Description_1": "Luo kestäviä, ylläpidettäviä, modulaarisia ja skaalautuvia ohjelmistoratkaisuja ABP Frameworkin avulla.", + "MasteringAbpFramework_Book_Key_Features_Description_2": "Opi toteuttamaan SOLID-periaatteita ja verkkotunnuslähtöistä suunnittelua verkkosovelluksissasi.", + "MasteringAbpFramework_Book_Key_Features_Description_3": "Tutustu kuinka ABP Framework nopeuttaa kehityssykliäsi automatisoimalla toistuvia tehtäviä.", + "MasteringAbpFramework_Book_Description": "Kirjan kuvaus", + "MasteringAbpFramework_Book_Description_Details_1": "ABP Framework on täydellinen infrastruktuuri nykyaikaisten verkkosovellusten luomiseen seuraavilla ohjelmistoilla\n parhaiden käytäntöjen ja käytäntöjen kehittäminen. ABP:n korkean tason kehyksen ja ekosysteemin avulla voit\n ottaa käyttöön Älä toista itseäsi (DRY) -periaatteen ja keskittyä liiketoimintakoodiisi.", + "MasteringAbpFramework_Book_Description_Details_2": "Tämä ABP Frameworkin luojan kirjoittama kirja auttaa sinua saamaan täydellisen käsityksen\n frameworkista ja modernit verkkosovellusten kehitystekniikat. Vaiheittaisilla selityksillä olennaisista\n käsitteitä ja käytännön esimerkeistä, ymmärrät nykyaikaisen verkkoratkaisun vaatimukset ja kuinka ABP\n Framework tekee omien ratkaisujen kehittämisestä miellyttävää. Löydät yleiset vaatimukset\n yritysverkkosovellusten kehittämiseen ja ABP:n tarjoamaan infrastruktuuriin tutustumiseen. Läpi\n kirjan, opit ohjelmistokehityksen parhaita käytäntöjä ylläpidettävien ja modulaaristen verkkosovellusten rakentamiseen.", + "MasteringAbpFramework_Book_Description_Details_3": "Tämän kirjan luettuasi pystyt luomaan täydellisen verkkoratkaisun, jota on helppo kehittää,\n huoltaa ja testata.", + "MasteringAbpFramework_Book_WhatYouWillLearn": "Mitä opit", + "MasteringAbpFramework_Book_What_You_Will_Learn_1": "Määritä kehitysympäristö ja aloita ABP Frameworkin käyttö.", + "MasteringAbpFramework_Book_What_You_Will_Learn_2": "Työskentele Entity Framework Coren ja MongoDB:n kanssa kehittääksesi tiedon käyttökerroksesi.", + "MasteringAbpFramework_Book_What_You_Will_Learn_3": "Ymmärrä monialaiset huolenaiheet ja kuinka ABP automatisoi toistuvia tehtäviä.", + "MasteringAbpFramework_Book_What_You_Will_Learn_4": "Ota hallintaan toimialuelDomain Driven Design -ähtöisen suunnittelun toteuttaminen ABP Frameworkin avulla.", + "MasteringAbpFramework_Book_What_You_Will_Learn_5": "Rakenna käyttöliittymäsivuja ja komponentteja ASP.NET Core MVC:llä (Razor Pages) ja Blazorilla.", + "MasteringAbpFramework_Book_What_You_Will_Learn_6": "Työskentele monivuokrauksen kanssa modulaaristen verkkosovellusten luomiseksi.", + "MasteringAbpFramework_Book_What_You_Will_Learn_7": "Ymmärrä modulaarisuus ja luo uudelleenkäytettäviä sovellusmoduuleja.", + "MasteringAbpFramework_Book_What_You_Will_Learn_8": "Kirjoita yksikkö-, integrointi- ja käyttöliittymätestejä ABP Frameworkin avulla.", + "MasteringAbpFramework_Book_WhoIsThisBookFor": "Kenelle tämä kirja on tarkoitettu", + "MasteringAbpFramework_Book_WhoIsThisBookFor_Description": "Tämä kirja on tarkoitettu verkkokehittäjille, jotka haluavat oppia ohjelmistoarkkitehtuureja ja parhaita käytäntöjä\n ylläpidettävien web-pohjaisten ratkaisujen kehittämiseen Microsoft-tekniikoilla ja ABP Frameworkilla. C#:n\n ja ASP.NET Core: perustiedot tarvitaan tätä kirjaa luettaessa.", + "ComputersAndTechnology": "Tietokoneet ja tekniikka", + "BuildingMicroserviceSolutions": "Building Microservice Solutions", + "MicroserviceBookPracticalGuide": "Tämä kirja on opas mikropalvelupohjaisten sovellusten kehittämiseen ja hallintaan ABP-kehyksen avulla. Siinä viitataan .NET Microservice Sample Reference Application: eShopOnContainers -sovellukseen ja käsitellään ABP Frameworkia käyttäviä arkkitehtonisia suunnittelu- ja toteutusmenetelmiä. Tämän kirjan loppuun mennessä opit, kuinka ABP lähestyy yleisiä mikropalveluiden monimutkaisia ongelmia, kuten valtuutusta, hajautettuja tapahtumia, mikropalvelujen välistä viestintää, käyttöönottoa jne.", + "IntroducingTheSolution": "Esittelyssä eShopOnAbp-ratkaisu", + "RunningTheSolution": "Ratkaisun suorittaminen", + "UnderstandingTheAuthenticationSystem": "Todennusjärjestelmän ymmärtäminen", + "ExploringTheApplications": "Sovellusten tutkiminen", + "UnderstandingTheAPIGateways": "API-yhdyskäytävien ymmärtäminen", + "DevelopingTheMicroservices": "Mikropalveluiden kehittäminen", + "UnderstandingTheInfrastructure": "Infrastruktuurin ymmärtäminen", + "DiggingInTheUseCases": "Käyttötapausten kuvaaminen", + "DeployingTheSolution": "Ratkaisun käyttöönotto", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "Tämä kirja on luonnosvaiheessa eikä ole vielä valmis.", + "Authors": "Tekijät", + "MicroserviceEBook": "Microservice E-Book", + "SelectUITheme": "Valitse käyttöliittymän teema", + "LeptonXLiteTheme": "LeptonX Lite -teema", + "BasicTheme": "Perusteema", + "LeptonXLiteThemeInfo": " Moderni ja tyylikäs Bootstrap-käyttöliittymäteema. Ihanteellinen, jos haluat tuotantovalmiin käyttöliittymäteeman. Tämä on uusin teema ja oletuksena.", + "BasicThemeInfo": "Minimalistinen käyttöliittymäteema tavallisilla Bootstrap-väreillä ja -tyyleillä. Ihanteellinen, jos rakennat oman käyttöliittymäteeman.", + "SeeDocumentation": "Katso dokumentaatio.", + "SeeFullScreen": "🖼️ Katso kuvakaappaus", + "BuildingMicroserviceSolutionsShortDescription": "Tämä kirja on opas mikropalvelupohjaisten sovellusten kehittämiseen ja hallintaan ABP-kehyksen avulla.", + "InstallAbpCliMessage": "Asenna ABP CLI komentoriviltä, jos et ole asentanut sitä aiemmin:", + "Terminal": "Terminaali", + "Copy": "Kopio", + "RunTheFollowingCommand": "Suorita seuraava komento komentorivillä:", + "ChangeSolutionOptionsBelow": "Voit muuttaa alla olevia ratkaisuvaihtoehtoja.", + "MultiLayerApplication": "Monikerroksinen sovellus", + "MultiLayerApplicationExplanation1": "Luo täysin kerrostetun ratkaisun, joka perustuu Domain Driven Designin käytäntöihin.", + "MultiLayerApplicationExplanation2": "Suositellaan pitkäaikaisiin projekteihin, jotka tarvitsevat ylläpidettävän ja laajennettavan koodikannan.", + "SingleLayerApplication": "Single-layer
sovellus", + "SingleLayerApplicationExplanation1": "Luo yksikerroksisen verkkosovelluksen.", + "SingleLayerApplicationExplanation2": "Suositellaan yksinkertaisemman ja helposti ymmärrettävän arkkitehtuurin sovelluksen rakentamiseen.", + "ApplicationModule": "Sovellus
moduuli", + "SeeTheScreenshot": "Katso kuvakaappaus", + "ApplicationModuleExplanation1": "Luo uudelleenkäytettävän, täysin kerrostetun sovellusmoduuliratkaisun.", + "ApplicationModuleExplanation2": "Voit käyttää tätä vaihtoehtoa luodaksesi moduuleja modulaariselle sovelluksellesi.", + "Expert_": "Asiantuntija", + "Partner_": "Kumppanuus", + "WebSite": "Verkkosivusto", + "Expert_Year": "Asiantuntijavuosi", + "CompanyInfo": "Yritystiedot", + "Date": "Päivämäärä", + "WhoWeAre_Partner": "Keitä olemme", + "WhoWeAre_Expert": "Minusta" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fr.json index 90314de979..e66bc4082a 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/fr.json @@ -274,7 +274,8 @@ "FirstEdition": "Première édition", "ThankYou": "Merci!", "CheckboxMandatory": "Vous devez vérifier cela pour continuer !", - "SelectUITheme": "Sélectionnez le thème de l'interface utilisateur" - + "SelectUITheme": "Sélectionnez le thème de l'interface utilisateur", + "CreateSolutionFolder": "Créer un dossier de solutions", + "CreateSolutionFolderOption": "Spécifie si le projet sera dans un nouveau dossier dans le dossier de sortie ou directement dans le dossier de sortie." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hi.json index 35232cf828..1b4bd1c879 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hi.json @@ -274,7 +274,8 @@ "FirstEdition": "प्रथम संस्करण", "ThankYou": "शुक्रिया!", "CheckboxMandatory": "आगे बढ़ने के लिए आपको इसे जांचना होगा!", - "SelectUITheme": "यूआई थीम का चयन करें" - + "SelectUITheme": "यूआई थीम का चयन करें", + "CreateSolutionFolder": "समाधान फ़ोल्डर बनाएँ", + "CreateSolutionFolderOption": "निर्दिष्ट करता है कि प्रोजेक्ट आउटपुट फ़ोल्डर या सीधे आउटपुट फ़ोल्डर में एक नए फ़ोल्डर में होगा या नहीं।" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hu.json index 2a6ebf2feb..a3f4d84e26 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hu.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/hu.json @@ -392,6 +392,8 @@ "LeptonXLiteThemeInfo": "Modern és stílusos Bootstrap UI téma. Ideális, ha gyártásra kész felhasználói felület témát szeretne. Ez a legújabb téma, és az alapértelmezett.", "BasicThemeInfo": "Minimalista felhasználói felület téma egyszerű Bootstrap színekkel és stílusokkal. Ideális, ha saját felhasználói felület témát készít.", "SeeDocumentation": "Lásd a dokumentációt .", - "SeeFullScreen": "🖼️ Nézze meg a képernyőképet" + "SeeFullScreen": "🖼️ Nézze meg a képernyőképet", + "CreateSolutionFolder": "Hozzon létre megoldási mappát", + "CreateSolutionFolderOption": "Meghatározza, hogy a projekt egy új mappában legyen-e a kimeneti mappában vagy közvetlenül a kimeneti mappában." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/is.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/is.json index f3449c4798..15941b2f20 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/is.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/is.json @@ -274,7 +274,8 @@ "FirstEdition": "Fyrsta útgáfa", "ThankYou": "Þakka þér!", "CheckboxMandatory": "Þú þarft að smella hér til að halda áfram!", - "SelectUITheme": "Veldu UI þema" - + "SelectUITheme": "Veldu UI þema", + "CreateSolutionFolder": "Búðu til lausnarmöppu", + "CreateSolutionFolderOption": "Tilgreinir hvort verkefnið verður í nýrri möppu í úttaksmöppunni eða beint í framleiðslumöppunni." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/it.json index 2e37c54280..5cc16b4646 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/it.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/it.json @@ -274,7 +274,8 @@ "FirstEdition": "Prima Edizione", "ThankYou": "Grazie!", "CheckboxMandatory": "Devi mettere la spunta su questo per procedere!", - "SelectUITheme": "Seleziona Tema dell'interfaccia utente" - + "SelectUITheme": "Seleziona Tema dell'interfaccia utente", + "CreateSolutionFolder": "Crea cartella della soluzione", + "CreateSolutionFolderOption": "Specifica se il progetto si troverà in una nuova cartella nella cartella di output o direttamente nella cartella di output." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/nl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/nl.json index eb3ac12a86..4bc2cffb2a 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/nl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/nl.json @@ -274,7 +274,8 @@ "FirstEdition": "Eerste editie", "ThankYou": "Bedankt!", "CheckboxMandatory": "Je moet dit aanvinken om verder te gaan!", - "SelectUITheme": "Selecteer UI-thema" - + "SelectUITheme": "Selecteer UI-thema", + "CreateSolutionFolder": "Oplossingsmap maken", + "CreateSolutionFolderOption": "Geeft aan of het project zich in een nieuwe map in de uitvoermap bevindt of direct in de uitvoermap." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pl-PL.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pl-PL.json index 1adc7b009f..cb33d69ab6 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pl-PL.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pl-PL.json @@ -274,7 +274,8 @@ "FirstEdition": "Pierwsza edycja", "ThankYou": "Dziękuję Ci!", "CheckboxMandatory": "Musisz to sprawdzić, aby kontynuować!", - "SelectUITheme": "Wybierz motyw interfejsu" - + "SelectUITheme": "Wybierz motyw interfejsu", + "CreateSolutionFolder": "Utwórz folder rozwiązania", + "CreateSolutionFolderOption": "Określa, czy projekt znajdzie się w nowym folderze w folderze wyjściowym, czy bezpośrednio w folderze wyjściowym." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json index 75fc4d8864..b468c06403 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json @@ -274,7 +274,8 @@ "FirstEdition": "Primeira edição", "ThankYou": "Obrigado!", "CheckboxMandatory": "Você precisa verificar isso para continuar!", - "SelectUITheme": "Selecione o tema da interface do usuário" - + "SelectUITheme": "Selecione o tema da interface do usuário", + "CreateSolutionFolder": "Criar Pasta de Solução", + "CreateSolutionFolderOption": "Especifica se o projeto estará em uma nova pasta na pasta de saída ou diretamente na pasta de saída." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json index e91664d726..003309aa74 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json @@ -275,7 +275,7 @@ "ThankYou": "Vă mulţumim!", "CheckboxMandatory": "Trebuie să bifaţi asta pentru a continua!", "SelectUITheme": "Selectați Tema UI", - - + "CreateSolutionFolder": "Creați folderul de soluții", + "CreateSolutionFolderOption": "Specifică dacă proiectul va fi într-un folder nou în folderul de ieșire sau direct folderul de ieșire." } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ru.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ru.json index 05378ac5e1..8df80b7422 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ru.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ru.json @@ -274,6 +274,8 @@ "FirstEdition": "Первое издание", "ThankYou": "Спасибо!", "CheckboxMandatory": "Вам необходимо проверить это, чтобы продолжить!", - "SelectUITheme": "Выберите тему пользовательского интерфейса" + "SelectUITheme": "Выберите тему пользовательского интерфейса", + "CreateSolutionFolder": "Создать папку решения", + "CreateSolutionFolderOption": "Указывает, будет ли проект находиться в новой папке в выходной папке или непосредственно в выходной папке." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sk.json index a7cdab3afd..f578158624 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sk.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sk.json @@ -274,7 +274,8 @@ "FirstEdition": "Prvá edícia", "ThankYou": "Ďakujem!", "CheckboxMandatory": "Ak chcete pokračovať, musíte to skontrolovať!", - "SelectUITheme": "Vyberte tému používateľského rozhrania" - + "SelectUITheme": "Vyberte tému používateľského rozhrania", + "CreateSolutionFolder": "Vytvorte priečinok riešení", + "CreateSolutionFolderOption": "Určuje, či bude projekt v novom priečinku vo výstupnom priečinku alebo priamo vo výstupnom priečinku." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sl.json index b7a60ef904..c7a1f495f2 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/sl.json @@ -274,7 +274,8 @@ "FirstEdition": "Prva izdaja", "ThankYou": "Hvala vam!", "CheckboxMandatory": "Za nadaljevanje morate to preveriti!", - "SelectUITheme": "Izberite temo uporabniškega vmesnika" - + "SelectUITheme": "Izberite temo uporabniškega vmesnika", + "CreateSolutionFolder": "Ustvarite mapo rešitev", + "CreateSolutionFolderOption": "Podaja, ali bo projekt v novi mapi v izhodni mapi ali neposredno v izhodni mapi." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json index 969bd72694..dcc04e9f79 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json @@ -1,7 +1,7 @@ { "culture": "tr", "texts": { - "GetStarted": "Başlamak - Başlangıç Templateleri", + "GetStarted": "Başlangıç Şablonları", "Create": "Oluştur", "NewProject": "Yeni Proje", "DirectDownload": "Doğrudan İndir", @@ -82,7 +82,7 @@ "CLI_CommandLineInterface": "CLI (Command Line Interface)", "CLI_CommandLineInterfaceExplanation": "CLI yeni proje oluşturma ve uygulamanıza modüller ekleme işlemlerini otomatik hale getirir.", "StartupTemplates": "Başlangıç Templateler", - "StartupTemplatesExplanation": "Çeşitli başlangıç templateleri size geliştirme başlatmak için tam yapılandırılmış bir çözüm sağlar.", + "StartupTemplatesExplanation": "Çeşitli başlangıç şablonları size geliştirme başlatmak için tam yapılandırılmış bir çözüm sağlar.", "BasedOnFamiliarTools": "Bilinen Araçlara Dayalı ", "BasedOnFamiliarToolsExplanation": "Zaten bildiğiniz popüler araçlar ile geliştirilme ve egtegre edilmiştir. Düşük öğrenme eğrisi, koaly adaptasyon, rahat geliştirme.", "ORMIndependent": "ORM Bağımsız", @@ -139,8 +139,8 @@ "AggregateRootEntity": "Aggregate Root, Entity", "AutoRESTAPIsExplanation": "ABP, application servislerinizi otomatik olarak API Controller olarak kurallı bir şekilde yapılandırabilir.", "DynamicClientProxiesExplanation": "Apilerinizi, JavaScript ve C# clients tarafından kolaylıkla kullanın.", - "DistributedEventBusWithRabbitMQIntegrationExplanation": "Easily publish & consume distributed events using built-in Distributed Event Bus with RabbitMQ integration available.", - "TestInfrastructureExplanation": "The framework has been developed unit & integration testing in mind. Provides you base classes to make it easier. Startup templates come with pre-configured for testing.", + "DistributedEventBusWithRabbitMQIntegrationExplanation": "RabbitMQ entegrasyonu ile yerleşik Dağıtılmış Event Bus kullanarak dağıtılmış olayları kolayca yayınlayın ve tüketin.", + "TestInfrastructureExplanation": "Çerçeve, birim ve entegrasyon testleri göz önünde bulundurularak geliştirilmiştir. İşinizi kolaylaştırmak için size temel sınıflar sağlar. Başlangıç şablonları test için önceden yapılandırılmış olarak gelir.", "AuditLoggingEntityHistoriesExplanation": "İş açısından kritik uygulamalar için yerleşik denetim günlüğü. Özellik düzeyinde ayrıntılarla istek, hizmet, yöntem düzeyinde denetim günlüğü ve varlık geçmişleri.", "EmailSMSAbstractionsWithTemplatingSupportExplanation": "IEmailSender ve ISmsSender soyutlamaları, uygulama mantığınızı altyapıdan ayırır. Gelişmiş e-posta şablon sistemi, e-posta şablonları oluşturmanıza ve yerelleştirmenize ve gerektiğinde kolayca kullanmanıza olanak tanır.", "LocalizationExplanation": "Yerelleştirme sistemi, düz JSON dosyalarında kaynaklar oluşturmanıza ve bunları UI'nizi yerelleştirmek için kullanmanıza olanak tanır. AspNet Core'un yerelleştirme sistemi ile tam uyumlu iken kalıtım, uzantılar ve JavaScript entegrasyonu gibi gelişmiş senaryoları destekler.", @@ -163,7 +163,7 @@ "Strong": "Güçlü", "Complete": "Tamamlayınız", "BasedLayeringModel": "Tabanlı Katmanlama Modeli", - "Microservice": "mikro hizmet", + "Microservice": "Mikroservis", "Compatible": "Uyumlu", "MeeTTheABPCommunityInfo": "Misyonumuz, geliştiricilerin makaleler, öğreticiler, vaka çalışmaları vb. ile birbirlerine yardımcı olabilecekleri ve benzer düşünen insanlarla tanışabilecekleri bir ortam yaratmaktır.", "JoinTheABPCommunityInfo": "Canlı bir topluluğa katılın ve ABP Çerçevesine katkıda bulunun!", @@ -178,7 +178,7 @@ "ProgressiveWebApplication": "Progresif Web Uygulaması", "UseslatestPreVersion": "En son yayın öncesi sürümünü kullanır", "ReadTheDocumentation": "Belgeleri okuyun", - "Documentation": "belgeler", + "Documentation": "Dökümanlar", "GettingStartedTutorial": "Başlarken Eğitimi", "ApplicationDevelopmentTutorial": "Uygulama Geliştirme Eğitimi", "TheStartupTemplate": "Başlangıç Şablonu", @@ -285,7 +285,6 @@ "Database": "Veritabanı", "Saas": "Saas", "OpenSourceWebApp": " Açık kaynak
web uygulaması", - "Framework": "Çerçeve", "AuditLoggingExplanation": "Sisteminizdeki tüm işlemleri ve veri değişikliklerini otomatik olarak izleyin.", "AbpNewCommandExplanation": "ABP başlangıç şablonlarını kullanarak yeni çözümler oluşturur.", "AbpAddModuleCommandExplanation": "Çözümünüze önceden oluşturulmuş uygulama modülleri yükler", @@ -300,10 +299,8 @@ "Preview": "Önizleme", "CreateANewSolution": "Yeni bir çözüm oluşturun", "ABPFrameworkFeatures": "ABP Çerçevesi Özellikleri", - "Commercial": "Ticari", "ThirdPartyTools": "Üçüncü taraf araçlar", "Back": "Geri", - "Community": "Topluluk", "SeeMore": "Daha fazla göster", "DetailsOfTheEBook": "E-kitap detayları", "JoinOurMarketingNewsletter": "Pazarlama bültenimize katılın", @@ -374,7 +371,21 @@ "MasteringAbpFramework_Book_WhoIsThisBookFor_Description": "Bu kitap, Microsoft teknolojilerini ve ABP Çerçevesini kullanarak sürdürülebilir web tabanlı çözümler\n oluşturmak için yazılım mimarilerini ve en iyi uygulamaları öğrenmek isteyen web geliştiricileri içindir.\n Bu kitaba başlamak için temel C# ve ASP.NET Core bilgisi gereklidir.", "ComputersAndTechnology": "Bilgisayar ve Teknoloji", "ThisBookIsInDraftStageAndIsNotCompletedYet": "Bu kitap taslak aşamasındadır ve henüz tamamlanmamıştır.", - "SelectUITheme": "Vyberte téma uživatelského rozhraní" - + "CreateSolutionFolder": "Çözüm Klasörü Oluşturun", + "CreateSolutionFolderOption": "Projenin çıktı klasöründe yeni bir klasörde mi yoksa doğrudan çıktı klasöründe mi olacağını belirtir.", + "SelectUITheme": "UI Temasını Seçin", + "BooksPageTitle": "ABP Kitapları", + "InstallAbpCliMessage": "Daha önce yüklemediyseniz, ABP CLI'yi bir komut satırı terminaline yükleyin:", + "RunTheFollowingCommand": "Aşağıdaki komutu bir komut satırı terminalinde çalıştırın:", + "ChangeSolutionOptionsBelow": "Aşağıdaki çözüm seçeneklerini değiştirebilirsiniz.", + "MultiLayerApplicationExplanation1": "Domain Driven Design uygulamalarına dayalı olarak tamamen katmanlı bir çözüm oluşturur.", + "MultiLayerApplicationExplanation2": "Sürdürülebilir ve genişletilebilir bir kod tabanına ihtiyaç duyan uzun vadeli projeler için önerilir.", + "SingleLayerApplicationExplanation1": "Tek katmanlı bir web uygulaması oluşturur.", + "SingleLayerApplicationExplanation2": "Daha basit ve anlaşılması kolay bir mimariye sahip bir uygulama oluşturmak için önerilir.", + "ApplicationModuleExplanation1": "Yeniden kullanılabilir, tamamen katmanlı bir uygulama modülü çözümü oluşturur.", + "ApplicationModuleExplanation2": "Modüler uygulamanız için modüller oluşturmak üzere bu seçeneği kullanabilirsiniz.", + "LeptonXLiteThemeInfo": " Modern ve şık bir Bootstrap UI teması. Üretime hazır bir UI temasına sahip olmak istiyorsanız idealdir. Bu en yeni temadır ve varsayılandır.", + "BasicThemeInfo": "Sade Bootstrap renkleri ve stilleri ile minimalist UI teması. Kendi UI temanızı oluşturacaksanız idealdir.", + "Details": "Detaylar" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/vi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/vi.json index faa0b53211..b67ff75480 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/vi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/vi.json @@ -274,7 +274,8 @@ "FirstEdition": "Ấn bản đầu tiên", "ThankYou": "Cảm ơn bạn!", "CheckboxMandatory": "Bạn cần kiểm tra điều này để tiếp tục!", - "SelectUITheme": "Chọn chủ đề giao diện người dùng" - + "SelectUITheme": "Chọn chủ đề giao diện người dùng", + "CreateSolutionFolder": "Tạo thư mục giải pháp", + "CreateSolutionFolderOption": "Chỉ định xem dự án sẽ nằm trong một thư mục mới trong thư mục đầu ra hay trực tiếp trong thư mục đầu ra." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json index a6ef45db1d..7fca00dd3e 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json @@ -408,6 +408,17 @@ "ApplicationModule": "应用程序模块", "SeeTheScreenshot": "如截图所示", "ApplicationModuleExplanation1": "创建可重用的、完全分层的应用程序模块解决方案。", - "ApplicationModuleExplanation2": "您可以使用此选项为您的模块化应用程序创建模块。" + "ApplicationModuleExplanation2": "您可以使用此选项为您的模块化应用程序创建模块。", + "Expert_": "专家", + "Partner_": "合作伙伴", + "WebSite": "网站", + "Expert_Year": "专业年限", + "CompanyInfo": "公司信息", + "Date": "日期", + "WhoWeAre_Partner": "关于我们", + "WhoWeAre_Expert": "关于我", + "CreateSolutionFolder": "创建解决方案文件夹", + "CreateSolutionFolderOption": "指定项目是位于输出文件夹中的新文件夹中,还是直接位于输出文件夹中。", + "BooksPageTitle": "ABP书籍" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json index baa41ba088..e3e3ded37c 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json @@ -274,7 +274,8 @@ "FirstEdition": "第一版", "ThankYou": "謝謝!", "CheckboxMandatory": "你需要檢查這個才能繼續!", - "SelectUITheme": "選擇 UI 主題" - + "SelectUITheme": "選擇 UI 主題", + "CreateSolutionFolder": "創建解決方案文件夾", + "CreateSolutionFolderOption": "指定項目是位於輸出文件夾中的新文件夾中,還是直接位於輸出文件夾中。" } } \ No newline at end of file diff --git a/common.props b/common.props index 22b86f2a2f..82232bc214 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 7.1.1 + 7.2.0-rc.2 $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ diff --git a/docs/en/Background-Jobs-Hangfire.md b/docs/en/Background-Jobs-Hangfire.md index c6c3d69ad7..ca2067980e 100644 --- a/docs/en/Background-Jobs-Hangfire.md +++ b/docs/en/Background-Jobs-Hangfire.md @@ -66,6 +66,8 @@ After you have installed these NuGet packages, you need to configure your projec } ```` +> You have to configure a storage for Hangfire. + 2. If you want to use hangfire's dashboard, you can add `UseHangfireDashboard` call in the `OnApplicationInitialization` method in `Module` class ````csharp diff --git a/docs/en/Background-Jobs.md b/docs/en/Background-Jobs.md index 84e746f73d..c6e19fb48a 100644 --- a/docs/en/Background-Jobs.md +++ b/docs/en/Background-Jobs.md @@ -75,6 +75,42 @@ This job simply uses `IEmailSender` to send emails (see [email sending document] A background job should not hide exceptions. If it throws an exception, the background job is automatically re-tried after a calculated waiting time. Hide exceptions only if you don't want to re-run the background job for the current argument. +#### Cancelling Background Jobs + +If your background task is cancellable, then you can use the standard [Cancellation Token](Cancellation-Token-Provider.md) system to obtain a `CancellationToken` to cancel your job when requested. See the following example that uses the `ICancellationTokenProvider` to obtain the cancellation token: + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace MyProject +{ + public class LongRunningJob : AsyncBackgroundJob, ITransientDependency + { + private readonly ICancellationTokenProvider _cancellationTokenProvider; + + public LongRunningJob(ICancellationTokenProvider cancellationTokenProvider) + { + _cancellationTokenProvider = cancellationTokenProvider; + } + + public override async Task ExecuteAsync(LongRunningJobArgs args) + { + foreach (var id in args.Ids) + { + _cancellationTokenProvider.Token.ThrowIfCancellationRequested(); + await ProcessAsync(id); // code omitted for brevity + } + } + } +} +``` + +> A cancellation operation might be needed if the application is shutting down and we don't want to block the application in the background job. This example throws an exception if the cancellation is requested. So, the job will be retried the next time the application starts. If you don't want that, just return from the `ExecuteAsync` method without throwing any exception (you can simply check the `_cancellationTokenProvider.Token.IsCancellationRequested` property). + #### Job Name Each background job has a name. Job names are used in several places. For example, RabbitMQ provider uses job names to determine the RabbitMQ Queue names. diff --git a/docs/en/Background-Workers-Hangfire.md b/docs/en/Background-Workers-Hangfire.md index 5a456b1092..9506eb97a7 100644 --- a/docs/en/Background-Workers-Hangfire.md +++ b/docs/en/Background-Workers-Hangfire.md @@ -40,6 +40,50 @@ public class YourModule : AbpModule > Hangfire background worker integration provides an adapter `HangfirePeriodicBackgroundWorkerAdapter` to automatically load any `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived classes as `IHangfireBackgroundWorker` instances. This allows you to still to easily switch over to use Hangfire as the background manager even you have existing background workers that are based on the [default background workers implementation](Background-Workers.md). +## Configuration + +You can install any storage for Hangfire. The most common one is SQL Server (see the [Hangfire.SqlServer](https://www.nuget.org/packages/Hangfire.SqlServer) NuGet package). + +After you have installed these NuGet packages, you need to configure your project to use Hangfire. + +1.First, we change the `Module` class (example: `HttpApiHostModule`) to add Hangfire configuration of the storage and connection string in the `ConfigureServices` method: + +````csharp + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + var hostingEnvironment = context.Services.GetHostingEnvironment(); + + //... other configarations. + + ConfigureHangfire(context, configuration); + } + + private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration) + { + context.Services.AddHangfire(config => + { + config.UseSqlServerStorage(configuration.GetConnectionString("Default")); + }); + } +```` + +> You have to configure a storage for Hangfire. + +2. If you want to use hangfire's dashboard, you can add `UseHangfireDashboard` call in the `OnApplicationInitialization` method in `Module` class + +````csharp + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + + // ... others + + app.UseHangfireDashboard(); //should add to the request pipeline before the app.UseConfiguredEndpoints() + app.UseConfiguredEndpoints(); + } +```` + ## Create a Background Worker `HangfireBackgroundWorkerBase` is an easy way to create a background worker. diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/POST.md b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/POST.md new file mode 100644 index 0000000000..14571157b6 --- /dev/null +++ b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/POST.md @@ -0,0 +1,37 @@ +# Migrating from MS-SQL to Postgresql + +![sql-server-to-postgres](images/sql-server-to-postgres.jpg) + +## Introduction + +Database migration is a common practice for organizations that want to move from one database system to another. This can be for a variety of reasons, including cost, performance, and features. In this article, we will discuss the process of migrating a database from MS-SQL to PostgreSQL, the challenges that may arise during the migration, and how to overcome them. And we recently moved the main database of https://abp.io platform from MS-SQL to PostgreSQL. + +In our case, we decided to switch our database from Microsoft SQL Server (MS-SQL) to PostgreSQL because we wanted to move our on-premise platform to Azure. We’ve also found out that the cost of the license for MS-SQL on Azure was significantly higher than PostgreSQL. After conducting a cost-benefit analysis, we decided to migrate our database to PostgreSQL to save costs. + +Before migrating to Azure, we decided to switch our database from MS-SQL to PostgreSQL on-premise first. This gave us the opportunity to test and fine-tune the migration process before making the final switch to Azure. + +## Challenges + +Despite using a third-party tool(DBConvert for MySQL & PostgreSQL) for the migration, we faced three main problems when exporting data to PostgreSQL. Firstly, some tables with plain text had utf-8 encoding problems. We overcame this problem by dump-restoring these tables. + +![db-converter](images/db-converter.jpg) + + +Secondly, our database had to be case-insensitive, but PostgreSQL does not have this as a default configuration. We handled it using `citext` with the ABP migration service. + +![citext-1](images/citext-1.jpg) +![citext-2](images/citext-2.jpg) +![citext-3](images/citext-3.jpg) + + +While everything was proceeding very smooth, we faced one last problem: importing binary data, such as the content of the NuGet packages. It was hard to understand that the binaries of the NuGet packages were different. Our paid commercial NuGet packages are being stored as binary data in the database. Therefore, it was the most compelling part of this migration to transfer the NuGet packages. Fortunately, we overcame the binary error. And we decided to write a custom .NET tool to move only the binary data from MS-SQL to PostgreSQL, thanks to the ABP Core team! + + +## Conclusion + +One of the benefits of using PostgreSQL is the low license costs of the Azure platform. As the main contributors of ABP, we also use ABP Framework under the hood of our abp.io websites, we could easily switch to PostgreSQL. For those who want to switch their ABP project to PostgreSQL, check out [docs.abp.io/en/abp/latest/Entity-Framework-Core-PostgreSQL](https://docs.abp.io/en/abp/latest/Entity-Framework-Core-PostgreSQL). We had not used any MS-SQL specific function, therefore there was no need to make any changes in the repository classes. This means that the applications that were previously using MS-SQL can seamlessly switch to PostgreSQL without any modifications. + +Thanks to the flexibility of ABP, it has [PostgreSQL package](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql) which is 100% compatible with PostgreSQL. This helped us to make this migration very smooth and seamless. + +In conclusion, migrating a database from MS-SQL to PostgreSQL can be challenging, but it can bring significant cost savings in the long run. By testing and fine-tuning the migration process before making the final switch, we were able to overcome the challenges we’d faced during the migration process. Thanks to the flexibility of ABP, we were able to make the transition with minimal code changes. Also we didn't see any big performance differences between MS-SQL and PostgreSQL. + diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-1.jpg b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-1.jpg new file mode 100644 index 0000000000..4dc01228fa Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-1.jpg differ diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-2.jpg b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-2.jpg new file mode 100644 index 0000000000..a70b0312bf Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-2.jpg differ diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-3.jpg b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-3.jpg new file mode 100644 index 0000000000..c8a95d61a5 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/citext-3.jpg differ diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/db-converter.jpg b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/db-converter.jpg new file mode 100644 index 0000000000..9c5371d36c Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/db-converter.jpg differ diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/mssql-postges.png b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/mssql-postges.png new file mode 100644 index 0000000000..c1766bc713 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/mssql-postges.png differ diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/mssql.png b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/mssql.png new file mode 100644 index 0000000000..2333842ea6 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/mssql.png differ diff --git a/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/sql-server-to-postgres.jpg b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/sql-server-to-postgres.jpg new file mode 100644 index 0000000000..645de45341 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-15-Migration-Mssql-Postgresql/images/sql-server-to-postgres.jpg differ diff --git a/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/POST.md b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/POST.md new file mode 100644 index 0000000000..82384b3f67 --- /dev/null +++ b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/POST.md @@ -0,0 +1,49 @@ + +# On-Prem to Azure: Migration of abp.io Platform to Azure + + +![abpio-azure](images/abpio-azure.png) + +Migrating a Kubernetes platform with a database from our own dedicated servers to Azure can be a compelling task, but it can be a necessary one to take advantage of the benefits that the cloud service offers. In this post, we will discuss the reasons for migrating from a on-premise platform to Azure, the steps taken to create and configure the [abp.io platform](https://abp.io) on Azure, and the benefits gained from the migration. + +### On-Premise Server: The old platform + +There were several reasons for migrating from the old on-premise platform to Azure. First, the Kubernetes cluster and the database were on the same Windows server. Additionally, the Linux virtual machines in Kubernetes were on the Windows server and had limited resources. Furthermore, the Kubernetes maintenance was quite challenging, which was another reason for the migration. + +### Reasons for Moving to Azure: The new platform + +The decision to move to the cloud was made to eliminate the disadvantages of the old platform. The migration to Azure meant that the resources would be independent of each other but faster in terms of communicating with each other. The platform would also take advantage of cloud security and availability. The managed Kubernetes service that Azure offers comes with autoscaling and loadbalancing, which makes the platform more reliable. Finally, the migration to Azure would provide a better quality service to global customers and the community. + +### Before Moving to Azure + +Before migrating to Azure, we decided to switch our database from MS-SQL to PostgreSQL on-premise first. This gave us the opportunity to test and fine-tune the migration process before making the final switch to Azure.You can check the details of database migration from this article [Migrating from MS-SQL to Postgresql](https://community.abp.io/posts/migrating-from-mssql-to-postgresql-lbi5anlv). + +The platform was tested in a staging environment created on Azure with the same resources as the production environment. The staging environment was used to test and optimize the migration process, including the migration of data from the old platform to Azure, which was tested multiple times to ensure success. + +### Creating and Configuring the abp.io Platform on Azure + +Several steps were taken to create and configure the abp.io platform on Azure. [Terraform](https://www.terraform.io/) was used to create the infrastructure (VM, Private Network, AKS, Postgresql Flexible Server...), while [Ansible](https://www.ansible.com/) was used to configure the Azure resources like Terraform, Helm, Kubectl, Docker, VPN, Redis, Prometheus, Grafana, ElasticSearch, Kibana and so on.... Azure DevOps pipelines and release were used for AKS deployment. The most time-consuming part in this process was to prepare, test and optimize the terraform and ansible settings files. + +To access our platform, which is configured on a private network in Azure, we require a VPN connection. To enable this, we have installed [Wireguard](https://www.wireguard.com/) - an open source VPN service - by creating a virtual machine using Terraform and configuring it with Ansible in Azure. This approach has made the process efficient and streamlined. + +![terra-wire](images/terra-wire.png) + +The most important step was to transfer the data in both the database and Kubernetes of the volumes. rsync (remote sync commands) were used to transfer the data from Kubernetes volumes to Azure NFS through the VPN machine. Additionally, `pg_dump` and `pg_restore` were used to transfer the PostgreSQL database through the machine with VPN. + +Before the production environment, the data migration was tested many times for the staging environment. We estimated this migration to take max 1.5 hours. The ABP community was informed that there may be interruptions during the hours designated for the transition to Azure. To inform our customers and community, we created a status page before this migration. The new status page is [status.abp.io](https://status.abp.io). From now on we wil make all the infrastructural announcements on [status.abp.io](https://status.abp.io). We used [Upptime](https://upptime.js.org) which is an open-source uptime monitor and status page provider. During the migration of the production environment, the websites and databases were still up and running. After the data transfer, the only remaining step was to direct the traffic of the already standing abp.io sites to the Azure Kubernetes service via Cloudflare. + +We would like to happily state that **we were offline for only 4 minutes** during this transition. + +![az-infra](images/az-infra.png) + + +### Benefits of Moving to Azure + +The migration to Azure resulted in several benefits. The platform is now more reliable, scalable, secure, solid with built-in one-click backup and recovery capabilities for abp.io. Additionally, the critical resources are in a private network, making them more secure than the old environment. When we initially compared the speed of our abp.io sites before and after migrating to Azure, we were pleasantly surprised by the significant improvement in performance. To be honest, we did not expect such a speed increase. + +![speed](images/speed.png) + +In conclusion, migrating a Kubernetes platform with a database from on-premise to Azure is a complex process that requires careful planning and execution. However, the benefits gained from the migration make the process worthwhile. By moving to Azure, the abp.io platform now has a more reliable and available infrastructure that is more secure than the old environment. The migration also resulted in significant improvements in connection speeds, which ultimately provides a better service to global customers and the community. + + + diff --git a/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/abpio-azure.png b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/abpio-azure.png new file mode 100644 index 0000000000..18e2379268 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/abpio-azure.png differ diff --git a/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/az-infra.png b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/az-infra.png new file mode 100644 index 0000000000..facbb4141b Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/az-infra.png differ diff --git a/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/speed.png b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/speed.png new file mode 100644 index 0000000000..a9c99ea321 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/speed.png differ diff --git a/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/terra-wire.png b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/terra-wire.png new file mode 100644 index 0000000000..ad003ac362 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-16-Migration-Abp.io-Azure/images/terra-wire.png differ diff --git a/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/POST.md b/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/POST.md new file mode 100644 index 0000000000..0cecf0fb72 --- /dev/null +++ b/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/POST.md @@ -0,0 +1,82 @@ +# ABP.IO Platform 7.1 Final Has Been Released! + +[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 7.1 versions have been released today. + +## What's New With Version 7.1? + +All the new features were already explained in detail in the [7.1 RC Announcement Post](https://blog.abp.io/abp/ABP.IO-Platform-7.1-RC-Has-Been-Published), so no need to go over them again. Check it out for more details. + +## Getting Started with 7.1 + +### Creating New Solutions + +You can create a new solution with the ABP Framework version 7.1 by either using the `abp new` command or generating the CLI command on the [get started page](https://abp.io/get-started). + +> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for more. + +### How to Upgrade an Existing Solution + +#### Install/Update the ABP CLI + +First of all, install the ABP CLI or upgrade it to the latest version. + +If you haven't installed it yet: + +```bash +dotnet tool install -g Volo.Abp.Cli +``` + +To update the existing CLI: + +```bash +dotnet tool update -g Volo.Abp.Cli +``` + +#### Upgrading Existing Solutions with the ABP Update Command + +[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command: + +```bash +abp update +``` + +Run this command in the root folder of your solution. + +## Migration Guides + +This version includes a very minor breaking change and it doesn't affect most of the applications. Check [the migration guide](https://docs.abp.io/en/abp/7.1/Migration-Guides/Abp-7_1) for the details. + +## Community News + +## ABP Community Talks 2023.2 + +The next ABP Community Talks will take place on March 30, at 18:00 (UTC). + +![abp-comm-talks-2023-2](abp-comm-talks-2023-2.png) + +In this episode, core ABP Framework developers will discuss the benefits of using the ABP Framework as a .NET developer instead of creating your own solution from scratch. They will answer most of the common doubts about using ABP and application frameworks in general. You will better understand how ABP makes a developer’s life easier and more enjoyable while cutting production costs. We will also have a question - answer session after the talk, as always. I think this talk will be useful for every .NET developer whether they use ABP or not. + +**[CLICK HERE to register for the event and join us](https://kommunity.com/volosoft/events/abp-community-talks-20232-why-use-abp-framework-as-a-net-developer-e3254183)**. + +## Introducing the first ABP .NET Conference! + +As the ABP team, we've executed more than 10 [online events](https://community.abp.io/events) and gained a good experience of software talks. In May, we are organizing a full-featured software conference, named **ABP Dotnet Conference 2023**! + +![abp-conf-2023](abp-conf-2023.png) + +We are still organizing the speakers, talks and schedule. There will be 12 sessions about software development and .NET. These will also include a few ABP-related talks. You can **follow https://abp.io/conference website** and buy early bird tickets from now. + +### New ABP Community Posts + +There are exciting articles contributed by the ABP community as always. I will highlight some of them here: + +* [Creating Dockerfile for ABP Applications](https://community.abp.io/posts/creating-dockerfile-for-abp-applications-caj4fkxa) by [Anto Subash](https://community.abp.io/members/antosubash) +* [IdentityUser Relationship and Extending it](https://community.abp.io/posts/identityuser-relationship-and-extending-it-xtv79mpx) by [Onur Pıçakçı](https://community.abp.io/members/onurpicakci) +* [Streamline Localization in Your ABP Project](https://community.abp.io/posts/streamline-localization-in-your-abp-project-1t12rmjc) by [Salih Özkara](https://community.abp.io/members/salih) +* [.Net Microservice template with ABP](https://community.abp.io/posts/.net-microservice-template-with-abp-53r52ryy) by [Anto Subash](https://community.abp.io/members/antosubash) + +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/articles/submit) to the ABP Community. + +## About the Next Version + +The next feature version will be 7.2. 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/2023-03-23 v7_1_Release_Stable/abp-comm-talks-2023-2.png b/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/abp-comm-talks-2023-2.png new file mode 100644 index 0000000000..730e48dc0b Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/abp-comm-talks-2023-2.png differ diff --git a/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/abp-conf-2023.png b/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/abp-conf-2023.png new file mode 100644 index 0000000000..889ddbdc0a Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-23 v7_1_Release_Stable/abp-conf-2023.png differ diff --git a/docs/en/Blog-Posts/2023-03-24-status.abp.io/POST.md b/docs/en/Blog-Posts/2023-03-24-status.abp.io/POST.md new file mode 100644 index 0000000000..42fd131f3b --- /dev/null +++ b/docs/en/Blog-Posts/2023-03-24-status.abp.io/POST.md @@ -0,0 +1,114 @@ +# Creating a Custom Status Page for abp.io with Upptime + +## Introduction +In today's digital world, providing reliable and transparent information about your platform's availability is essential to maintaining trust among your community and customers. With the growing number of abp.io users, we needed a dedicated status page [status.abp.io](https://status.abp.io/) to keep everyone informed about our platform's health. To achieve this, we utilized the open-source project [Upptime](https://upptime.js.org/) and built a custom status page on [GitHub Pages](https://pages.github.com/). In this article, we'll guide you through the process of creating our own status page and customizing it to suit our needs. + +![status-abpio](./images/status-abpio.png) + +## Why we chose Upptime +[Upptime](https://github.com/upptime/upptime) is an open-source, easy-to-use, and cost-effective solution for monitoring websites and APIs. It offers essential features, such as downtime alerts, response time monitoring, and status history. We decided to use Upptime because of its compatibility with GitHub Pages, ease of customization, comprehensive [documentation ](https://upptime.js.org/docs/) and discord notifications. + +![gh-status](./images/gh-status.png) + +#### Advantages of Upptime +* Open-source: Allows easy customization and community support. + +* GitHub Pages compatibility: Seamless integration with GitHub Pages for hosting. + +* Cost-effective: Utilizes GitHub Actions, which provides free monitoring within the GitHub Actions usage limits. + +* Comprehensive documentation: Easy-to-follow instructions for setting up and customizing the status page. + +#### Disadvantages of Upptime +* Limited monitoring capabilities: Upptime offers basic monitoring features but lacks advanced capabilities found in dedicated monitoring tools. + +* Dependence on GitHub Actions: Upptime relies on GitHub Actions, which may pose limitations for users unfamiliar with GitHub's ecosystem or those with large-scale projects. + +* No built-in alerting system: Users must rely on third-party integrations or custom solutions for notifications, requiring additional configuration. + +* Limited customization options: Upptime allows for some customization, but options are limited compared to comprehensive monitoring platforms. + +* Self-hosted limitations: As a self-hosted solution, users are responsible for maintaining and managing their own infrastructure, which may not be ideal for those who prefer a fully managed monitoring solution. + + +## How to set up the status page on GitHub Pages +To get started with our custom status page, we followed the instructions in the [Upptime documentation](https://upptime.js.org/docs/). Here's a summary of the steps we took: + +* Fork the Upptime [template repository](https://github.com/upptime/upptime) to our own GitHub account as [abpio-status](https://github.com/abpframework/abpio-status). + +* Configure the GitHub Actions workflow. We configured the GitHub Actions workflow by adding the following lines to the [`.github/workflows/uptime.yml`](https://github.com/abpframework/abpio-status/blob/master/.github/workflows/uptime.yml) + +* Add the monitored endpoints. We added the monitored endpoints (our abp.io websites) to the [.upptimerc.yml](https://github.com/abpframework/abpio-status/blob/master/.upptimerc.yml) file. This file is located in the root of the repository and contains a list of URLs that Upptime monitors. + +```yaml +sites: + - name: abp.io + url: https://abp.io/health-status + - name: community.abp.io + url: https://community.abp.io/health-status + - name: commercial.abp.io + url: https://commercial.abp.io/health-status + - name: nuget.abp.io + url: https://nuget.abp.io/health-status + - name: docs.abp.io + url: https://docs.abp.io/health-status + - name: support.abp.io + url: https://support.abp.io/health-status + - name: blog.abp.io + url: https://blog.abp.io/health-status + - name: commercial-demo.abp.io + url: https://commercial-demo.abp.io/health-status +``` +* Enable GitHub Pages. Finally, we enabled GitHub Pages for our forked repository by going to the repository's settings and selecting the gh-pages branch as the source. This made our status page accessible at [status.abp.io](https://status.abp.io/). + +## Customizing the status page + +After setting up the default Upptime status page, we focused on customizing it to align with our brand and provide a consistent experience for our community and customers. We made the following changes: + +* Updating the logo and favicon. We replaced the default logo and favicon with our own abp.io branded assets. This involved adding the new image files to the repository and updating the references in the `.upptimerc.yml` file: + +* Customizing the color scheme and typography. We customized the color scheme and typography to match our corporate identity by editing the `.upptimerc.yml` file: + +```yaml +status-website: + theme: dark + # Add your custom domain name, or remove the `cname` line if you don't have a domain + # Uncomment the `baseUrl` line if you don't have a custom domain and add your repo name there + cname: status.abp.io + # baseUrl: /abpio-status + logoUrl: https://commercial.abp.io/assets/svg/abp-logo-light.svg + favicon: https://raw.githubusercontent.com/abpframework/abpio-status/master/assets/abp-logo-without-text.svg + faviconSvg: https://raw.githubusercontent.com/abpframework/abpio-status/master/assets/abp-logo-without-text.svg +``` +## Creating GitHub Issues for Maintenance Information on status.abp.io + +To provide maintenance information for your status page, you can create GitHub issues in your repository. This allows you to inform your users about planned downtime or ongoing maintenance work. + +![issue](./images/issue.png) + +## Discord Notifications + +### Create a Discord Webhook + +To set up Discord notifications for your status.abp.io status page using [Upptime documentation](https://upptime.js.org/docs/notifications#discord), follow these steps: + +* In Discord, go to "Server Settings" > "Integrations" > "Create Webhook." +* Customize the Webhook name, choose a channel, and copy the Webhook URL. + +### Configure GitHub Actions +* In your Upptime repository, go to the "Settings" tab. +* Click on "Secrets" and then "New repository secret." +* Add secret: Name it DISCORD_WEBHOOK_URL and paste the Webhook URL as the value. +* Add environment variables NOTIFICATION_DISCORD_WEBHOOK and NOTIFICATION_DISCORD set it to true. + +Your status page will now send notifications to your Discord channel whenever there's a change in your platform's status. + +![discord](./images/discord.png) + + +## Conclusion +If your primary goal is to create a simple, cost-effective status page with basic monitoring features, Upptime is an excellent choice. Its open-source nature, seamless integration with GitHub Pages, and comprehensive documentation make it a user-friendly option. + +If you require advanced monitoring capabilities or prefer a fully managed monitoring solution, you may want to explore dedicated monitoring tools, such as Pingdom, Uptime Robot, or Datadog. These tools typically offer more robust monitoring features, built-in alerting systems, and customizable dashboards. + +Creating a custom status page for abp.io using Upptime and GitHub Pages proved to be an efficient and cost-effective solution. By following the documentation and customizing the template, we were able to provide our community and customers with a reliable source of information about our platform's availability. With this new status page [status.abp.io](https://status.abp.io/), we can continue to build trust and transparency as our platform grows and evolves. diff --git a/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/discord.png b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/discord.png new file mode 100644 index 0000000000..b9f66bfead Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/discord.png differ diff --git a/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/gh-status.png b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/gh-status.png new file mode 100644 index 0000000000..b48229b479 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/gh-status.png differ diff --git a/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/issue.png b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/issue.png new file mode 100644 index 0000000000..39fda7a869 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/issue.png differ diff --git a/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/status-abpio.png b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/status-abpio.png new file mode 100644 index 0000000000..528a5755d7 Binary files /dev/null and b/docs/en/Blog-Posts/2023-03-24-status.abp.io/images/status-abpio.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/abp-essential-features.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/abp-essential-features.png new file mode 100644 index 0000000000..287d130cb8 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/abp-essential-features.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/abp-try-now.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/abp-try-now.png new file mode 100644 index 0000000000..c3a5ffdaec Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/abp-try-now.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/cover.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/cover.png new file mode 100644 index 0000000000..b2a7aa8595 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/cover.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/cross-platform.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/cross-platform.png new file mode 100644 index 0000000000..5889357a42 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/cross-platform.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/ddd-book.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/ddd-book.png new file mode 100644 index 0000000000..b18c3b716a Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/ddd-book.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/developer-focused.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/developer-focused.png new file mode 100644 index 0000000000..bfb0f15d28 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/developer-focused.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/features.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/features.png new file mode 100644 index 0000000000..7c941289e2 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/features.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/key-features.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/key-features.png new file mode 100644 index 0000000000..4c4b714694 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/key-features.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/module-layers-and-packages.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/module-layers-and-packages.png new file mode 100644 index 0000000000..50d8d09f9b Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/module-layers-and-packages.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/open-source.png b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/open-source.png new file mode 100644 index 0000000000..e389e67146 Binary files /dev/null and b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/images/open-source.png differ diff --git a/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/post.md b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/post.md new file mode 100644 index 0000000000..8c6bef4b8a --- /dev/null +++ b/docs/en/Blog-Posts/2023-04-07_Ultimate_NET_Framework_ABP/post.md @@ -0,0 +1,85 @@ +Building robust web applications has become more important than ever as the world is becoming more web-focused. With the rise of new tools and frameworks, choosing the right web development framework can be challenging. Especially if you are a .NET developer, there not so many popular ASPNET Framework around. However, the ABP Framework has become popular for many developers due to its flexibility, scalability, feature set and performance. Let's mention what's ABP Framework and what it promises to .NET developers. + +## ASP.NET Core Architecture Best Practices + +![ABP Key Features](images/key-features.png) + +ABP Framework is an application design framework that provides developers with a powerful set of tools to build web applications quickly and efficiently. It is an open-source, cross-platform framework supporting monolithic and microservices architectures. ABP Framework is built on top of the ASP.NET Core architecture and incorporates best practices for developing web applications. + +## ASP.NET Platform + +The framework includes a wide range of features, such as an angular code generator with the help of [ABP Suite](https://commercial.abp.io/tools/suite), project templates, and web application themes. These features enable developers to create web applications that are both functional and visually appealing without spending much time on coding. Moreover, ABP Framework provides a common application framework that can be used for different applications, including SAAS, e-commerce, and social media platforms. + +ABP Framework also supports the domain-driven design, which means that the framework is designed to be flexible and adaptable to different business requirements. This approach allows developers to build applications aligned with business needs, ensuring that they are efficient and effective. + +## Open Source Dot Net Framework + +One of the major advantages of ABP Framework is its open-source nature. Many developers continuously improve and update the framework, making it more reliable and secure. Moreover, the ABP Framework is compatible with multiple .NET frameworks, including ASP.NET and .NET Core. When starting your project on top of a solid Microsoft web framework, the ABP Framework is one of the best choices. + +![ABP is cross platform](images\cross-platform.png) + +Another advantage of ABP Framework is that it provides rapid web application development tools that are easy to use. The framework includes project templates that developers can use as a starting point for their web applications, which can significantly reduce the development time. ABP Framework also provides a web app builder that developers can use to create web applications quickly and efficiently. + +## ASPNET Core Architecture + +ABP Framework is also compatible with Microsoft's Clean Architecture, a software design pattern that promotes separation of concerns and maintainability. This integration ensures that the applications developed using ABP Framework are well-structured, easy to maintain, and scalable. Many application marketplace reviewers commented about ABP as the best web application framework. While ABP supports multiple UI choices like MVC, Angular, Blazor Web Assembly and Blazor Server, the most downloaded one is MVC microservice architecture. If you are here to find a NET application framework for your next NET Core application, you are in the right place! + +![ABP Framework Project Hierarchy](images/module-layers-and-packages.png) + +Clean Architecture is a design pattern that emphasizes the separation of concerns, ensuring that the code is organized in independent layers. This helps developers to write code that is easy to maintain, test and refactor. ABP Framework uses this pattern to structure its application code and ensure that it is easy to manage. + +## Open Source Web Framework + +ABP Framework is an open-source web framework that is free to use and distribute. The framework is licensed under the MIT license, meaning developers can use it for commercial and non-commercial purposes without any restrictions. + +ABP Framework provides different templates, which are ASPNET Core web app compatible with various platforms, including Windows, Linux, and macOS. + +## Domain Driven Design DotNet + +The ABP Framework also implements Domain-Driven Design (DDD), a software design methodology that emphasizes the importance of the domain model. The framework provides a guide for implementing DDD through an implementing domain-driven design. It helps developers to create a domain model that is easy to understand, test, and maintain. As ABP is a C# framework, it supports most of the common application framework features for a core framework. + +![ABP Framework - Domain Driven Design e-book](images/ddd-book.png) + +There is also a free PDF e-book for Dotnet developers that explains the Domain Driven Design principle with real-world examples. You can download this e-book at https://abp.io/books/implementing-domain-driven-design + +## It's a Dotnet Web Framework + +ABP Framework is a dotnet web framework that is designed with C# and provides developers with a set of tools that makes it easy to build modern web applications. Whether you want to start a new dotnet monolithic solution or dotnet microservice solution, you can start with ABP. Creating your own dotnet framework architecture may be hard if you don't have many years of experience. The brain team of the ABP Framework specializes in ASP.NET framework architecture and ASP.NET application frameworks. + +![Developer Focused](images/developer-focused.png) + +## Essential Features of the ABP Framework: + +ASP.NET Core modularity, ASP.NET Core modular development, ASP.NET Core localization, ASP.NET Core SaaS framework, ASP.NET Core distributed, event, bus, ASP.NET Core cross-cutting concerns, ASP.NET Core blob storing, ASP.NET Core audit logging, ASP.NET Core microservice, ASP.NET Core microservice solution, ASP.NET Core microservice example, ASP.NET Core API gateway, ASP.NET Core domain, driven, design, ASP.NET Core layered architecture, ASP.NET Core layering, ASP.NET Core clean architecture, ASP.NET Core authentication, ASP.NET Core authorization, ASP.NET Core UI theme, ASP.NET Core tag helpers, ASP.NET Core identity, ASP.NET Core, identity, server, ASP.NET Core IdentityServer, ASP.NET Core payment module, ASP.NET Core best practices, ASP.NET Core design patterns, ASP.NET Core background jobs, ASP.NET Core exception handling, ASP.NET Core, background, workers, ASP.NET Core repository, ASP.NET Core repository pattern, ASP.NET Core unit of work, ASP.NET Core domain services, ASP.NET Core Swagger, ASP.NET Core content management system, ASP.NET Core CMS module, ASP.NET Core user management, ASP.NET Core Role management, ASP.NET Core permission management + +![ABP Essential Features](images/abp-essential-features.png) + +## Open Source Web Application Framework + +ABP Framework is an open-source web application development framework that is free to use and distribute. The framework is licensed under the MIT license, meaning developers can use it for commercial and non-commercial purposes without any restrictions. + +![ABP Framework is open-source](images\open-source.png) + +## C# Web Application Framework + +ABP Framework is built using C#, which is a modern programming language that is widely used in the development of web applications. C# provides developers with features that make it easy to write clean and maintainable code. ABP Framework is a web framework designed to work with C# and provides developers with tools that make it easy to build modern web applications. + +## Key Features + +The following .NET features are available in the ABP Framework: + +.NET modular development, .NET localization, .NET multi-tenancy, .NET SaaS framework, .NET distributed event bus, .NET cross-cutting concerns, .NET,microservice, .NET microservice solution, .NET microservice example, .NET domain driven design, .NET clean architecture, .NET authentication, .NET authorization, .NET best practices, .NET design,patterns, .NET exception handling, .NET background workers, .NET unit of work, .NET domain services, .NET user management, .NET role management, .NET permission management + +![ABP Framework Features](images/features.png) + +The following keywords best describe the ABP Framework; + +Open source backend framework, open source development framework, open source web app builder, open source web applications, open source web development, web application development framework, web application framework, web application framework software, web application infrastructure, web application open source, asp net framework, asp net open source, ASP.NET application, ASP.NET software, ASP.NET web app, ASP.NET web development, web app builder open source, web app framework, Dotnet framework, Dotnet UI framework, Dotnet web application themes. + + + +## Conclusion + +ABP Framework is a powerful and flexible web application framework that provides developers with the tools to build high-quality web applications quickly and efficiently. It is an open-source, cross-platform framework that supports multiple .NET frameworks, including ASP.NET and .NET Core. ABP Framework provides rapid web application development tools, project templates, and web application themes that enable developers to create visually appealing and functional applications in no time. + +![Try ABP now](images\abp-try-now.png) \ No newline at end of file diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 9feb810730..49b5ca830b 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -164,6 +164,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample * `--local-framework-ref --abp-path`: Uses local projects references to the ABP framework instead of using the NuGet packages. This can be useful if you download the ABP Framework source code and have a local reference to the framework from your application. * `--no-random-port`: Uses template's default ports. * `--skip-installing-libs` or `-sib`: Skip installing client side packages. +* `--with-public-website`: **Public Website** is a front-facing website for describing your project, listing your products and doing SEO for marketing purposes. Users can login and register on your website with this website. See some [examples for the new command](CLI-New-Command-Samples.md) here. diff --git a/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/POST.md b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/POST.md new file mode 100644 index 0000000000..63936521c6 --- /dev/null +++ b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/POST.md @@ -0,0 +1,44 @@ +## Streamline Localization in Your ABP Project + +Making localization changes to an ABP project can be a daunting task, especially if you're dealing with multiple languages and translations. During development, it's easy to overlook some changes and that leads to inconsistencies across different languages. Fortunately, I have developed a tool that can help streamline the localization process and ensure consistency across different languages. + +The tool is a console application that uses JSON files to manage localization keys and their translations. It addresses three common scenarios that can arise during localization: + + +1. When the argument count of a key changes, it can be difficult to update the translations for all languages. My tool solves this problem by scanning all JSON files in the project folder and identifying any keys that have mismatched argument counts. It then offers two options to the user: delete the mismatched translations or export them as a JSON file for manual editing. + +2. When a new key is added to the project, forgetting to add its translations to all the other languages is easy. My tool helps to avoid this issue by scanning the default language's JSON file and identifying any keys that don't have translations in other languages. It then exports these keys as a JSON file that can be used to add missing translations. + +3. When a key's name is changed, it's important to update its translations in all the other languages. My tool makes this task simple by scanning all the JSON files in the project folder and updating any translations of the old key name with the new one. + +The tool also includes an export feature that allows users to modify translations outside of the application and import them back into the JSON files. + +## How it Helps + +With my Localization Key Synchronizer tool, you can perform complex localization changes more quickly and easily than by manually sifting through files and making changes one-by-one. This can save you significant time and effort, especially if you're working with a large number of languages or translations. + +## How it Works + +When you run the Localization Key Synchronizer tool, it presents you with three options: + +1. Find Asynchronous Keys +2. Apply Changes in the Exported File +3. Replace Keys + +If you select "Find Asynchronous Keys," the tool prompts you to enter the default language path. Once you've entered the path, the tool displays all of the JSON files in the same folder as a multi-select list. After selecting one or more files, you are asked whether you want to find keys that do not match the number of arguments, missing keys, or both. If you select "Missing Keys," the tool prompts you to enter the absolute path to export the missing keys. After you've entered the path, the export process starts, and the tool closes. + +![](./images/Part1.gif) + +If you select "Apply Changes in the Exported File" at the main menu, the tool prompts you to enter the path to the exported file. After you've entered the path, the import process starts, and the tool closes. + +![](./images/Part2.gif) + +If you select "Replace Keys," the tool prompts you to enter the localization folder path, the old key, the new key, and the JSON files to apply the changes to. Once you've entered all the required information and made your selections, the tool performs the replacements and closes. + +![](./images/Part3.gif) + +## Conclusion + +If you're struggling to manage localization changes in an ABP project, give my Localization Key Synchronizer tool a try. It can help streamline your workflow and make the process much more manageable. You can find the tool on [GitHub](https://github.com/abpframework/abp/tree/dev/tools/localization-key-synchronizer). + +To use the tool, simply run the console application and follow the prompts. It's a user-friendly solution that helps to ensure localization consistency in your ABP project. Give it a try and let me know what you think! diff --git a/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part1.gif b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part1.gif new file mode 100644 index 0000000000..f2e6b66e64 Binary files /dev/null and b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part1.gif differ diff --git a/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part2.gif b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part2.gif new file mode 100644 index 0000000000..9bc70d361d Binary files /dev/null and b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part2.gif differ diff --git a/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part3.gif b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part3.gif new file mode 100644 index 0000000000..8a8ae32d25 Binary files /dev/null and b/docs/en/Community-Articles/2023-02-22-Streamline-Localization-In-Your-ABP-Project/images/Part3.gif differ diff --git a/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/POST.md b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/POST.md new file mode 100644 index 0000000000..14571157b6 --- /dev/null +++ b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/POST.md @@ -0,0 +1,37 @@ +# Migrating from MS-SQL to Postgresql + +![sql-server-to-postgres](images/sql-server-to-postgres.jpg) + +## Introduction + +Database migration is a common practice for organizations that want to move from one database system to another. This can be for a variety of reasons, including cost, performance, and features. In this article, we will discuss the process of migrating a database from MS-SQL to PostgreSQL, the challenges that may arise during the migration, and how to overcome them. And we recently moved the main database of https://abp.io platform from MS-SQL to PostgreSQL. + +In our case, we decided to switch our database from Microsoft SQL Server (MS-SQL) to PostgreSQL because we wanted to move our on-premise platform to Azure. We’ve also found out that the cost of the license for MS-SQL on Azure was significantly higher than PostgreSQL. After conducting a cost-benefit analysis, we decided to migrate our database to PostgreSQL to save costs. + +Before migrating to Azure, we decided to switch our database from MS-SQL to PostgreSQL on-premise first. This gave us the opportunity to test and fine-tune the migration process before making the final switch to Azure. + +## Challenges + +Despite using a third-party tool(DBConvert for MySQL & PostgreSQL) for the migration, we faced three main problems when exporting data to PostgreSQL. Firstly, some tables with plain text had utf-8 encoding problems. We overcame this problem by dump-restoring these tables. + +![db-converter](images/db-converter.jpg) + + +Secondly, our database had to be case-insensitive, but PostgreSQL does not have this as a default configuration. We handled it using `citext` with the ABP migration service. + +![citext-1](images/citext-1.jpg) +![citext-2](images/citext-2.jpg) +![citext-3](images/citext-3.jpg) + + +While everything was proceeding very smooth, we faced one last problem: importing binary data, such as the content of the NuGet packages. It was hard to understand that the binaries of the NuGet packages were different. Our paid commercial NuGet packages are being stored as binary data in the database. Therefore, it was the most compelling part of this migration to transfer the NuGet packages. Fortunately, we overcame the binary error. And we decided to write a custom .NET tool to move only the binary data from MS-SQL to PostgreSQL, thanks to the ABP Core team! + + +## Conclusion + +One of the benefits of using PostgreSQL is the low license costs of the Azure platform. As the main contributors of ABP, we also use ABP Framework under the hood of our abp.io websites, we could easily switch to PostgreSQL. For those who want to switch their ABP project to PostgreSQL, check out [docs.abp.io/en/abp/latest/Entity-Framework-Core-PostgreSQL](https://docs.abp.io/en/abp/latest/Entity-Framework-Core-PostgreSQL). We had not used any MS-SQL specific function, therefore there was no need to make any changes in the repository classes. This means that the applications that were previously using MS-SQL can seamlessly switch to PostgreSQL without any modifications. + +Thanks to the flexibility of ABP, it has [PostgreSQL package](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql) which is 100% compatible with PostgreSQL. This helped us to make this migration very smooth and seamless. + +In conclusion, migrating a database from MS-SQL to PostgreSQL can be challenging, but it can bring significant cost savings in the long run. By testing and fine-tuning the migration process before making the final switch, we were able to overcome the challenges we’d faced during the migration process. Thanks to the flexibility of ABP, we were able to make the transition with minimal code changes. Also we didn't see any big performance differences between MS-SQL and PostgreSQL. + diff --git a/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-1.jpg b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-1.jpg new file mode 100644 index 0000000000..4dc01228fa Binary files /dev/null and b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-1.jpg differ diff --git a/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-2.jpg b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-2.jpg new file mode 100644 index 0000000000..a70b0312bf Binary files /dev/null and b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-2.jpg differ diff --git a/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-3.jpg b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-3.jpg new file mode 100644 index 0000000000..c8a95d61a5 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/citext-3.jpg differ diff --git a/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/db-converter.jpg b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/db-converter.jpg new file mode 100644 index 0000000000..9c5371d36c Binary files /dev/null and b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/db-converter.jpg differ diff --git a/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/sql-server-to-postgres.jpg b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/sql-server-to-postgres.jpg new file mode 100644 index 0000000000..645de45341 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-15-Migration-Mssql-Postgresql/images/sql-server-to-postgres.jpg differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/Post.md b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/Post.md new file mode 100644 index 0000000000..48db4e9557 --- /dev/null +++ b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/Post.md @@ -0,0 +1,307 @@ +## Introduction +In this article, I will talk about the relationships of IdentityUser in every web application that can be created with the ABP framework. When you read this article, you will learn how to extend the user entity in the applications you develop using the ABP framework with a primitive type, extending the user by associating the user with another entity (User-many-to-one-X). + + +## Creating the Solution +>For the source code of the application: https://github.com/onurpicakci/Abp-Identity-Relationship + +In this article we will use EF Core as the database provider and MVC as the user interface framework. But Angular, Blazor Server and Blazor WebAssembly also work. ABP Framework offers starter templates to get started faster. We can create a new starter template using the ABP CLI: + +```bash +abp new IdentityRelationship +``` + +After the project is created, you can run the `IdentityRelationship.DbMigrator` project to create the database and seed the initial data. You can then run the `IdentityRelationship.Web` project to see our application run. + +> The default admin username is **admin** and the password is **1q2w3E\*** + +![solution-image](images/solution-image.png) + +## Module Entity Extensions + +The module entity extension system is a high level extension system that allows you to define new properties for existing entities of the depended modules. It automatically adds properties to the entity, database, HTTP API and the user interface in a single point. + +### Extending the User Entity With a Primitive Type + +Open the `IdentityRelationshipModuleExtensionConfigurator` class inside the `Domain.Shared` project of your solution and change the `ConfigureExtraProperties` method as shown below to add an `IdentificationNumber` property to the `IdentityUser` entity of the [Identity Module](https://docs.abp.io/en/abp/latest/Modules/Identity). + +```csharp +public static void ConfigureExtraProperties() +{ + OneTimeRunner.Run(() => + { + ObjectExtensionManager.Instance.Modules() + .ConfigureIdentity(identity => + { + identity.ConfigureUser(user => + { + user.AddOrUpdateProperty( //property type: string + "IdentificationNumber", //property name + property => + { + //validation rules + property.Attributes.Add(string.Empty); + property.Attributes.Add( + new StringLengthAttribute(64) { + MinimumLength = 4 + } + ); + + //...other configurations for this property + } + ); + }); + }); + }); +} +``` +> This method is called inside the IdentityRelationshipDomainSharedModule at the beginning of the application. OneTimeRunner is a utility class that guarantees to execute this code only one time per application, since multiple calls are unnecessary. + +If you want to localize, open the `IdentityRelationship.Domain.Shared` project and create a new localization in your `/Localization/IdentityRelationship/en.json` file. + +```json + "IdentificationNumber": "Identification Number" + ``` +Once you define a property, it appears in the create and update forms of the related entity: + + ![identification-number](images/identification-number.png) + + New properties also appear in the data table of the related page: + + ![users-page](images/users-page.png) + + +## Navigation Properties / Foreign Keys + +It is supported to add an extension property to an entity that is the Id of another entity (foreign key). + +### Example: Let's associate a department in the database with a user + +First, create a `Departments` folder in the `IdentityRelationship.Domain` project and add the `Department` class inside: +```csharp +using System; +using Volo.Abp.Domain.Entities; + +namespace IdentityRelationship.Departments; + +public class Department : AggregateRoot +{ + public string Name { get; set; } +} +``` + +EF Core requires that you relate the entities with your `DbContext`. The easiest way to do so is adding a DbSet property to the `IdentityRelationshipDbContext` class in the `IdentityRelationship.EntityFrameworkCore` project, as shown below: + +```csharp + public DbSet Departments { get; set; } +``` + +Then in the `IdentityRelationship.EntityFrameworkCore` project of your solution, open the `/EntityFrameworkCore/IdentityRelationshipEfCoreEntityExtensionMappings` class and update your code: + +```csharp +public static class IdentityRelationshipEfCoreEntityExtensionMappings +{ + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public static void Configure() + { + IdentityRelationshipGlobalFeatureConfigurator.Configure(); + IdentityRelationshipModuleExtensionConfigurator.Configure(); + + OneTimeRunner.Run(() => + { + ObjectExtensionManager.Instance + .MapEfCoreProperty( + "DepartmentId", + (entityBuilder, propertyBuilder) => { propertyBuilder.HasMaxLength(128); } + ); + + }); + } +} +``` + +This class can be used to map these extra properties to table fields in the database. Please read [this](https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities?_ga=2.21022651.140118448.1679289046-1173891759.1672473062) document to improve your understanding of what we are doing. + +We need to create a new migration to see the changes in the database. Open your `EntityFrameworkCore` project in the terminal and run the following command (this depends on the IDE you are using). + +![terminal-image](images/open-terminal.png) + +```bash +dotnet ef migrations add Create_Department_Entity +``` + +Finally, run the `IdentityRelationship.DbMigrator` project to update the database. + +When you look at your database, you can see that the `Department` table has been added and `DepartmentId` has been added to your `AbpUsers` table. + +![database-tables](images/database-tables.png) + +![users-table](images/users-table.png) + +> It's good to have some initial data in the database before running the application. This section introduces the [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding) system of the ABP framework. You can skip this section if you don't want to create the data seeding, but it is suggested to follow along and learn this useful ABP Framework feature. + +Create a class deriving from the `IDataSeedContributor` in the `IdentityRelationship.Domain` project by copying the following code: + +```csharp +using System; +using System.Threading.Tasks; +using IdentityRelationship.Departments; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + +namespace IdentityRelationship; + +public class IdentityRelationshipDataSeederContributor + : IDataSeedContributor, ITransientDependency +{ + private readonly IRepository _departmentRepository; + + public IdentityRelationshipDataSeederContributor(IRepository departmentRepository) + { + _departmentRepository = departmentRepository; + } + + public async Task SeedAsync(DataSeedContext context) + { + if (await _departmentRepository.GetCountAsync() <= 0) + { + await _departmentRepository.InsertAsync( + new Department + { + Name = "Human Resources" + }, + autoSave: true + ); + + await _departmentRepository.InsertAsync( + new Department + { + Name = "Production" + }, + autoSave: true + ); + } + } +} +``` +- This code simply uses the `IRepository` (the default [repository](https://docs.abp.io/en/abp/latest/Repositories)) to insert two books to the database in case there weren't any books in it. + +Run the `IdentityRelationship.DbMigrator` application to update the database: + +![run-dbmigrator](images/run-dbmigrator.png) + +Again, open the `IdentityRelationshipModuleExtensionConfigurator` class in the Domain.Shared project and add the following code: + +```csharp + +user.AddOrUpdateProperty( + "DepartmentId", + property => + { + property.UI.Lookup.Url = "/api/app/department"; + property.UI.Lookup.DisplayPropertyName = "name"; + } +); +``` + +The `UI.Lookup.Url` option takes a URL to get the list of departments to select on the edit/create forms. This endpoint can be a typical controller, an auto API controller or any type of endpoint that returns a proper JSON response. + +To localize, open the `IdentityRelationship.Domain.Shared` project and add it to your `/Localization/IdentityRelationship/en.json` file: + +```json +"DepartmentId": "Department" +``` + +Create a `Departments` folder in the `IdentityRelationship.Application.Contracts` project of your solution and add the `DepartmentDto` class in it + +```csharp +using System; +using Volo.Abp.Application.Dtos; +namespace IdentityRelationship.Departments; + +public class DepartmentDto : EntityDto + +{ + public string Name { get; set; } +} +``` +Now let's create an `IDepartmentAppService` interface in the `Departments` folder + +```csharp +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace IdentityRelationship.Departments; + +public interface IDepartmentAppService : IApplicationService +{ + public Task> GetAsync(); +} +``` + +Time to implement the `IDepartmentAppService` interface. Create a `Departments` folder in your `IdentityRelationship.Application` project and add the `DepartmentAppService` class inside. + +```csharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using IdentityRelationship.Departments; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Domain.Repositories; + +namespace IdentityRelationship.Department; + +public class DepartmentAppService : IdentityRelationshipAppService, IDepartmentAppService +{ + private readonly IRepository _departmentRepository; + + public DepartmentAppService(IRepository departmentRepository) + { + _departmentRepository = departmentRepository; + } + + public async Task> GetAsync() + { + var departments = await _departmentRepository.GetListAsync(); + return new ListResultDto( + ObjectMapper.Map, List>(departments)); + } +} +``` +`DepartmentAppService `is using the `ObjectMapper` to convert the `Department` objects to `DepartmentDto` objects. So, we need to define this mapping in the AutoMapper configuration. + +Open the `IdentityRelationshipApplicationAutoMapperProfile` class inside the `IdentityRelationship.Application` project and add the following line to the constructor: + +```csharp +using AutoMapper; +using IdentityRelationship.Departments; + +namespace IdentityRelationship; + +public class IdentityRelationshipApplicationAutoMapperProfile : Profile +{ + public IdentityRelationshipApplicationAutoMapperProfile() + { + CreateMap(); + } +} +``` + +Run your `IdentityRelationship.Web` project and add a department to one of your users. + +![user-department-image](images/user-department.png) + +And it shows the department name on the data table: + +![users-page-department-image](images/users-page-department.png) + +## Conclusion +In this article I talked about the use of the IdentityUser relationship and how to extend it. Thank you for reading the article, I hope it was useful. See you soon! + +## References +- https://docs.abp.io/en/abp/latest/Module-Entity-Extensions +- https://learn.microsoft.com/en-us/ef/core/modeling/relationships +- https://community.abp.io/posts/how-to-add-custom-properties-to-the-user-entity-rixchoha \ No newline at end of file diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/database-tables.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/database-tables.png new file mode 100644 index 0000000000..a1cef0bc26 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/database-tables.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/identification-number.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/identification-number.png new file mode 100644 index 0000000000..75fdd94768 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/identification-number.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/open-terminal.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/open-terminal.png new file mode 100644 index 0000000000..9f1069d02b Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/open-terminal.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/run-dbmigrator.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/run-dbmigrator.png new file mode 100644 index 0000000000..6e42848862 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/run-dbmigrator.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/solution-image.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/solution-image.png new file mode 100644 index 0000000000..cd54f473f4 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/solution-image.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/user-department.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/user-department.png new file mode 100644 index 0000000000..feb97234c3 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/user-department.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-page-department.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-page-department.png new file mode 100644 index 0000000000..c923c9fc4b Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-page-department.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-page.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-page.png new file mode 100644 index 0000000000..5622e11373 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-page.png differ diff --git a/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-table.png b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-table.png new file mode 100644 index 0000000000..81b2cf90dd Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20- IdentityUser-Relationships/images/users-table.png differ diff --git a/docs/en/Community-Articles/2023-03-20-Dapper/POST.md b/docs/en/Community-Articles/2023-03-20-Dapper/POST.md new file mode 100644 index 0000000000..491c9a010c --- /dev/null +++ b/docs/en/Community-Articles/2023-03-20-Dapper/POST.md @@ -0,0 +1,297 @@ +# Using Dapper with the ABP Framework + +[Dapper](https://github.com/DapperLib/Dapper) is a simple and lightweight object mapper for .NET. A key feature of Dapper is its [high performance](https://github.com/DapperLib/Dapper#performance) compared to other ORMs. In this article, I will show how to use it in your ABP projects. But, we'll see when to use it first. + +### Source Code + +You can find the [full source code of the demo application here](https://github.com/abpframework/abp-samples/tree/master/Dapper). + +## When to Use Dapper? + +In the ABP Framework, we suggest to use Dapper in combination with Entity Framework Core (EF Core) for the following reasons: + +* EF Core is much easier to use (you don't need to manually write SQL queries and work with low level database objects). +* EF Core abstracts different DBMS dialects, so it will be easier to change your DBMS later. +* The EF Core's change tracking system automatically updates the changes in the database. +* EF Core is better compatible with Object Oriented Programming (OOP) practices and is more type safe to work with. So, the EF Core code is more understandable and maintainable. + +In most of your use cases, you typically work with one or a few entities and a maintainable codebase can be chosen instead of a slight performance difference. However, there may be certain places in your application where it matters: + +* You may work with a lot of entities, so you'd like to query faster (Indeed, EF Core's [AsNoTracking()](https://learn.microsoft.com/en-us/ef/core/querying/tracking) extension can help in most cases). +* You may be performing too many database operations in a single request. +* EF Core may not create an optimized SQL query and you may want to manually write it for better performance. + +For such cases, Dapper can be a good choice. You can easily write SQL queries and bind the result to your objects. + +## Creating a new ABP Solution + +To demonstrate the useage of Dapper, I've created an ABP solution. You can find the [full source code of the demo application here](https://github.com/abpframework/abp-samples/tree/master/Dapper). If you want to create the same solution from scratch, follow the steps below: + +Install the ABP CLI if you haven't installed it before: + +````bash +dotnet tool install -g Volo.Abp.Cli +```` + +Create a new solution with the ABP Framework's non-layered startup template with MVC UI and EF Core database: + +````bash +abp new DapperDemo -t app-nolayers +```` + +> The startup template and UI selection don't matter for this article. I selected these options to keep the demo solution simple. + +After creating the solution, run the following command to migrate the database (run the command in the folder of the `.csproj` file: + +````csharp +dotnet run --migrate-database +```` + +> If you've created a layered solution, then run the `DbMigrator` application inside the solution. If you have trouble by creating the solution, please refer to the [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Single-Layer/Index) document. + +## Setting Up the Entity Framework Core Part + +We will use EF Core with Dapper, so we need to configure EF Core first. I will use the following `Book` entity as an example: + +````csharp +public class Book : AuditedAggregateRoot +{ + public string Name { get; set; } + public DateTime PublishDate { get; set; } + public float Price { get; set; } +} +```` + +If you are using a layered solution, entities are located in the `Domain` project. For my demo solution, I just placed it in the `Entities` folder of the single-layer project: + +![book-class-in-rider](book-class-in-rider.png) + +Once I created the `Book` entity, I should add it to my `DbContext` class: + +````csharp +public class DapperDemoDbContext : AbpDbContext +{ + // 1: ADD A DBSET PROPERTY + public DbSet Books { get; set; } + + public DapperDemoDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder builder) + { + //...other code parts + + // 2: MAP YOUR ENTITY TO A DATABASE TABLE + builder.Entity(b => + { + b.ToTable("Books"); + b.Property(x => x.Name).IsRequired().HasMaxLength(128); + }); + } +} + +```` + +Now, we can add a new database migration: + +````bash +dotnet ef migrations add Added_Book +```` + +And apply the changes to the database: + +````bash +dotnet ef database update +```` + +At this point, you should be able to see the Books table if you check your database: + +![book-database-table](book-database-table.png) + +> As you see, the `Books` table contains more fields than the `Book` entity's property count. Other properties are inherited from the `AuditedAggregateRoot` table. You could inherit from the `BasicAggregateRoot` class if you don't want these properties. + +## Seeding the Database + +ABP's [data seeding](https://docs.abp.io/en/abp/latest/Data-Seeding) system is a great way to add some test data to the database. The following class inserts two books to the `Books` table when I migrate the database: + +````csharp +public class DapperDemoDataSeederContributor : IDataSeedContributor, ITransientDependency +{ + private readonly IRepository _bookRepository; + + public DapperDemoDataSeederContributor(IRepository bookRepository) + { + _bookRepository = bookRepository; + } + + public async Task SeedAsync(DataSeedContext context) + { + if (await _bookRepository.GetCountAsync() > 0) + { + return; + } + + await _bookRepository.InsertAsync( + new Book + { + Name = "1984", + PublishDate = new DateTime(1949, 6, 8), + Price = 19.84f + } + ); + + await _bookRepository.InsertAsync( + new Book + { + Name = "The Hitchhiker's Guide to the Galaxy", + PublishDate = new DateTime(1995, 9, 27), + Price = 42.0f + } + ); + } +} +```` + +After creating the `DapperDemoDataSeederContributor` class, I can re-run the following command: + +````bash +dotnet run --migrate-database +```` + +Now, I can see the records in the database: + +![book-table-data](book-table-data.png) + +Now, everything is ready to try querying from the `Books` table with Dapper. + +## Using Dapper Without the Integration Package + +ABP provides an integration package for Dapper. However, I first want to demonstrate using Dapper without the integration package. + +### Installing the Dapper Package + +First, install the [Dapper](https://www.nuget.org/packages/Dapper) package to your project. You can use a command-line terminal, locate the root path of your project (`.csproj` file that you want to install it in) and run the following command: + +````bash +dotnet add package Dapper +```` + +> If your application is layered, then we suggest to add the `Dapper` package to your `EntityFrameworkCore` integration project in your solution. + +### Executing a Dapper Query + +I will query from the `Books` table, but I don't want to use the `Book` entity to map the result (because I don't need all the properties). So, I am creating a new class for the query result: + +````csharp +public class BookDataView +{ + public Guid Id { get; set; } + public string Name { get; set; } + public float Price { get; set; } +} +```` + +Now, we can use Dapper's `QueryAsync` extension method as shown below: + +````csharp +public class DemoService : ITransientDependency +{ + private readonly IRepository _bookRepository; + + public DemoService(IRepository bookRepository) + { + _bookRepository = bookRepository; + } + + [UnitOfWork] + public virtual async Task> GetListAsync() + { + var database = (await _bookRepository.GetDbContextAsync()).Database; + var dbConnection = database.GetDbConnection(); + var dbTransaction = database.CurrentTransaction?.GetDbTransaction(); + + var queryResult = await dbConnection.QueryAsync( + "SELECT Id, Name, Price FROM Books", + transaction: dbTransaction + ); + + return queryResult.ToList(); + } +} +```` + +Let's examine this class: + +* I've injected the ABP's standard [generic repository](https://docs.abp.io/en/abp/latest/Repositories) service into the `DemoService` constructor. +* `_bookRepository.GetDbContextAsync()` returns the underlying `DbContext` object of EF Core. We need to have the [Volo.Abp.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore) package reference to be able to access that method. If you have created a single-layer solution, the reference will already have existed. If you have created a layered solution you may need to manually add this package to the project that contains the `DemoService` class. Because the layered solution isolates the EF Core dependency from the rest of the solution. +* Dapper needs a `DbConnection` and a `DbTransaction` object (as optional) to execute a query. We are getting them over the `database` object obtained from the `DbContext`. We suggest to always pass the current `DbTransaction` object while working with Dapper. Because, if there is a database transaction on the same database connection that you execute queries on, and you don't pass the transaction object, you'll get an exception. +* Finally, we can use Dapper's `QueryAsync` extension method to execute the database query. +* Notice that the `GetListAsync` method is made as `virtual` and marked with the `UnitOfWork` attribute to enable the [Unit Of Work](https://docs.abp.io/en/abp/latest/Unit-Of-Work) for that method. It ensures the database connection is available in the body of the `GetListAsync` method. + +That's all. You can execute any Dapper operation using the `DbConnection` and `DbTransaction` objects obtained from the `_bookRepository` object. Please refer to Dapper's documentation for other operations. + +> We've obtained the `DbContext` object from a repository. However, a repository is not required to obtain a `DbContext`. Instead, you could inject the `IDbContextProvider` service (`IDbContextProvider` for this demo) and call its `GetDbContextAsync` method. + +## Using the Volo.Abp.Dapper Package + +In the previous section, you saw that you don't need an ABP integration package to be able to use Dapper in your ABP applications. However, there is an integration package here: [Volo.Abp.Dapper](https://www.nuget.org/packages/Volo.Abp.Dapper). In fact, that package doesn't contain much services. It just provides a convenient base class to create Dapper based repository classes. + +### Installing the Volo.Abp.Dapper Package + +You can use the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI#add-package) to easily install ABP packages to your projects. Execute the following command in the folder of the `.csproj` file that you want to install the package on: + +````bash +abp add-package Volo.Abp.Dapper +```` + +> You can check the [ABP Dapper document](https://docs.abp.io/en/abp/latest/Dapper) for alternative installation options. + +### Creating a Repository Class + +In the `DemoService` example, we used database objects out of a [repository](https://docs.abp.io/en/abp/latest/Repositories) class. If you want to implement layering to your solution and abstracting database operations, it can be better to create a repository class to execute the Dapper operations. + +Here's a repository class that executes the same database query: + +````csharp +public class BookRepository : DapperRepository, ITransientDependency +{ + public BookRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public virtual async Task> GetListAsync() + { + var connection = await GetDbConnectionAsync(); + var queryResult = await connection.QueryAsync( + "SELECT Id, Name, Price FROM Books", + transaction: await GetDbTransactionAsync() + ); + return queryResult.ToList(); + } +} +```` + +Let's examine this class: + +* It inherits from the `DapperRepository` class, which provides useful methods and properties for database operations. It also implements the `IUnitOfWorkEnabled` interface, so ABP makes the database connection (and transaction if requested) available in the method body by implementing dynamic proxies (a.k.a. interception). +* The `GetListAsync` method's been made `virtual`. That's needed to make the interception process working. It wouldn't be needed if we introduce `IBookRepository` to that class and always use it by injecting the `BookRepository` class (in this case, it will use interface proxying - however, this is too much details for the purpose of this article). +* We've used the `GetDbConnectionAsync` and `GetDbTransactionAsync` methods to obtain the current database connection and transaction (that is managed by ABP's [unit of work](https://docs.abp.io/en/abp/latest/Unit-Of-Work) system). + +You can then inject the `BookRepository` class when you want to get a list of `BookDataView` whenever it is needed. In the demo project, I used it inside the `IndexModel.cshtml.cs` to show a list of books on the page: + +![list-of-books](list-of-books.png) + +## Conclusion + +In this article, I've explained ABP's Dapper integration and demonstrated how you can execute Dapper operations in your applications. I suggest to use Dapper when it is really needed and adds any significant value (generally a performance gain) to your application. Otherwise, EF Core is much more convenient for most of the database operations and you will have a more maintainable codebase using EF Core. + +## Source Code + +You can find the [full source code of the demo application here](https://github.com/abpframework/abp-samples/tree/master/Dapper). + +## See Also + +* [ABP Dapper documentation](https://docs.abp.io/en/abp/latest/Dapper) diff --git a/docs/en/Community-Articles/2023-03-20-Dapper/book-class-in-rider.png b/docs/en/Community-Articles/2023-03-20-Dapper/book-class-in-rider.png new file mode 100644 index 0000000000..db1e5791b4 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20-Dapper/book-class-in-rider.png differ diff --git a/docs/en/Community-Articles/2023-03-20-Dapper/book-database-table.png b/docs/en/Community-Articles/2023-03-20-Dapper/book-database-table.png new file mode 100644 index 0000000000..d1584118d9 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20-Dapper/book-database-table.png differ diff --git a/docs/en/Community-Articles/2023-03-20-Dapper/book-table-data.png b/docs/en/Community-Articles/2023-03-20-Dapper/book-table-data.png new file mode 100644 index 0000000000..6b9ea69b59 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20-Dapper/book-table-data.png differ diff --git a/docs/en/Community-Articles/2023-03-20-Dapper/list-of-books.png b/docs/en/Community-Articles/2023-03-20-Dapper/list-of-books.png new file mode 100644 index 0000000000..23b190afa6 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-20-Dapper/list-of-books.png differ diff --git a/docs/en/Community-Articles/2023-03-27-What-is-new-in-NET8/cover.jpg b/docs/en/Community-Articles/2023-03-27-What-is-new-in-NET8/cover.jpg new file mode 100644 index 0000000000..aa0f3694d4 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-27-What-is-new-in-NET8/cover.jpg differ diff --git a/docs/en/Community-Articles/2023-03-27-What-is-new-in-NET8/post.md b/docs/en/Community-Articles/2023-03-27-What-is-new-in-NET8/post.md new file mode 100644 index 0000000000..5ae3ff2ce0 --- /dev/null +++ b/docs/en/Community-Articles/2023-03-27-What-is-new-in-NET8/post.md @@ -0,0 +1,226 @@ +# What’s New in .NET 8 🧐 ? Discover ALL .NET 8 Features⚡🚀 + +In this post, I'll briefly mention the new features of .NET 8 and the changes. + +## `dotnet publish` and `dotnet pack` Release Mode 🏭 + +With this new version, `dotnet publish` and `dotnet pack` commands will build and pack with the `Release` mode. Before it was producing in `Debug` mode. To be able to produce in Debug mode, you need to set this parameter `-p:PublishRelease` as false. + +```bash +dotnet publish -> /app/bin/Release/net8.0/app.dll +dotnet publish -p:PublishRelease=false -> /app/bin/Debug/net8.0/app.dll +``` + +--- + + + +## System.Text.Json Serialization 🧱 + +[System.Text.Json](https://learn.microsoft.com/en-us/dotnet/api/system.text.json) replaced Newtonsoft.Json in the recent versions. We are also using `System.Text.Json` in the [ABP Framework](https://abp.io) now. There are several enhancements to object serialization and deserialization. + +The latest version of the [source generator](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation) now offers improved performance and reliability for Native AOT apps when used with ASP.NET Core. It also allows serializing types with [`required`](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/required-properties) and [`init`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init) properties already supported in reflection-based serialization. Additionally, there is now an option to customize the handling of members that are not present in the JSON payload, see https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/missing-members. Support for serializing properties from interface hierarchies. The [JsonNamingPolicy](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonnamingpolicy?view=net-8.0&preserve-view=true#properties) feature has been expanded to include new naming policies for `snake_case` and `kebab-case` property name conversions. Finally, [JsonSerializerOptions.MakeReadOnly](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.makereadonly#system-text-json-jsonserializeroptions-makereadonly) method allows for explicit control over when a `JsonSerializerOptions` instance is frozen, and you can check its status using the [IsReadOnly](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.isreadonly#system-text-json-jsonserializeroptions-isreadonly) property. + +--- + + + +## Randomness + +AI programming is very popular these days. And the need to produce more random content arose. + +### GetItems() 🧮 + +Two new methods: [Random.GetItems](https://learn.microsoft.com/en-us/dotnet/api/system.random.getitems) and [RandomNumberGenerator.GetItems](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator.getitems) have been introduced that enable developers to randomly select a set number of items from a given input set. The example below demonstrates the usage of the `System.Random.GetItems()` method using an instance obtained from the `Random.Shared` property to randomly insert 31 items into an array. + +```csharp +private static ReadOnlySpan countries = new[] +{ + new CountryPhoneCode("Turkey", "90"), + new CountryPhoneCode("China", "86"), + new CountryPhoneCode("Germany", "49"), + new CountryPhoneCode("Finland", "358"), + new CountryPhoneCode("Spain", "34") +}; + +var randomValues = Random.Shared.GetItems(countries, 2); +foreach (var x in randomValues) +{ + Console.WriteLine(x.Name + " -> " + x.CountryPhoneCode); +} + +/************** +- Output - +Germany -> 49 +Finland -> 358 +**************/ +``` + +--- + + + +### Shuffle() 🔀 + +If you need to randomize the order of a span in your application, you can take advantage of two new methods: [Random.Shuffle](https://learn.microsoft.com/en-us/dotnet/api/system.random.shuffle) and [RandomNumberGenerator.Shuffle](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator.shuffle?view=net-8.0). These methods are particularly handy when you want to minimize the impact of training bias in machine learning by varying the order in which training and testing data are presented. Using these methods, you can ensure that the first thing in your dataset is only sometimes used for training, and the last is only sometimes reserved for testing. + +```csharp +var trainingData = GetData(); +Random.Shared.Shuffle(trainingData); + +IDataView source = mlContext.Data.LoadFromEnumerable(trainingData); + +DataOperationsCatalog.TrainTestData splittedData = mlContext.Data.TrainTestSplit(source); +model = chain.Fit(splittedData.TrainSet); + +IDataView resultPredictions = model.Transform(split.TestSet); +``` + +--- + + + +## Performance Improvements 🚀 + +In .NET 8, various new types have been introduced to enhance application performance. + +- The [System.Collections.Frozen](https://learn.microsoft.com/en-us/dotnet/api/system.collections.frozen) namespace in .NET 8 includes the [FrozenDictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.frozen.frozendictionary-2) and [FrozenSet](https://learn.microsoft.com/en-us/dotnet/api/system.collections.frozen.frozenset-1) collection types. These types are designed to prevent changes to keys and values once a collection is created, resulting in faster read operations such as `TryGetValue()`. They are particularly useful for collections populated on first use and then persisted for a long-lived service. + + ```csharp + private static readonly FrozenDictionary frozenData = LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true); + ////// + if (frozenData.TryGetValue(key, out bool setting) && setting) + { + Process(); + } + ``` + +- [Buffers.IndexOfAnyValues](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.indexofanyvalues-1) is a new type in .NET 8, designed to be passed to methods that search for the first occurrence of any value in a passed collection. The new overloads of methods like [String.IndexOfAny](https://learn.microsoft.com/en-us/dotnet/api/system.string.indexofany?view=net-8.0#system-string-indexofany(system-char())) and [MemoryExtensions.IndexOfAny](https://learn.microsoft.com/en-us/dotnet/api/system.memoryextensions.indexofany) accept an instance of the new type. When you create an instance of [Buffers.IndexOfAnyValues](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.indexofanyvalues-1), all the necessary data for optimizing subsequent searches is derived at that time. + +- [Text.CompositeFormat](https://learn.microsoft.com/en-us/dotnet/api/system.text.compositeformat) is a new type in .NET 8 useful for optimizing format strings that aren't known at compile time (such as format strings loaded from a resource file). While some extra time is spent upfront to perform tasks like parsing the string, it saves the work from being done each time the format string is used. + + ```csharp + private static readonly CompositeFormat range = CompositeFormat.Parse(Load()); + ////////// + static string GetMessage(int min, int max) => + string.Format(CultureInfo.InvariantCulture, range, min, max); + ``` + +- In .NET 8, two new types are introduced to implement the fast [XxHash3](https://learn.microsoft.com/en-us/dotnet/api/system.io.hashing.xxhash3) and [XxHash128](https://learn.microsoft.com/en-us/dotnet/api/system.io.hashing.xxhash128) hash algorithms. + +--- + + + +## Improvements in System.Numerics and System.Runtime.Intrinsics 🔥 + +There are several enhancements made to the [System.Numerics](https://learn.microsoft.com/en-us/dotnet/api/system.numerics) and [System.Runtime.Intrinsics](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.intrinsics) namespaces. These improvements include better hardware acceleration for [Vector256](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.intrinsics.vector256-1), [Matrix3x2](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.matrix3x2), and [Matrix4x4](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.matrix4x4) in .NET 8. + +[Vector256](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.intrinsics.vector256-1) was redesigned to utilize `2x Vector128` operations internally to achieve partial acceleration of certain functions on `Arm64` processors where `Vector128.IsHardwareAccelerated == true` but `Vector256.IsHardwareAccelerated == false`. The introduction of [Vector512](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.intrinsics.vector512-1) is also included in .NET 8. + +Additionally, the `ConstExpected` attribute has been added to hardware intrinsic to alert users when a non-constant value might cause unexpected performance issues. + +Lastly, the [Lerp(TSelf, TSelf, TSelf)](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.ifloatingpointieee754-1.lerp#system-numerics-ifloatingpointieee754-1-lerp(-0-0-0)) API has been added to [IFloatingPointIeee754](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.ifloatingpointieee754-1), enabling the efficient and accurate linear interpolation of two values in `float`([Single](https://learn.microsoft.com/en-us/dotnet/api/system.single)), `double` ([Double](https://learn.microsoft.com/en-us/dotnet/api/system.double)), and [Half](https://learn.microsoft.com/en-us/dotnet/api/system.half). + +--- + + + +## New Data Validation Attributes 🛡️ + +The [DataAnnotations](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations) namespace, aimed specifically for validation in cloud-native services. The existing `DataAnnotations` validators are primarily used for validating user data, like form fields. However, the new attributes are meant to validate data, not entered by users, like [configuration options](https://learn.microsoft.com/en-us/dotnet/core/extensions/options#options-validation). Apart from the new attributes, the [RangeAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.rangeattribute) and [RequiredAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.requiredattribute) types also received new properties. + +- [RequiredAttribute.DisallowAllDefaultValues](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.requiredattribute.disallowalldefaultvalues#system-componentmodel-dataannotations-requiredattribute-disallowalldefaultvalues): The attribute forces that structs for inequality with their default values. +- [RangeAttribute.MinimumIsExclusive](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.rangeattribute.minimumisexclusive#system-componentmodel-dataannotations-rangeattribute-minimumisexclusive) & [RangeAttribute.MaximumIsExclusive](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.rangeattribute.maximumisexclusive#system-componentmodel-dataannotations-rangeattribute-maximumisexclusive): Specifies whether the allowable range includes its boundaries or not. +- [DataAnnotations.LengthAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.lengthattribute): Specifies the lower and upper limits for strings or collections using the `Length` attribute. For instance, the `[Length(5, 100)]` attribute specifies that a collection must have at least 5 elements and at most 100 elements. +- [DataAnnotations.Base64StringAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.base64stringattribute): Validates a valid `Base64` format. +- [DataAnnotations.AllowedValuesAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.allowedvaluesattribute) & [DataAnnotations.DeniedValuesAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.deniedvaluesattribute): Specifies accepted allow lists or not allowed deny lists. For instance: `[AllowedValues("red", "green", "blue")]` or `[DeniedValues("yellow", "purple")]`. + + + +--- + + + +## Function Pointers Introspection Support ↩️ + +[Function pointers](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code#function-pointers) were released with .NET 5. There was no support for reflection at that time. As a result, using `typeof` or reflection on a function pointer, such as `typeof(delegate*())` or `FieldInfo.FieldType`, respectively, would return an [IntPtr](https://learn.microsoft.com/en-us/dotnet/api/system.intptr). However, in .NET 8, a [System.Type](https://learn.microsoft.com/en-us/dotnet/api/system.type) object is returned instead, providing access to function pointer metadata, such as calling conventions, return type, and parameters. This functionality is implemented only in the `CoreCLR` runtime and [MetadataLoadContext](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.metadataloadcontext). + +--- + + + +## Native AOT 🏭 + +The [publishing as native AOT](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/) was initially introduced in .NET 7, the option to publish an application as native AOT enables the creation of a self-contained version of the app that does not require a separate runtime, bundling everything into a single file. + +In .NET 8, the support for native AOT now encompasses the `x64` and `Arm64` architectures on macOS. Moreover, native AOT applications on Linux are now up to 50% smaller in size. Here's the table, illustrates the size of a minimal app published with native AOT, containing the entire .NET runtime: + + + +* **Linux x64** (with `-p:StripSymbols=true`) + * .NET 7 ➡ 3.76MB + * .NET 8 ➡ 1.84 MB +* **Windows x64** + * .NET 7 ➡ 2.85 MB + * .NET 8 ➡ 1.77 MB + +--- + + + +## Code Generation Improvements 📃 + +.NET 8 includes enhancements to code generation and just-in-time (*JIT*) compilation: + +- JIT throughput improvements +- Arm64 performance improvements +- Profile-guided optimization (PGO) improvements +- Support for AVX-512 ISA extensions +- SIMD improvements +- Cloud-native improvements +- Loop and general optimizations + +--- + + + +## .NET 8 DevOps Improvements 📦 + +### NET Container Image Changes + +There are some changes with .NET 8 on image containers. First, [Debian 12](https://wiki.debian.org/DebianBookworm) is the **default Linux distribution** in the container images. + +Secondly, the images include a `non-root` user to make the images `non-root` capable. To run as `non-root`, add the line `USER app` at the end of your `Dockerfile`. + +Besides, the **default port has also changed** from `80` to `8080` and a **new environment variable** `ASPNETCORE_HTTP_PORTS` is available to change ports easily. + +Also, the format for the `ASPNETCORE_HTTP_PORTS` variable is easier compared to the format required by `ASPNETCORE_URLS`, and it accepts a list of ports. If you change the port back to `80` using one of these variables, it won’t be possible to run as `non-root`. + +Finally, .NET 8 is now supported on **Chiseled Ubuntu** images, available at the [Ubuntu/DotNet-deps Docker Hub](Ubuntu/DotNet-deps Docker Hub). Chiseled images are designed to have a smaller attack surface as they are stripped down to be ultra-compact, and do not include a package manager or shell. Chiseled images are non-root, making them ideal for developers looking for the benefits of appliance-style computing. These images are regularly published to the [.NET nightly artifact registry](https://mcr.microsoft.com/product/dotnet/nightly/aspnet/tags) for easy access. + +### Building Your .NET on Linux + +Previously, building .NET from source in earlier versions required creating a `source tarball` from the corresponding release commit in the [dotnet/installer repository](dotnet/installer repository). However, in .NET 8, this step is no longer necessary as the [dotnet/dotnet repository](https://github.com/dotnet/dotnet) allows building .NET directly on Linux using [dotnet/source-build](https://github.com/dotnet/source-build) to create runtimes, tools, and SDKs. Red Hat and Canonical also use this build for .NET. Building in a container is the easiest approach for most people since the `dotnet-buildtools/prereqs` container images have all the necessary dependencies. [The build instructions]() provide more information. + +### Minimum support baselines for Linux + +The support requirements for Linux have been updated for .NET 8, with changes to the minimum support baselines: + +1. All architectures will target Ubuntu 16.04 for building .NET, which is important for setting the minimum required version of `glibc` for .NET 8. Versions of Ubuntu earlier than 16.04, such as 14.04, will not even allow .NET 8 to start. +2. **Red Hat Enterprise Linux 7 is no longer supported** with .NET 8. Only supporting RHEL 8 and later. + +For further details, please refer to the [support for Red Hat Enterprise Linux Family](https://github.com/dotnet/core/blob/main/linux-support.md#red-hat-enterprise-linux-family-support) page. + + + +--- + +Become a pioneer and try the new features of .NET 8 now. +Adapt it to your project or start a new .NET 8 project. +[Claim your copy of .NET 8](https://dotnet.microsoft.com/next) today 🏎️ ! + +〰️〰️〰️ + +Happy Coding ⌨️ + diff --git a/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/POST.md b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/POST.md new file mode 100644 index 0000000000..4904da48cf --- /dev/null +++ b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/POST.md @@ -0,0 +1,372 @@ +# Convert Create/Edit Modals to Page +In this document we will explain how to convert BookStore's Books create & edit modals to regular blazor pages. + +## Before +![bookstore-crud-before](images/old.gif) + +## After + +![bookstore-crud-after](images/new.gif) + + +# Books.razor Page +Books.razor page is the main page of the books management. Create & Update operations are done in this page. So we'll remove create & update operations from this page and move a separate blazor component for each operation. Each component will be a page. + +- Remove both Create & Update modals. + + ![remove-all-modals](images/books-remove-modals.png) + +- Replace **NewBook** button with a link to **CreateBook** page. + + ```html + + ``` + +- Inject `NavigationManager` to `Books.razor` page. + ```csharp + @inject NavigationManager NavigationManager + ``` + +- Replace **Edit** button with a link to **UpdateBook** page. + + ```html + + ``` + + ```csharp + private void NavigateToEdit(Guid id) + { + NavigationManager.NavigateTo($"books/{id}/edit"); + } + ``` + +- Remove all methods in the `Books.razor` page except constructor. And add `GoToEditPage` as below: + + ```csharp + protected void GoToEditPage(BookDto book) + { + NavigationManager.NavigateTo($"books/{book.Id}"); + } + ``` + + ![bookstore-remove-methods](images/books-remove-methods.png) + +- Change Edit button to a link in the table. + + ```html + + ``` + + +# CreateBooks Page +Create new `CreateBook.razor` and `CreateBook.razor.cs` files in your project. + +- `CreateBook.razor` + +```html +@page "/books/new" +@attribute [Authorize(BookStorePermissions.Books.Create)] +@inherits BookStoreComponentBase + +@using Acme.BookStore.Books; +@using Acme.BookStore.Localization; +@using Acme.BookStore.Permissions; +@using Microsoft.Extensions.Localization; +@using Volo.Abp.AspNetCore.Components.Web; + +@inject IStringLocalizer L +@inject AbpBlazorMessageLocalizerHelper LH +@inject IBookAppService AppService +@inject NavigationManager NavigationManager + + + + + @L["NewBook"] + + + + + + + @L["Author"] + + + + @L["Name"] + + + + + + + + + @L["Type"] + + + + @L["PublishDate"] + + + + @L["Price"] + + + + + + + + + +``` + +- `CreateBook.razor.cs` + +```csharp +using Acme.BookStore.Books; +using Blazorise; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; + +namespace Acme.BookStore.Blazor.Pages; + +public partial class CreateBook +{ + protected Validations CreateValidationsRef; + protected CreateUpdateBookDto NewEntity = new(); + IReadOnlyList authorList = Array.Empty(); + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + authorList = (await AppService.GetAuthorLookupAsync()).Items; + + if (!authorList.Any()) + { + throw new UserFriendlyException(message: L["AnAuthorIsRequiredForCreatingBook"]); + } + + NewEntity.AuthorId = authorList.First().Id; + + if (CreateValidationsRef != null) + { + await CreateValidationsRef.ClearAll(); + } + } + + protected virtual async Task CreateEntityAsync() + { + try + { + var validate = true; + if (CreateValidationsRef != null) + { + validate = await CreateValidationsRef.ValidateAll(); + } + if (validate) + { + await AppService.CreateAsync(NewEntity); + NavigationManager.NavigateTo("books"); + } + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } +} +``` + +# EditBooks Page +Create new `EditBook.razor` and `EditBook.razor.cs` files in your project. + +- `EditBook.razor` + +```html +@page "/books/{Id}" +@attribute [Authorize(BookStorePermissions.Books.Edit)] +@inherits BookStoreComponentBase +@using Acme.BookStore.Books; +@using Acme.BookStore.Localization; +@using Acme.BookStore.Permissions; +@using Microsoft.Extensions.Localization; +@using Volo.Abp.AspNetCore.Components.Web; + +@inject IStringLocalizer L +@inject AbpBlazorMessageLocalizerHelper LH +@inject IBookAppService AppService +@inject NavigationManager NavigationManager + + + + + @EditingEntity.Name + + + + + + + @L["Author"] + + + + @L["Name"] + + + + + + + + + @L["Type"] + + + + @L["PublishDate"] + + + + @L["Price"] + + + + + + + + + +``` + +- `EditBook.razor.cs` + +```csharp +using Acme.BookStore.Books; +using Blazorise; +using Microsoft.AspNetCore.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; + +namespace Acme.BookStore.Blazor.Pages; + +public partial class EditBook +{ + protected CreateUpdateBookDto EditingEntity = new(); + protected Validations EditValidationsRef; + IReadOnlyList authorList = Array.Empty(); + + [Parameter] + public string Id { get; set; } + + public Guid EditingEntityId { get; set; } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + // Blazor can't parse Guid as route constraint currently. + // See https://github.com/dotnet/aspnetcore/issues/19008 + EditingEntityId = Guid.Parse(Id); + + authorList = (await AppService.GetAuthorLookupAsync()).Items; + + if (!authorList.Any()) + { + throw new UserFriendlyException(message: L["AnAuthorIsRequiredForCreatingBook"]); + } + + var entityDto = await AppService.GetAsync(EditingEntityId); + + EditingEntity = ObjectMapper.Map(entityDto); + + if (EditValidationsRef != null) + { + await EditValidationsRef.ClearAll(); + } + } + + protected virtual async Task UpdateEntityAsync() + { + try + { + var validate = true; + if (EditValidationsRef != null) + { + validate = await EditValidationsRef.ValidateAll(); + } + if (validate) + { + await AppService.UpdateAsync(EditingEntityId, EditingEntity); + + NavigationManager.NavigateTo("books"); + } + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } +} +``` + +You can check the following commit for details: +https://github.com/abpframework/abp-samples/commit/aae61ad6d66ebf6191dd4dcfb4e23d30bd680a4e \ No newline at end of file diff --git a/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/books-remove-methods.png b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/books-remove-methods.png new file mode 100644 index 0000000000..a2df67fee2 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/books-remove-methods.png differ diff --git a/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/books-remove-modals.png b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/books-remove-modals.png new file mode 100644 index 0000000000..0e9fd6e8d4 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/books-remove-modals.png differ diff --git a/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/new.gif b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/new.gif new file mode 100644 index 0000000000..42784eb281 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/new.gif differ diff --git a/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/old.gif b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/old.gif new file mode 100644 index 0000000000..80a97a80f2 Binary files /dev/null and b/docs/en/Community-Articles/2023-03-28-Converting-Create-Edit-Modal-To-Page/images/old.gif differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/abp-framework.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/abp-framework.png new file mode 100644 index 0000000000..b1157793bf Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/abp-framework.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/abp-suite.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/abp-suite.png new file mode 100644 index 0000000000..e4ad6d6014 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/abp-suite.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/architecture-layers.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/architecture-layers.png new file mode 100644 index 0000000000..081376668b Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/architecture-layers.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/conclusion.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/conclusion.png new file mode 100644 index 0000000000..cecdd739b4 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/conclusion.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/cover.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/cover.png new file mode 100644 index 0000000000..a926bcfca6 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/cover.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/csharp-microservice-framework.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/csharp-microservice-framework.png new file mode 100644 index 0000000000..2550a9209d Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/csharp-microservice-framework.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/ddd.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/ddd.png new file mode 100644 index 0000000000..45f6261a57 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/ddd.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/essential-features.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/essential-features.png new file mode 100644 index 0000000000..e709f00327 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/essential-features.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/essentials.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/essentials.png new file mode 100644 index 0000000000..dee5928bbd Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/essentials.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/modular.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/modular.png new file mode 100644 index 0000000000..96943ef81f Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/modular.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/pre-built-modules.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/pre-built-modules.png new file mode 100644 index 0000000000..0d5f5a7e9a Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/pre-built-modules.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/the-abp-platform.png b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/the-abp-platform.png new file mode 100644 index 0000000000..bae6f08238 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/images/the-abp-platform.png differ diff --git a/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/post.md b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/post.md new file mode 100644 index 0000000000..b844fb5540 --- /dev/null +++ b/docs/en/Community-Articles/2023-04-03-What-is-ABP-Framework/post.md @@ -0,0 +1,118 @@ +# ABP Framework: An Open Source Web Application Development Framework + + + +## What is ABP Framework? + +![ABP Framework](images/abp-framework.png) + +ABP Framework is an open-source web application development framework that provides developers with a set of tools to build modern, scalable, and maintainable web applications. ABP Framework is also a C# web framework that is based on the ASP.NET web framework. It is one of the [most popular repository](https://github.com/abpframework/abp) for open source application framework. + +ABP Framework is a modular and extensible framework that uses the clean architecture principles and is built on top of the latest .NET technologies. The framework comes with a set of pre-built modules, including user management, role management, permission management, content management system (CMS) modules, which makes it easier for developers to create line of business applications. + + + +## Clean Architecture + +When you want to start a new scratch project, you first google for Dotnet Framework Architecture. There are some boilerplate dotnet startup templates but these are only an orchestration of some popular tools. ABP is not a template but it's a full stack open source application development framework. + +When you say "Clean Architecture ASP.NET Core", the first web development framework that comes to mind is undoubtedly the ABP Framework. It is built using clean architecture principles, which help developers build scalable and maintainable applications. Clean architecture separates the application into distinct layers, each with a clear responsibility. The dotnet architecture layers include the presentation layer, application layer, domain layer, and infrastructure layer. Each layer has a clear responsibility, which helps in separating concerns and keeping the code organized. This makes ABP Framework one of the best asp net frameworks. + +![Clean architecture - ABP Layers](images/architecture-layers.png) + +## C# Web Framework for Web Development + +ABP Framework is built using C#, which is a modern programming language that is widely used in the development of web applications. C# provides developers with a set of features that make it easy to write clean and maintainable code. ABP Framework is a web framework that is designed to work with C# and provides developers with a set of tools that makes it easy to build modern web applications. If you are looking for an ASP NET Core shared framework download, then go to https://abp.io/get-started and create your project. + +![ABP Framework Essentials](images/essentials.png) + +## Yet another ASP.NET Web Framework + +There are a few full stack AspNet Core frameworks around. Many of them are one developer projects which can be risky for you to start a long running project. ABP Framework is built on top of the latest ASP NET Core Framework, which provides developers with a set of features that makes it easy to build modern web applications. And most important part is, ABP is backed with a large group of developers and it has almost 10K stars on GitHub. ASP.NET provides developers with a set of tools that makes it easy to build web applications using a model-view-controller (MVC) architecture. + +![ABP.io Platform](images/the-abp-platform.png) + + + +## Implementing Domain Driven Design with C# + +ABP Framework provides developers with a set of tools that make it easy to implement domain-driven design principles. The framework comes with a set of pre-built modules, including user management, role management, permission management, and content management system (CMS) modules, which makes it easier for developers to create complex applications. + +![Implementing Domain Driven Design with C#](images/ddd.png) + + + +## Open Source Web Application + +ABP Framework is an open-source web application development framework that is free to use and distribute. The framework is licensed under the MIT license, which means that developers can use it for commercial and non-commercial purposes without any restrictions. + + + +## .NET Application Framework with Pre-Built Modules + +ABP Framework is built using the latest .NET technologies and provides developers with a set of tools that makes it easy to build modern web applications. ABP contains several important modules of a line of business applications. + +![ABP Pre-built Modules](images/pre-built-modules.png) + + + +## C# Microservice Framework + +ABP Framework is a C# microservices framework that is designed to help developers build scalable and maintainable microservices. The framework is also known as .NET .net microservices framework. It provides developers with a set of tools that makes it easy to build microservices using clean architecture principles. + +![C# Microservice Framework](images/csharp-microservice-framework.png) + + + +## CRUD Tool Dotnet + +ABP Framework has a commercial version as well. The paid version comes with a premium support, rich themes and there's a very handy tool called [ABP Suite](https://commercial.abp.io/tools/suite) for "CRUD page generation ASP.NET". While ABP is not a low-code or no-code platform, ABP Suite provides ASP NET rapid application development. There are many ASP.NET rapid development tools but these are only tools without a framework support. If you are looking for web based rapid application development tools (also open-source), ABP is the way to go! + +![ABP Suite](images/abp-suite.png) + +## Modular Development + +One of the best sides of the ABP Framework is the modular development side. It's born as a modular system. There are several open source web frameworks around but many of them lack of modularity. + +![Modular Development](images/modular.png) + +Let's see the key features of the ABP Framework: + +- Multi-tenancy support +- Cross-cutting concerns implemented +- Full-stack microservice solution +- SaaS framework +- ASP.NET modular monolith +- Has an ASP.NET user management module +- Distributed events +- Layered architecture +- Free framework for website +- Several framework templates + + + +## The Essential Features of ABP + +ABP Framework is an open source SaaS framework. This crucial feature distinguishes it from other open source web development frameworks. + +![Essential Features](images/essential-features.png) + +The following essential ASP.NET features are available in the ABP Framework: + +ASP.NET modularity, ASP.NET modular development, ASP.NET localization, ASP.NET multi-tenancy, ASP.NET SaaS, ASP.NET SaaS framework, ASP.NET distributed events, ASP.NET distributed event bus, ASP.NET cross-cutting concerns, ASP.NET blob storing, ASP.NET audit logging, ASP.NET microservice, ASP.NET microservice solution, ASP.NET microservice example, ASP.NET API gateway, ASP.NET domain driven design, ASP.NET layered architecture, ASP.NET layering, ASP.NET clean architecture, ASP.NET authentication, ASP.NET authorization, ASP.NET identity, ASP.NET identity server, ASP.NET IdentityServer, ASP.NET payment module, ASP.NET best practices, ASP.NET design patterns, ASP.NET background jobs, ASP.NET exception handling, ASP.NET background workers, ASP.NET repository, ASP.NET repository pattern, ASP.NET unit of work, ASP.NET domain services, ASP.NET swagger, ASP.NET content management system, ASP.NET user management, ASP.NET role management, ASP.NET permission management + + + +## Microservice Example: eShopOnAbp + +[eShopOnAbp](https://www.eshoponabp.com/) is a microservice example built on top ABP. It is a sample net application, similar to the Microsoft's [eShopOnContainer](https://github.com/dotnet-architecture/eShopOnContainers) project. It is a reference microservice solution built with the ABP Framework and .NET, runs on Kubernetes with Helm configuration, includes API Gateways, Angular and ASP.NET Core MVC applications with PostgreSQL and MongoDB databases. For more information, check out https://github.com/abpframework/eShopOnAbp. + + + +## Conclusion + +In conclusion, ABP Framework is an open-source web development framework that offers many features and benefits for building modern and scalable web applications. Its modular and extensible architecture, implementation of Domain-Driven Design, and compatibility with various platforms make it a popular choice for developers. Whether you're building a web application, microservices, or modular monoliths, ABP Framework has everything you need to get started. + +![conclusion](images/conclusion.png) + +Whether you're building a dot net website, a web app infrastructure, or a webpage framework, open source web application frameworks are a cost-effective and flexible option for web development. If you are looking for an open source web application builder which contains project framework template with web application development tools (open source), [ABP Framework](https://abp.io/) is the right choice. \ No newline at end of file diff --git a/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/Top 10 .NET Core Libraries Every Developer Should Know.md b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/Top 10 .NET Core Libraries Every Developer Should Know.md new file mode 100644 index 0000000000..417a5266f7 --- /dev/null +++ b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/Top 10 .NET Core Libraries Every Developer Should Know.md @@ -0,0 +1,60 @@ +# Top 10 .NET Core Libraries Every Developer Should Know + +> *Brief Summary*: +> +> This article is intended for .NET Core developers who wish to create a robust and useful.NET core application. It is a list of the most popular and widely used .NET Core libraries that have been carefully vetted. Go up the GitHub reference link for the DotNet libraries and see how many stars the .NET community has rewarded. + + + +## Best .NET libraries — Top useful libraries every .NET developers use + +.NET Core has become one of the most popular frameworks for developing modern applications. One of the reasons for its popularity is the wide range of libraries available to developers. .NET Core got new updates in its features with lesser coding, deploying high-accomplishment, and extremely scalable applications. Making the underlying architecture functions more effective and efficient without having to reinvent the wheel will free up your time to focus on more crucial tasks, including making your application stand out from the competition. + +In this article, we'll take a closer look at **The Most Popular .NET Libraries Every Developer Should Know**. As a software developer, you're likely familiar with the .NET framework and the many libraries it offers. With so many options available, it can be overwhelming to know which ones to choose for your project. This is the main reason I have compiled a list of the **Top 10 .NET Libraries That Developers Should Use** to make their development process more efficient and effective. A list of Top 10 .NET Core Libraries will let developers understand these so that they can pick appropriate libraries for their projects. + +If you're a .NET Core developer, there are **10 important .NET Core libraries** that you should be familiar with. While creating these **Essential 10 .NET Libraries Every Developer Must Know**, I used NuGet and GitHub.com popular repositories. And all the libraries listed here are also open-source. The list is filtered with only to .NET Core related libraries. Also I excluded the Microsoft .NET Core Framework libraries from this **Top 10 Unique .NET Core Libraries Developers Must Utilize**. So, without further ado, let’s get right into it: + +------ + + + +## Top 10 best libraries for .NET developers + +1. **Newtonsoft.Json:** This library is widely used for working with JSON data in .NET applications. It provides high performance and ease of use, making it a go-to solution for serialization and deserialization of JSON data. +2. **Dapper:** It is a simple and efficient ORM that offers high performance and flexibility when working with relational databases. It is easy to use and offers a fast and efficient way to interact with databases. +3. **Polly:** Polly is a library that helps handle transient errors and faults in .NET applications. It offers an easy-to-use policy-based approach to handling retries, timeouts, and circuit breakers, making it a valuable tool for building reliable applications. +4. **AutoMapper**: This .NET Core library simplifies object-to-object mapping by automatically mapping properties from one object to another. This library is especially useful in larger projects where mapping can become time-consuming and tedious. +5. **FluentValidation:** It is a library that provides a fluent API for building validation rules. It makes it easy to create complex validation logic and supports a wide range of validation scenarios, making it a valuable tool for ensuring data integrity in your applications. +6. **Serilog**: This library is a structured logging library that makes it easy to collect and analyze logs from your application. It offers flexibility and extensibility, and supports a variety of sinks for storing logs, including Elasticsearch, SQL Server, and more. +7. **Swashbuckle.AspNetCore.Swagger:** This library generates OpenAPI documentation for your ASP.NET Core Web API. It makes it easy to understand the functionality of your API and allows you to easily generate client code for your API. +8. **NLog**: It is is a free logging platform for .NET with rich log routing and management capabilities. It makes it easy to produce and manage high-quality logs for your application regardless of its size or complexity. +9. **Moq4**: It is is a popular mocking framework for .NET applications. It makes it easy to create mock objects for unit testing, reducing the need for expensive and time-consuming integration testing. +10. **StackExchange.Redis**: This is a library for working with Redis databases in .NET applications. It provides a simple and efficient way to interact with Redis, and offers high performance and scalability. + +------ + +![10 important .NET Core Libraries](essential-10-net-libraries-every-developer-must-know.png) + + + +## Top 10 .NET Core Libraries List That Every Developer Must Know + +Here you can see them in table with the GitHub stars, GitHub release counts, recent release frequency, NuGet download counts and per day NuGet download counts: + +| GitHub URL | NuGet URL | Stars | Releases | Last release | Downloads | Download Per Day | +| ------------------------------------------------------------ | ------------------------------------------------------------ | ----- | -------- | ------------ | --------- | ---------------- | +| [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) | [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json) | 10K | 65 | 1 month ago | 3B | 680K | +| [Dapper](https://github.com/DapperLib/Dapper) | [Dapper](https://www.nuget.org/packages/Dapper) | 16K | 70 | 2 years ago | 216M | 50K | +| [Polly](https://github.com/App-vNext/Polly) | [Polly](https://www.nuget.org/packages/polly) | 12K | 26 | 1 year ago | 335M | 92K | +| [AutoMapper](https://github.com/AutoMapper/AutoMapper) | [AutoMapper](https://www.nuget.org/packages/AutoMapper) | 9K | 41 | 6 months ago | 400M | 90K | +| [FluentValidation](https://github.com/FluentValidation/FluentValidation) | [FluentValidation](https://www.nuget.org/packages/FluentValidation) | 8K | 68 | 3 days ago | 250M | 56K | +| [Serilog](https://github.com/serilog/serilog) | [Serilog](https://www.nuget.org/packages/Serilog) | 6K | 15 | 1 month ago | 722M | 197K | +| [Swashbuckle.AspNetCore.Swagger](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) | [Swashbuckle.AspNetCore.Swagger](https://www.nuget.org/packages/Swashbuckle.AspNetCore.Swagger) | 5K | 28 | 4 months ago | 386M | 168K | +| [NLog](https://github.com/NLog/NLog) | [NLog](https://www.nuget.org/packages/Nlog) | 6K | 125 | 1 week ago | 217M | 48K | +| [Moq](https://github.com/moq/moq4) | [Moq](https://www.nuget.org/packages/Moq) | 5K | 33 | 4 months ago | 418M | 93K | +| [StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis) | [StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis) | 5K | 34 | 11 days ago | 244M | 74K | + + + +In conclusion, these 10 .NET Core libraries are essential tools for any .NET Core developer. They offer a wide range of functionality, from handling errors to mocking for unit testing and simplifying object mapping. Whether you're working on a large-scale enterprise application or a small project, these libraries can help you build more reliable, efficient, and effective applications. + diff --git a/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/cover1.png b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/cover1.png new file mode 100644 index 0000000000..2edb48ce42 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/cover1.png differ diff --git a/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/cover2.png b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/cover2.png new file mode 100644 index 0000000000..2e2a201748 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/cover2.png differ diff --git a/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/essential-10-net-libraries-every-developer-must-know.png b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/essential-10-net-libraries-every-developer-must-know.png new file mode 100644 index 0000000000..e986bb5719 Binary files /dev/null and b/docs/en/Community-Articles/2023-04-11-Top-10-NET-Core-Libraries-Every-Developer-Should-Know/essential-10-net-libraries-every-developer-must-know.png differ diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index 47e60700bc..206c2c58a4 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -440,16 +440,16 @@ Use `ICachedServiceProvider` (instead of `ITransientCachedServiceProvider`) unle ## Advanced Features -### IServiceCollection.OnRegistred Event +### IServiceCollection.OnRegistered Event -You may want to perform an action for every service registered to the dependency injection. In the `PreConfigureServices` method of your module, register a callback using the `OnRegistred` method as shown below: +You may want to perform an action for every service registered to the dependency injection. In the `PreConfigureServices` method of your module, register a callback using the `OnRegistered` method as shown below: ````csharp public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { var type = ctx.ImplementationType; //... @@ -465,7 +465,7 @@ public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true)) { @@ -478,7 +478,7 @@ public class AppModule : AbpModule This example simply checks if the service class has `MyLogAttribute` attribute and adds `MyLogInterceptor` to the interceptor list if so. -> Notice that `OnRegistred` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors. +> Notice that `OnRegistered` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors. ## 3rd-Party Providers diff --git a/docs/en/Migration-Guides/Abp-7_1.md b/docs/en/Migration-Guides/Abp-7_1.md index 7e579af217..711f520800 100644 --- a/docs/en/Migration-Guides/Abp-7_1.md +++ b/docs/en/Migration-Guides/Abp-7_1.md @@ -2,6 +2,8 @@ This document is a guide for upgrading ABP v7.0 solutions to ABP v7.1. There are a few changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. +> **Note**: Entity Framework developers may need to add a new code-first database migration to their projects since we made some improvements to the existing entities of some application modules. + ## Navigation Menu - `CustomData` type changed to `Dictionary` `ApplicationMenu` and `ApplicationMenuItem` classes' `CustomData` property type has been changed to `Dictionary`. So, if you use the optional `CustomData` property of these classes, change it accordingly. See [#15608](https://github.com/abpframework/abp/pull/15608) for more information. @@ -16,4 +18,4 @@ var menu = new ApplicationMenu("Home", L["Home"], "/", customData: new MyCustomD ```csharp var menu = new ApplicationMenu("Home", L["Home"], "/").WithCustomData("CustomDataKey", new MyCustomData()); -``` \ No newline at end of file +``` diff --git a/docs/en/Migration-Guides/Abp-7_2.md b/docs/en/Migration-Guides/Abp-7_2.md new file mode 100644 index 0000000000..5c99e8e604 --- /dev/null +++ b/docs/en/Migration-Guides/Abp-7_2.md @@ -0,0 +1,13 @@ +# ABP Version 7.2 Migration Guide + +This document is a guide for upgrading ABP v7.1 solutions to ABP v7.2. There are a few changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. + +## `LastPasswordChangeTime` and `ShouldChangePasswordOnNextLogin` Properties Added to the `IdentityUser` Class + +In this version, two new properties, which are `LastPasswordChangeTime` and `ShouldChangePasswordOnNextLogin` have been added to the `IdentityUser` class and to the corresponding entity. Therefore, you may need to create a new migration and apply it to your database. + +## Renamed `OnRegistered` Method + +There was a typo in an extension method, named as `OnRegistred`. In this version, we have fixed the typo and renamed the method as `OnRegistered`. Also, we have updated the related places in our modules that use this method. + +However, if you have used this method in your projects, you need to rename it as `OnRegistered` in your code. \ No newline at end of file diff --git a/docs/en/Migration-Guides/Index.md b/docs/en/Migration-Guides/Index.md index 8a693970b2..7d85d3f46f 100644 --- a/docs/en/Migration-Guides/Index.md +++ b/docs/en/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). +- [7.1 to 7.2](Abp-7_2.md) - [7.0 to 7.1](Abp-7_1.md) - [6.0 to 7.0](Abp-7_0.md) - [5.3 to 6.0](Abp-6_0.md) diff --git a/docs/en/Modules/Cms-Kit/Comments.md b/docs/en/Modules/Cms-Kit/Comments.md index 26aa7c0398..cc8d01249b 100644 --- a/docs/en/Modules/Cms-Kit/Comments.md +++ b/docs/en/Modules/Cms-Kit/Comments.md @@ -19,6 +19,16 @@ Configure(options => { options.EntityTypes.Add(new CommentEntityTypeDefinition("Product")); options.IsRecaptchaEnabled = true; //false by default + options.AllowedExternalUrls = new Dictionary> + { + { + "Product", + new List + { + "https://abp.io/" + } + } + }; }); ``` @@ -28,6 +38,7 @@ Configure(options => - `EntityTypes`: List of defined entity types(`CmsKitCommentOptions`) in the comment system. - `IsRecaptchaEnabled`: This flag enables or disables the reCaptcha for the comment system. You can set it as **true** if you want to use reCaptcha in your comment system. +- `AllowedExternalUrls`: Indicates the allowed external URLs by entity types, which can be included in a comment. If it's specified for a certain entity type, then only the specified external URLs are allowed in the comments. `CommentEntityTypeDefinition` properties: @@ -46,7 +57,7 @@ The comment system provides a commenting [widget](../../UI/AspNetCore/Widgets.md }) ``` -`entityType` was explained in the previous section. `entityId` should be the unique id of the product, in this example. If you have a Product entity, you can use its Id here. `referralLinks` is an optional parameter. You can use this parameter to add values (such as "nofollow", "noreferrer", or any other values) to the [rel attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel) of links. +`entityType` was explained in the previous section. `entityId` should be the unique id of the product, in this example. If you have a Product entity, you can use its Id here. `referralLinks` is an optional parameter. You can use this parameter to add values (such as "nofollow", "noreferrer", or any other values) to the [rel attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel) of links. ## User Interface diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 7dac3762aa..19cf8fa443 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -32,25 +32,6 @@ Configure(options => > Multi-Tenancy is disabled in the ABP Framework by default. However, it is **enabled by default** when you create a new solution using the [startup template](Startup-Templates/Application.md). `MultiTenancyConsts` class in the solution has a constant to control it in a single place. -### AbpMultiTenancyOptions: Handle inactive and non-existent tenants. - -The `MultiTenancyMiddlewareErrorPageBuilder` of `AbpMultiTenancyOptions` is used to handle inactive and non-existent tenants. - -It will respond to an error page by default, you can change it if you want, eg: only output the error log and continue ASP NET Core's request pipeline. - -```csharp -Configure(options => -{ - options.MultiTenancyMiddlewareErrorPageBuilder = async (context, exception) => - { - // Handle the exception. - - // Return true to stop the pipeline, false to continue. - return true; - }; -}); -``` - ### Database Architecture ABP Framework supports all the following approaches to store the tenant data in the database; @@ -273,6 +254,23 @@ class SomeComponent { > However, we don't suggest to change this value since some clients may assume the the `__tenant` as the parameter name and they might need to manually configure then. +The `MultiTenancyMiddlewareErrorPageBuilder` is used to handle inactive and non-existent tenants. + +It will respond to an error page by default, you can change it if you want, eg: only output the error log and continue ASP NET Core's request pipeline. + +```csharp +Configure(options => +{ + options.MultiTenancyMiddlewareErrorPageBuilder = async (context, exception) => + { + // Handle the exception. + + // Return true to stop the pipeline, false to continue. + return true; + }; +}); +``` + ##### Domain/Subdomain Tenant Resolver In a real application, most of times you will want to determine current tenant either by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). If so, you can configure the `AbpTenantResolveOptions` to add the domain tenant resolver. diff --git a/docs/en/Tutorials/Part-10.md b/docs/en/Tutorials/Part-10.md index 6178ebbb8e..e71beccd6f 100644 --- a/docs/en/Tutorials/Part-10.md +++ b/docs/en/Tutorials/Part-10.md @@ -361,7 +361,7 @@ public class BookAppService : GetListPolicyName = BookStorePermissions.Books.Default; CreatePolicyName = BookStorePermissions.Books.Create; UpdatePolicyName = BookStorePermissions.Books.Edit; - DeletePolicyName = BookStorePermissions.Books.Create; + DeletePolicyName = BookStorePermissions.Books.Delete; } public override async Task GetAsync(Guid id) diff --git a/docs/en/UI/Angular/Card-Component.md b/docs/en/UI/Angular/Card-Component.md new file mode 100644 index 0000000000..861171c39e --- /dev/null +++ b/docs/en/UI/Angular/Card-Component.md @@ -0,0 +1,206 @@ +# Card Component + +The ABP Card Component is a wrapper component for the Bootstrap card class. +It supports all the features that Bootstrap card component provides. + +ABP Card Component has three main components, `CardHeader`, `CardBody` and `CardFooter`. These components have their own class and style inputs + +|Component |Selector |Input Properties | +|--------- |-----------------|------------------------------------| +|CardHeader|`abp-card-header`| `cardHeaderClass`,`cardHeaderStyle`| +|CardBody |`abp-card-body` | `cardBodyClass`,`cardBodyStyle` | +|CardFooter|`abp-card-footer`| `cardFooterClass`,`cardFooterStyle`| + +In addition to these components, the Card component provides directives like `CardHeader`,`CardTitle`,`CardSubtitle`,`CardImgTop`. + +|Directive |Selector | +|-------------|-------------------------------------------------------------| +|CardHeader |`abp-card-header`,`[abp-card-header]`,`[abpCardHeader]` | +|CardTitle |`abp-card-title`,`[abp-card-title]`,`[abpCardTitle]` | +|CardSubtitle |`abp-card-subtitle`,`[abp-card-subtitle]`,`[abpCardSubtitle]`| +|CardImgTop |`abp-card-img-top`,`[abp-card-img-top]`,`[abpCardImgTop]` | + + +# Usage + +ABP Card Component is a part of the `ThemeSharedModule` module. If you've imported that module into your module, you don't need to import it again. If not, first import it as shown below: + +```ts +// my-feature.module.ts + +import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { CardDemoComponent } from './chart-demo.component'; + +@NgModule({ + imports: [ + ThemeSharedModule , + // ... + ], + declarations: [CardDemoComponent], + // ... +}) +export class MyFeatureModule {} + +``` + +Then, the `abp-card` component can be used. See the examples below: + +## CardBody + +```ts +// card-demo.component.ts + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card-demo', + template: ` + + This is some text within a card body + + `, +}) +export class CardDemoComponent { } +``` +See the card body result below: + +![abp-card-body](./images/abp-card-body.png) + +## Titles, Text and Links + +```ts + +//card-demo.component.ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card-demo', + template: ` + + +
Card Title
+
Card subtitle
+

Some quick example text to build on the card title and make up the bulk of the card's content.

+ Card link + Another link +
+
+ `, +}) +export class CardDemoComponent { } +``` +See the card title, text and link result below: + +![abp-card-title-text-link](./images/abp-card-title-text-link.png) + +## Images + +```ts + +//card-demo.component.ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card-demo', + template: ` + + ... + +

Some quick example text to build on the card title and make up the bulk of the card's content.

+
+
+ `, +}) +export class CardDemoComponent { } +``` +See the card image result below: + +![abp-card-image-top](./images/abp-card-image.png) + +## List Groups + +```ts + +//card-demo.component.ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card-demo', + template: ` + +
    +
  • An item
  • +
  • A second item
  • +
  • A third item
  • +
+
+ `, +}) +export class CardDemoComponent { } +``` +See the group list result below: + +![abp-card-list-group](./images/abp-card-list-group.png) + +## Kitchen Sink + +```ts + +//card-demo.component.ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card-demo', + template: ` + + ... + +
Card title
+

Some quick example text to build on the card title and make up the bulk of the card's content.

+
+
    +
  • An item
  • +
  • A second item
  • +
  • A third item
  • +
+ + Card link + Another link + +
+ `, +}) +export class CardDemoComponent { } +``` +See kitchen sink result below: + +![abp-card-kitchen-sink](./images/abp-card-kitchen-sink.png) + +## Header and Footer + +```ts + +//card-demo.component.ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-card-demo', + template: ` + + Featured + +
Special title treatment
+

With supporting text below as a natural lead-in to additional content.

+ Go somewhere +
+ + 2 days ago + +
+ `, +}) +export class CardDemoComponent { } +``` +See the header and footer result below: + +![abp-card-header-footer](./images/abp-card-header-footer.png) diff --git a/docs/en/UI/Angular/Modifying-the-Menu.md b/docs/en/UI/Angular/Modifying-the-Menu.md index b0a3b760fa..c59ce0d650 100644 --- a/docs/en/UI/Angular/Modifying-the-Menu.md +++ b/docs/en/UI/Angular/Modifying-the-Menu.md @@ -88,14 +88,65 @@ function configureRoutes(routes: RoutesService) { } ``` +We can also define a group for navigation elements. It's an optional property + - **Note:** It'll also include groups that were defined at the modules + +```js +// route.provider.ts +import { RoutesService } from '@abp/ng.core'; + +function configureRoutes(routes: RoutesService) { + return () => { + routes.add([ + { + //etc.. + group: 'ModuleName::GroupName' + }, + { + path: '/your-path/child', + name: 'Your child navigation', + parentName: 'Your navigation', + requiredPolicy: 'permission key here', + order: 1, + }, + ]); + }; +} +``` + +To get the route items as grouped we can use the `groupedVisible` (or Observable one `groupedVisible$`) getter methods + - It returns `RouteGroup[]` if there is any group in the route tree, otherwise it returns `undefined` + +```js +import { ABP, RoutesService, RouteGroup } from "@abp/ng.core"; +import { Component } from "@angular/core"; + +@Component(/* component metadata */) +export class AppComponent { + visible: RouteGroup[] | undefined = this.routes.groupedVisible; + //Or + visible$:Observable[] | undefined> = this.routes.groupedVisible$; + + constructor(private routes: RoutesService) {} +} +``` + ...and then in app.module.ts... + - The `groupedVisible` method will return the `Others` group for ungrouped items, the default key is `AbpUi::OthersGroup`, we can change this `key` via the `OTHERS_GROUP` injection token ```js import { NgModule } from '@angular/core'; +import { OTHERS_GROUP } from '@abp/ng.core'; import { APP_ROUTE_PROVIDER } from './route.provider'; @NgModule({ - providers: [APP_ROUTE_PROVIDER], + providers: [ + APP_ROUTE_PROVIDER, + { + provide: OTHERS_GROUP, + useValue: 'ModuleName::MyOthersGroupKey', + }, + ], // imports, declarations, and bootstrap }) export class AppModule {} @@ -109,8 +160,9 @@ Here is what every property works as: - `requiredPolicy` is the permission key to access the page. See the [Permission Management document](./Permission-Management.md) - `order` is the order of the navigation element. "Administration" has an order of `100`, so keep that in mind when ordering top level menu items. - `iconClass` is the class of the `i` tag, which is placed to the left of the navigation label. -- `layout` defines in which layout the route will be loaded. (default: `eLayoutType.empty`) +- `layout` defines in which layout the route is loaded. (default: `eLayoutType.empty`) - `invisible` makes the item invisible in the menu. (default: `false`) +- `group` is an optional property that is used to group together related routes in an application. (type: `string`, default: `AbpUi::OthersGroup`) ### Via `routes` Property in `AppRoutingModule` diff --git a/docs/en/UI/Angular/Quick-Start.md b/docs/en/UI/Angular/Quick-Start.md index 768b3b7b67..dd26dd3efe 100644 --- a/docs/en/UI/Angular/Quick-Start.md +++ b/docs/en/UI/Angular/Quick-Start.md @@ -179,7 +179,7 @@ This command will download and start a simple static server, a browser window at Of course, you need your application to run on an optimized web server and become available to everyone. This is quite straight-forward: -1. Create a new static web server instance. You can use a service like [Azure App Service](https://azure.microsoft.com/tr-tr/services/app-service/web/), [Firebase](https://firebase.google.com/docs/hosting), [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), or even [GitHub Pages](https://angular.io/guide/deployment#deploy-to-github-pages). Another option is maintaining own web server with [NGINX](https://www.nginx.com/), [IIS](https://www.iis.net/), [Apache HTTP Server](https://httpd.apache.org/), or equivalent. +1. Create a new static web server instance. You can use a service like [Azure App Service](https://azure.microsoft.com/en-us/services/app-service/web/), [Firebase](https://firebase.google.com/docs/hosting), [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), or even [GitHub Pages](https://angular.io/guide/deployment#deploy-to-github-pages). Another option is maintaining own web server with [NGINX](https://www.nginx.com/), [IIS](https://www.iis.net/), [Apache HTTP Server](https://httpd.apache.org/), or equivalent. 2. Copy the files from `dist/MyProjectName` [1](#f-dist-folder-name) to a publicly served destination on the server via CLI of the service provider, SSH, or FTP (whichever is available). This step would be defined as a job if you have a CI/CD flow. 3. [Configure the server](https://angular.io/guide/deployment#server-configuration) to redirect all requests to the _index.html_ file. Some services do that automatically. Others require you [to add a file to the bundle via assets](https://angular.io/guide/workspace-config#assets-configuration) which describes the server how to do the redirections. Occasionally, you may need to do manual configuration. diff --git a/docs/en/UI/Angular/images/abp-card-body.png b/docs/en/UI/Angular/images/abp-card-body.png new file mode 100644 index 0000000000..d5d7d07d29 Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-body.png differ diff --git a/docs/en/UI/Angular/images/abp-card-component.png b/docs/en/UI/Angular/images/abp-card-component.png new file mode 100644 index 0000000000..726c617772 Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-component.png differ diff --git a/docs/en/UI/Angular/images/abp-card-header-footer.png b/docs/en/UI/Angular/images/abp-card-header-footer.png new file mode 100644 index 0000000000..72f0d7be45 Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-header-footer.png differ diff --git a/docs/en/UI/Angular/images/abp-card-header.png b/docs/en/UI/Angular/images/abp-card-header.png new file mode 100644 index 0000000000..a13ed5b3fe Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-header.png differ diff --git a/docs/en/UI/Angular/images/abp-card-image.png b/docs/en/UI/Angular/images/abp-card-image.png new file mode 100644 index 0000000000..c4136d524b Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-image.png differ diff --git a/docs/en/UI/Angular/images/abp-card-kitchen-sink.png b/docs/en/UI/Angular/images/abp-card-kitchen-sink.png new file mode 100644 index 0000000000..908e062ff0 Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-kitchen-sink.png differ diff --git a/docs/en/UI/Angular/images/abp-card-list-group.png b/docs/en/UI/Angular/images/abp-card-list-group.png new file mode 100644 index 0000000000..aa7b746647 Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-list-group.png differ diff --git a/docs/en/UI/Angular/images/abp-card-title-text-link.png b/docs/en/UI/Angular/images/abp-card-title-text-link.png new file mode 100644 index 0000000000..af7d009929 Binary files /dev/null and b/docs/en/UI/Angular/images/abp-card-title-text-link.png differ diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index f0776f47ec..60621f9906 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -104,6 +104,7 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt * `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. * `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. * `cssClass` (`string`): Additional string classes for the menu item. +* `groupName` (`string`): Can be used to group menu items. ### Authorization @@ -179,6 +180,58 @@ userMenu.Icon = "fa fa-users"; > `context.Menu` gives you ability to access to all the menu items those have been added by the previous menu contributors. +### Menu Groups + +You can define groups and associate menu items with a group. + +Example: + +```csharp +using System.Threading.Tasks; +using MyProject.Localization; +using Volo.Abp.UI.Navigation; + +namespace MyProject.Web.Menus +{ + public class MyProjectMenuContributor : IMenuContributor + { + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + context.Menu.AddGroup( + new ApplicationMenuGroup( + name: "Main", + displayName: l["Main"] + ) + ) + context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"], groupName: "Main") + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + ) + ); + } + } +} +``` + +> The UI theme will decide whether to render the groups or not, and if it decides to render, the way it's rendered is up to the theme. Only the LeptonX theme implements the menu group. + ## Standard Menus A menu is a **named** component. An application may contain more than one menus with different, unique names. There are two pre-defined standard menus: @@ -233,4 +286,3 @@ namespace MyProject.Web.Pages } } ``` - diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md b/docs/en/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md index 0c374a9cf8..9d996a45dd 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md @@ -108,6 +108,10 @@ See the [dynamic forms demo page](https://bootstrap-taghelpers.abp.io/Components Sets the c# model for dynamic form. Properties of this modal are turned into inputs in the form. +### column-size + +Here, use 'col-sm' to set the size . When setting this property 'col-12' will be added at the same time. + ### submit-button Can be `True` or `False`. diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 8f664a80a5..54e9712d30 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -10,7 +10,7 @@ See the [form elements demo page](https://bootstrap-taghelpers.abp.io/Components ## abp-input -`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`. +`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`. Usage: @@ -58,49 +58,49 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes - `[TextArea()]`: Converts the input into a text area. -* `[Placeholder()]`: Sets placeholder for input. You can use a localization key directly. -* `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly. -* `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are +* `[Placeholder()]`: Sets the description are of the input. You can use a localization key directly. +* `[InputInfoText()]`: Sets text for the input. You can directly use a localization key. +* `[FormControlSize()]`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `[DisabledInput]` : Input is disabled. -* `[ReadOnlyInput]`: Input is read-only. +* `[DisabledInput]` : Sets the input as disabled. +* `[ReadOnlyInput]`: Sets the input as read-only. #### Tag Attributes -* `info`: Sets a small info text for input. You can use a localization key directly. -* `auto-focus`: If true, browser auto focuses on the element. -* `size`: Sets size of form-control wrapper element. Available values are +* `info`: Sets text for the input. You can directly use a localization key. +* `auto-focus`: It lets the browser set focus to the element when its value is true. +* `size`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `disabled`: Input is disabled. -* `readonly`: Input is read-only. -* `label`: Sets the label for input. -* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `label`: Sets the label of input. +* `required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. -`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) are also valid for `abp-input` tag helper. +`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) are also valid for `abp-input` tag helper. ### Label & Localization -You can set label of your input in different ways: +You can set the label of the input in several ways: -- You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value"`. -- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core. +- You can use the `Label` attribute to set the label directly. This property does not automatically localize the text. To localize the label, use `label="@L["{LocalizationKey}"].Value"`. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute of ASP.NET Core. - You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys, if `label` or `[DisplayName]` attributes are not set. ## abp-select -`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`. +`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [ASP.NET Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of ASP.NET Core is also valid for `abp-select`. `abp-select` tag needs a list of `Microsoft.AspNetCore.Mvc.Rendering.SelectListItem ` to work. It can be provided by `asp-items` attriube on the tag or `[SelectItems()]` attribute on c# property. (if you are using [abp-dynamic-form](Dynamic-forms.md), c# attribute is the only way.) @@ -170,14 +170,14 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes * `[SelectItems()]`: Sets the select data. Parameter should be the name of the data list. (see example above) -- `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly. -- `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are +- `[InputInfoText()]`: Sets text for the input. You can directly use a localization key. +- `[FormControlSize()]`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` @@ -186,21 +186,21 @@ You can set some of the attributes on your c# property, or directly on html tag. #### Tag Attributes - `asp-items`: Sets the select data. This Should be a list of SelectListItem. -- `info`: Sets a small info text for input. You can use a localization key directly. -- `size`: Sets size of form-control wrapper element. Available values are +- `info`: Sets text for the input. You can directly use a localization key. +- `size`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -- `label`: Sets the label for input. -- `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. +- `label`: Sets the label of input. +- `required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. ### Label & Localization -You can set label of your input in different ways: +You can set the label of the input in several ways: - You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value".` -- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute of ASP.NET Core. - You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys. Localizations of combobox values are set by `abp-select` for **Enum** property. It searches for "{EnumTypeName}.{EnumPropertyName}" or "{EnumPropertyName}" localization keys. For instance, in the example above, it will use "CarType.StationWagon" or "StationWagon" keys for localization when it localizes combobox values. @@ -251,7 +251,7 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes @@ -261,3 +261,172 @@ You can set some of the attributes on your c# property, or directly on html tag. - `asp-items`: Sets the select data. This Should be a list of SelectListItem. - `Inline`: If true, radio buttons will be in single line, next to each other. If false, they will be under each other. + +## abp-date-picker & abp-date-range-picker + +`abp-date-picker` and `abp-date-range-picker` tags creates a Bootstrap form date picker for a given c# property. `abp-date-picker` is for single date selection, `abp-date-range-picker` is for date range selection. It uses [datepicker](https://www.daterangepicker.com/) jQuery plugin. + +Usage: + +````xml + + + +```` + +Model: + +````csharp + public class FormElementsModel : PageModel + { + public SampleModel MyModel { get; set; } + + public DynamicForm DynamicFormExample { get; set; } + + public void OnGet() + { + MyModel = new SampleModel(); + + DynamicFormExample = new DynamicForm(); + } + + public class SampleModel + { + public DateTime MyDate { get; set; } + + public DateTime MyDateRangeStart { get; set; } + + public DateTime MyDateRangeEnd { get; set; } + } + + public class DynamicForm + { + [DateRangePicker("MyPicker",true)] + public DateTime StartDate { get; set; } + + [DateRangePicker("MyPicker",false)] + [DatePickerOptions(nameof(DatePickerOptions))] + public DateTime EndDate { get; set; } + + public DateTime DateTime { get; set; } + + public DynamicForm() + { + StartDate = DateTime.Now; + EndDate = DateTime.Now; + DateTime = DateTime.Now; + } + } + + public AbpDatePickerOptions DatePickerOptions { get; set; } + } +```` + +### Attributes + +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. + +#### Property Attributes + +* `[Placeholder()]`: Sets the description are of the input. You can use a localization key directly. +* `[InputInfoText()]`: Sets text for the input. You can directly use a localization key. +* `[FormControlSize()]`: Sets the size of the form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `[DisabledInput]` : Sets the input as disabled. +* `[ReadOnlyInput]`: Sets the input as read-only. +- `[DatePickerOptions()]`: Sets the predefined options of the date picker. Parameter should be the name of the options property (see example above). See the available [datepicker options](https://www.daterangepicker.com/#options). You can use a localization key directly. + +##### abp-date-picker +`[DatePicker]` : Sets the input as datepicker. Especially for string properties. + +##### abp-date-range-picker +`[DateRangePicker()]` : Sets the picker id for the date range picker. You can set the property as a start date by setting IsStart=true or leave it as default/false to set it as an end date. + +#### Tag Attributes + +* `info`: Sets text for the input. You can directly use a localization key. +* `auto-focus`: It lets the browser set focus to the element when its value is true. +* `size`: Sets the size of the form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `label`: Sets the label of input. +* `required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. +* `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. +* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True`. +* `single-open-and-clear-button`: Shows the open and clear buttons in a single button when it's `True`. The default value is `True`. +* `is-utc`: Converts the date to UTC when its `True`. The default value is `False`. +* `is-iso`: Converts the date to ISO format when its `True`. The default value is `False`. +* `date-format`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. +* `date-separator`: Sets a character to separate start and end dates. The default value is `-` +* Other non-mapped attributes will be automatically added to the input element as is. See the available [datepicker options](https://www.daterangepicker.com/#options). Eg: `data-start-date="2020-01-01"` + +##### abp-date-picker + +* `asp-date`: Sets the date value. This should be a `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` or `string` value. + +##### abp-date-range-picker + +* `asp-for-start`: Sets the start date value. This should be a `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` or `string` value. +* `asp-for-end`: Sets the end date value. This should be a `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` or `string` value. + +### Label & Localization + +You can set the label of the input in several ways: + +- You can use the `Label` attribute to set the label directly. This property does not automatically localize the text. To localize the label, use `label="@L["{LocalizationKey}"].Value"`. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute ASP.NET Core. +- You can just let **abp** find the localization key for the property. If the `label` or `[DisplayName]` attributes are not set, it tries to find the localization by convention. For example `DisplayName:{YourPropertyName}` or `{YourPropertyName}`. If your property name is FullName, it will search for `DisplayName:FullName` or `{FullName}`. + +### JavaScript Usage + +````javascript +var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker( + { + label: "New Picker", + } +); +newPicker.insertAfter($('body')); +```` + +````javascript +var newPicker = abp.libs.bootstrapDateRangePicker.createSinglePicker( + { + label: "New Picker", + } +); +newPicker.insertAfter($('body')); +```` + +#### Options + +* `label`: Sets the label of the input. +* `placeholder`: Sets the placeholder of the input. +* `value`: Sets the value of the input. +* `name`: Sets the name of the input. +* `id`: Sets the id of the input. +* `required`: Sets the input as required. +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `size`: Sets the size of the form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `openButton`: A button to open the datepicker will be added when its `True`. The default value is `True`. +* `clearButton`: A button to clear the datepicker will be added when its `True`. The default value is `True`. +* `singleOpenAndClearButton`: Shows the open and clear buttons in a single button when it's `True`. The default value is `True`. +* `isUtc`: Converts the date to UTC when its `True`. The default value is `False`. +* `isIso`: Converts the date to ISO format when its `True`. The default value is `False`. +* `dateFormat`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. +* `dateSeparator`: Sets a character to separate start and end dates. The default value is `-`. +* `startDateName`: Sets the name of the hidden start date input. +* `endDateName`: Sets the name of the hidden end date input. +* `dateName`: Sets the name of the hidden date input. +* Other [datepicker options](https://www.daterangepicker.com/#options). Eg: `startDate: "2020-01-01"`. \ No newline at end of file diff --git a/docs/en/UI/Blazor/Basic-Theme.md b/docs/en/UI/Blazor/Basic-Theme.md index 4060f097ba..e4124d9a2c 100644 --- a/docs/en/UI/Blazor/Basic-Theme.md +++ b/docs/en/UI/Blazor/Basic-Theme.md @@ -85,6 +85,27 @@ You can simply override the styles in the Global Styles file of your application See the [Customization / Overriding Components](Customization-Overriding-Components.md) to learn how you can replace components, customize and extend the user interface. +### Overriding the Menu Item +Basic theme supports overriding a single menu item with a custom component. You can create a custom component and call `UseComponent` extension method of Basic Theme in the **MenuContributor**. + +```csharp +using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Navigation; + +//... + +context.Menu.Items.Add( + new ApplicationMenuItem("Custom.1", "My Custom Menu", "#") + .UseComponent(typeof(MyMenuItemComponent))); +``` + +```html + +``` + ### Copy & Customize You can run the following [ABP CLI](../../CLI.md) command in **Blazor{{if UI == "Blazor"}}WebAssembly{{else}} Server{{end}}** project directory to copy the source code to your solution: diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index 7f09a65dbb..0abac5fc68 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -104,6 +104,7 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt * `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. * `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. * `cssClass` (`string`): Additional string classes for the menu item. +* `groupName` (`string`): Can be used to group menu items. ### Authorization @@ -160,6 +161,58 @@ userMenu.Icon = "fa fa-users"; > `context.Menu` gives you ability to access to all the menu items those have been added by the previous menu contributors. +### Menu Groups + +You can define groups and associate menu items with a group. + +Example: + +```csharp +using System.Threading.Tasks; +using MyProject.Localization; +using Volo.Abp.UI.Navigation; + +namespace MyProject.Web.Menus +{ + public class MyProjectMenuContributor : IMenuContributor + { + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + context.Menu.AddGroup( + new ApplicationMenuGroup( + name: "Main", + displayName: l["Main"] + ) + ) + context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"], groupName: "Main") + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + ) + ); + } + } +} +``` + +> The UI theme will decide whether to render the groups or not, and if it decides to render, the way it's rendered is up to the theme. Only the LeptonX theme implements the menu group. + ## Standard Menus A menu is a **named** component. An application may contain more than one menus with different, unique names. There are two pre-defined standard menus: diff --git a/docs/en/UI/Blazor/Overall.md b/docs/en/UI/Blazor/Overall.md index 835bf4eab6..f38c0c257b 100644 --- a/docs/en/UI/Blazor/Overall.md +++ b/docs/en/UI/Blazor/Overall.md @@ -88,7 +88,7 @@ There are a set of standard libraries that comes pre-installed and supported by * [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. * [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree. * [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. -* [Flag Icon](https://github.com/lipis/flag-icon-css) as a library to show flags of countries. +* [Flag Icon](https://github.com/lipis/flag-icons) as a library to show flags of countries. These libraries are selected as the base libraries and available to the applications and modules. diff --git a/docs/en/UI/Blazor/Theming.md b/docs/en/UI/Blazor/Theming.md index d8cec07cb3..2496df9b20 100644 --- a/docs/en/UI/Blazor/Theming.md +++ b/docs/en/UI/Blazor/Theming.md @@ -48,7 +48,7 @@ All the themes must depend on the [Volo.Abp.AspNetCore.Components.Server.Theming * [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. * [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree. * [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. -* [Flag Icon](https://github.com/lipis/flag-icon-css) as a library to show flags of countries. +* [Flag Icon](https://github.com/lipis/flag-icons) as a library to show flags of countries. These libraries are selected as the base libraries and available to the applications and modules. diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 2ce69e69a9..fa688814b3 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -1197,6 +1197,10 @@ { "text": "Chart", "path": "UI/Angular/Chart-Component.md" + }, + { + "text": "Card", + "path": "UI/Angular/Card-Component.md" } ] } diff --git a/docs/zh-Hans/Background-Jobs-Hangfire.md b/docs/zh-Hans/Background-Jobs-Hangfire.md index fb899758cc..d3fb341bab 100644 --- a/docs/zh-Hans/Background-Jobs-Hangfire.md +++ b/docs/zh-Hans/Background-Jobs-Hangfire.md @@ -66,6 +66,8 @@ public class YourModule : AbpModule } ```` +> 你必须为Hangfire配置一个存储 + ### 指定队列 你可以使用 [`QueueAttribute`](https://docs.hangfire.io/en/latest/background-processing/configuring-queues.html) 来指定队列. diff --git a/docs/zh-Hans/Background-Workers-Hangfire.md b/docs/zh-Hans/Background-Workers-Hangfire.md index fde7b35973..bdd546eba8 100644 --- a/docs/zh-Hans/Background-Workers-Hangfire.md +++ b/docs/zh-Hans/Background-Workers-Hangfire.md @@ -41,6 +41,36 @@ public class YourModule : AbpModule > Hangfire后台工作者集成提供了 `HangfirePeriodicBackgroundWorkerAdapter` 来适配 `PeriodicBackgroundWorkerBase` 和 `AsyncPeriodicBackgroundWorkerBase` 派生类. 所以你依然可以按照[后台工作者文档](Background-Workers.md)来定义后台作业. +## 配置 + +你可以安装任何Hangfire存储. 最常用的是SQL Server(参阅[Hangfire.SqlServer](https://www.nuget.org/packages/Hangfire.SqlServer)NuGet包). + +当你安装NuGet包后,你需要为你的项目配置Hangfire. + +1.首先, 我们需要更改 `Module` 类 (例如: `HttpApiHostModule`) 的 `ConfigureServices` 方法去配置Hangfire存储和连接字符串: + +````csharp + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + var hostingEnvironment = context.Services.GetHostingEnvironment(); + + //... other configarations. + + ConfigureHangfire(context, configuration); + } + + private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration) + { + context.Services.AddHangfire(config => + { + config.UseSqlServerStorage(configuration.GetConnectionString("Default")); + }); + } +```` + +> 你必须为Hangfire配置一个存储 + ## 创建后台工作者 `HangfireBackgroundWorkerBase` 是创建一个后台工作者简单的方法. diff --git a/docs/zh-Hans/Dependency-Injection.md b/docs/zh-Hans/Dependency-Injection.md index 2264a12930..2c22c123ab 100644 --- a/docs/zh-Hans/Dependency-Injection.md +++ b/docs/zh-Hans/Dependency-Injection.md @@ -270,16 +270,16 @@ using (var scope = _serviceProvider.CreateScope()) ## 高级特性 -### IServiceCollection.OnRegistred 事件 +### IServiceCollection.OnRegistered 事件 -你可能想在注册到依赖注入的每个服务上执行一个操作, 在你的模块的 `PreConfigureServices` 方法中, 使用 `OnRegistred` 方法注册一个回调(callback) , 如下所示: +你可能想在注册到依赖注入的每个服务上执行一个操作, 在你的模块的 `PreConfigureServices` 方法中, 使用 `OnRegistered` 方法注册一个回调(callback) , 如下所示: ````csharp public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { var type = ctx.ImplementationType; //... @@ -295,7 +295,7 @@ public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true)) { @@ -308,7 +308,7 @@ public class AppModule : AbpModule 这个示例判断一个服务类是否具有 `MyLogAttribute` 特性, 如果有的话就添加一个 `MyLogInterceptor` 到拦截器集合中. -> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistred` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md). +> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistered` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md). ## 第三方提供程序 diff --git a/docs/zh-Hans/Tutorials/Part-10.md b/docs/zh-Hans/Tutorials/Part-10.md index 170e3106a1..da5c23c78f 100644 --- a/docs/zh-Hans/Tutorials/Part-10.md +++ b/docs/zh-Hans/Tutorials/Part-10.md @@ -367,7 +367,7 @@ namespace Acme.BookStore.Books GetListPolicyName = BookStorePermissions.Books.Default; CreatePolicyName = BookStorePermissions.Books.Create; UpdatePolicyName = BookStorePermissions.Books.Edit; - DeletePolicyName = BookStorePermissions.Books.Create; + DeletePolicyName = BookStorePermissions.Books.Delete; } public override async Task GetAsync(Guid id) diff --git a/docs/zh-Hans/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md b/docs/zh-Hans/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md index 5ec349b8b6..5672eebe09 100644 --- a/docs/zh-Hans/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md +++ b/docs/zh-Hans/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md @@ -110,6 +110,10 @@ public class DynamicFormsModel : PageModel 为动态表单设置c#模型,模型的属性以表单形式转化为输入. +### column-size + +此处使用 `col-sm` 来设置大小。当设置该属性是会同时添加 `col-12` . + ### submit-button 可以为 `True` 或 `False`. diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs new file mode 100644 index 0000000000..61c064b376 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs @@ -0,0 +1,56 @@ +using System; +using IdentityModel.Client; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication.Cookies; + +public static class CookieAuthenticationOptionsExtensions +{ + /// + /// Introspect access token on validating the principal. + /// + /// + /// + /// + public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") + { + var originalHandler = options.Events.OnValidatePrincipal; + options.Events.OnValidatePrincipal = async principalContext => + { + originalHandler?.Invoke(principalContext); + + if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated) + { + var accessToken = principalContext.Properties.GetTokenValue("access_token"); + if (!accessToken.IsNullOrWhiteSpace()) + { + var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService>().Get(oidcAuthenticationScheme); + if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) + { + openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted); + } + + var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest + { + Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect", + ClientId = openIdConnectOptions.ClientId, + ClientSecret = openIdConnectOptions.ClientSecret, + Token = accessToken + }); + + if (response.IsActive) + { + return; + } + } + + principalContext.RejectPrincipal(); + await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); + } + }; + + return options; + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj index 09c743bc2a..297b2a8576 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj @@ -12,11 +12,13 @@
- - - - - + + + + + + +
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs index 9a6a40a17a..aa48ad633b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/TableColumns/TableColumn.cs @@ -10,14 +10,22 @@ public class TableColumn { public string Title { get; set; } public string Data { get; set; } + + public string PropertyName { get; set; } + [CanBeNull] public string DisplayFormat { get; set; } + public IFormatProvider DisplayFormatProvider { get; set; } = CultureInfo.CurrentCulture; + [CanBeNull] public Type Component { get; set; } + public List Actions { get; set; } + [CanBeNull] public Func ValueConverter { get; set; } + public bool Sortable { get; set; } public TableColumn() diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.cs new file mode 100644 index 0000000000..40ac508030 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.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.WebAssembly.Configuration; + +[Dependency(ReplaceServices = true)] +public class BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService : + ICurrentApplicationConfigurationCacheResetService, + ITransientDependency +{ + private readonly WebAssemblyCachedApplicationConfigurationClient _webAssemblyCachedApplicationConfigurationClient; + + public BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService(WebAssemblyCachedApplicationConfigurationClient webAssemblyCachedApplicationConfigurationClient) + { + _webAssemblyCachedApplicationConfigurationClient = webAssemblyCachedApplicationConfigurationClient; + } + + public async Task ResetAsync() + { + await _webAssemblyCachedApplicationConfigurationClient.InitializeAsync(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs index da4a567b5d..463cd73971 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelper.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; @@ -12,6 +13,9 @@ public class AbpDynamicFormTagHelper : AbpTagHelper"); + foreach (var item in items.OrderBy(o => o.Order)) { - contentBuilder.AppendLine(item.HtmlContent); + contentBuilder.AppendLine(SetColumn(item.HtmlContent)); } + contentBuilder.AppendLine(""); + var content = childContent.GetContent(); if (content.Contains(AbpFormContentPlaceHolder)) { @@ -115,6 +121,18 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService{htmlContent}"; + } + protected virtual async Task SetSubmitButton(TagHelperContext context, TagHelperOutput output) { if (!TagHelper.SubmitButton ?? true) @@ -144,6 +162,10 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService(); + abpDateInputTagHelper.AspFor = model; + abpDateInputTagHelper.ViewContext = TagHelper.ViewContext; + abpDateInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true; + return abpDateInputTagHelper; + } + + private AbpTagHelper GetAbpDateRangeInputTagHelper(TagHelperContext context, TagHelperOutput output, ModelExpression model) + { + var modelAttribute = model.ModelExplorer.GetAttribute(); + + var pickerId = modelAttribute.PickerId; + + var abpDateRangeInputTagHelper = _serviceProvider.GetRequiredService(); + abpDateRangeInputTagHelper.PickerId = pickerId; + abpDateRangeInputTagHelper.ViewContext = TagHelper.ViewContext; + + if (modelAttribute.IsStart) + { + abpDateRangeInputTagHelper.AspForStart = model; + + var otherModelExists = TryToGetOtherDateModel(model, pickerId, out var otherModel); + if (otherModelExists && otherModel.GetAttribute().IsEnd) + { + abpDateRangeInputTagHelper.AspForEnd = ModelExplorerToModelExpressionConverter(otherModel); + } + } + + return abpDateRangeInputTagHelper; + } + + private bool TryToGetOtherDateModel(ModelExpression model, string pickerId, out ModelExplorer otherModel) + { + otherModel = TagHelper.Model.ModelExplorer.Properties.SingleOrDefault(x => x != model.ModelExplorer && x.GetAttribute()?.PickerId == pickerId); + return otherModel != null; + } + + private static bool IsDateRangeGroup(ModelExplorer modelModelExplorer) + { + return modelModelExplorer.GetAttribute() != null; + } + protected virtual void RemoveFormGroupItemsNotInModel(TagHelperContext context, TagHelperOutput output, List items) { var models = GetModels(context, output); @@ -294,6 +374,25 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService() != null || + model.ModelExplorer.GetAttribute() != null) + { + return true; + } + + if (model.Metadata.ModelType == typeof(DateTime) || + model.Metadata.ModelType == typeof(DateTime?) || + model.Metadata.ModelType == typeof(DateTimeOffset) || + model.Metadata.ModelType == typeof(DateTimeOffset?)) + { + return true; + } + + return false; + } + protected virtual bool IsEnum(ModelExplorer explorer) { return explorer.Metadata.IsEnum; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 0a3d1e1c08..a3cecfa471 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -294,8 +294,10 @@ public class AbpInputTagHelperService : AbpTagHelperService { return ""; } + + var isHaveRequiredAttribute = context.AllAttributes.Any(a => a.Name == "required"); - return TagHelper.AspFor.ModelExplorer.GetAttribute() != null ? " * " : ""; + return TagHelper.AspFor.ModelExplorer.GetAttribute() != null || isHaveRequiredAttribute ? " * " : ""; } protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs index 58c7b1b45d..e6bac77fa3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelper.cs @@ -37,6 +37,8 @@ public class AbpSelectTagHelper : AbpTagHelper output.Attributes.Add("data-autocomplete-selected-item-value", TagHelper.AutocompleteSelectedItemValue); output.Attributes.Add("data-autocomplete-allow-clear", TagHelper.AllowClear); output.Attributes.Add("data-autocomplete-placeholder", TagHelper.Placeholder); + output.Attributes.Add("data-autocomplete-parent-selector", TagHelper.AutocompleteParentSelector); } } @@ -196,8 +197,10 @@ public class AbpSelectTagHelperService : AbpTagHelperService { return ""; } + + var isHaveRequiredAttribute = context.AllAttributes.Any(a => a.Name == "required"); - return TagHelper.AspFor.ModelExplorer.GetAttribute() != null ? " * " : ""; + return TagHelper.AspFor.ModelExplorer.GetAttribute() != null || isHaveRequiredAttribute ? " * " : ""; } protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs new file mode 100644 index 0000000000..10923f25af --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public abstract class + AbpDatePickerBaseTagHelper : AbpTagHelper>, IAbpDatePickerOptions + where TTagHelper : AbpDatePickerBaseTagHelper + +{ + private readonly IAbpDatePickerOptions _abpDatePickerOptionsImplementation; + + public string Label { get; set; } + + public string LabelTooltip { get; set; } + + public string LabelTooltipIcon { get; set; } = "bi-info-circle"; + + public string LabelTooltipPlacement { get; set; } = "right"; + + public bool LabelTooltipHtml { get; set; } = false; + + [HtmlAttributeName("info")] + public string InfoText { get; set; } + + [HtmlAttributeName("disabled")] + public bool IsDisabled { get; set; } = false; + + [HtmlAttributeName("readonly")] + public bool? IsReadonly { get; set; } = false; + + public bool AutoFocus { get; set; } + + public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; + + [HtmlAttributeName("required-symbol")] + public bool DisplayRequiredSymbol { get; set; } = true; + + public string Name { get; set; } + + public string Value { get; set; } + + public bool SuppressLabel { get; set; } + + protected AbpDatePickerBaseTagHelper(AbpDatePickerBaseTagHelperService service) : base(service) + { + _abpDatePickerOptionsImplementation = new AbpDatePickerOptions(); + } + + public string PickerId { + get => _abpDatePickerOptionsImplementation.PickerId; + set => _abpDatePickerOptionsImplementation.PickerId = value; + } + + public DateTime? MinDate { + get => _abpDatePickerOptionsImplementation.MinDate; + set => _abpDatePickerOptionsImplementation.MinDate = value; + } + + public DateTime? MaxDate { + get => _abpDatePickerOptionsImplementation.MaxDate; + set => _abpDatePickerOptionsImplementation.MaxDate = value; + } + + public object MaxSpan { + get => _abpDatePickerOptionsImplementation.MaxSpan; + set => _abpDatePickerOptionsImplementation.MaxSpan = value; + } + + public bool? ShowDropdowns { + get => _abpDatePickerOptionsImplementation.ShowDropdowns; + set => _abpDatePickerOptionsImplementation.ShowDropdowns = value; + } + + public int? MinYear { + get => _abpDatePickerOptionsImplementation.MinYear; + set => _abpDatePickerOptionsImplementation.MinYear = value; + } + + public int? MaxYear { + get => _abpDatePickerOptionsImplementation.MaxYear; + set => _abpDatePickerOptionsImplementation.MaxYear = value; + } + + public AbpDatePickerWeekNumbers WeekNumbers { + get => _abpDatePickerOptionsImplementation.WeekNumbers; + set => _abpDatePickerOptionsImplementation.WeekNumbers = value; + } + + public bool? TimePicker { + get => _abpDatePickerOptionsImplementation.TimePicker; + set => _abpDatePickerOptionsImplementation.TimePicker = value; + } + + public int? TimePickerIncrement { + get => _abpDatePickerOptionsImplementation.TimePickerIncrement; + set => _abpDatePickerOptionsImplementation.TimePickerIncrement = value; + } + + public bool? TimePicker24Hour { + get => _abpDatePickerOptionsImplementation.TimePicker24Hour; + set => _abpDatePickerOptionsImplementation.TimePicker24Hour = value; + } + + public bool? TimePickerSeconds { + get => _abpDatePickerOptionsImplementation.TimePickerSeconds; + set => _abpDatePickerOptionsImplementation.TimePickerSeconds = value; + } + + public List Ranges { + get => _abpDatePickerOptionsImplementation.Ranges; + set => _abpDatePickerOptionsImplementation.Ranges = value; + } + + public bool? ShowCustomRangeLabel { + get => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel; + set => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel = value; + } + + public bool? AlwaysShowCalendars { + get => _abpDatePickerOptionsImplementation.AlwaysShowCalendars; + set => _abpDatePickerOptionsImplementation.AlwaysShowCalendars = value; + } + + public AbpDatePickerOpens Opens { + get => _abpDatePickerOptionsImplementation.Opens; + set => _abpDatePickerOptionsImplementation.Opens = value; + } + + public AbpDatePickerDrops Drops { + get => _abpDatePickerOptionsImplementation.Drops; + set => _abpDatePickerOptionsImplementation.Drops = value; + } + + public string ButtonClasses { + get => _abpDatePickerOptionsImplementation.ButtonClasses; + set => _abpDatePickerOptionsImplementation.ButtonClasses = value; + } + + public string TodayButtonClasses { + get => _abpDatePickerOptionsImplementation.TodayButtonClasses; + set => _abpDatePickerOptionsImplementation.TodayButtonClasses = value; + } + + public string ApplyButtonClasses { + get => _abpDatePickerOptionsImplementation.ApplyButtonClasses; + set => _abpDatePickerOptionsImplementation.ApplyButtonClasses = value; + } + + public string ClearButtonClasses { + get => _abpDatePickerOptionsImplementation.ClearButtonClasses; + set => _abpDatePickerOptionsImplementation.ClearButtonClasses = value; + } + + public object Locale { + get => _abpDatePickerOptionsImplementation.Locale; + set => _abpDatePickerOptionsImplementation.Locale = value; + } + + public bool? AutoApply { + get => _abpDatePickerOptionsImplementation.AutoApply; + set => _abpDatePickerOptionsImplementation.AutoApply = value; + } + + public bool? LinkedCalendars { + get => _abpDatePickerOptionsImplementation.LinkedCalendars; + set => _abpDatePickerOptionsImplementation.LinkedCalendars = value; + } + + public bool? AutoUpdateInput { + get => _abpDatePickerOptionsImplementation.AutoUpdateInput; + set => _abpDatePickerOptionsImplementation.AutoUpdateInput = value; + } + + public string ParentEl { + get => _abpDatePickerOptionsImplementation.ParentEl; + set => _abpDatePickerOptionsImplementation.ParentEl = value; + } + + public string DateFormat { + get => _abpDatePickerOptionsImplementation.DateFormat; + set => _abpDatePickerOptionsImplementation.DateFormat = value; + } + + public bool OpenButton { + get => _abpDatePickerOptionsImplementation.OpenButton; + set => _abpDatePickerOptionsImplementation.OpenButton = value; + } + + public bool ClearButton { + get => _abpDatePickerOptionsImplementation.ClearButton; + set => _abpDatePickerOptionsImplementation.ClearButton = value; + } + + public bool SingleOpenAndClearButton { + get => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton; + set => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton = value; + } + + public bool? IsUtc { + get => _abpDatePickerOptionsImplementation.IsUtc; + set => _abpDatePickerOptionsImplementation.IsUtc = value; + } + + public bool? IsIso { + get => _abpDatePickerOptionsImplementation.IsIso; + set => _abpDatePickerOptionsImplementation.IsIso = value; + } + + public object Options { + get => _abpDatePickerOptionsImplementation.Options; + set => _abpDatePickerOptionsImplementation.Options = value; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs new file mode 100644 index 0000000000..82273097cf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -0,0 +1,712 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.Json; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelperService + where TTagHelper : AbpDatePickerBaseTagHelper +{ + protected readonly Dictionary> SupportedInputTypes = new() { + {typeof(string), o => DateTime.Parse((string)o).ToString("O")}, + {typeof(DateTime), o => ((DateTime) o).ToString("O")}, + {typeof(DateTime?), o => ((DateTime?) o)?.ToString("O")}, + {typeof(DateTimeOffset), o => ((DateTimeOffset) o).ToString("O")}, + {typeof(DateTimeOffset?), o => ((DateTimeOffset?) o)?.ToString("O")} + }; + + protected readonly IJsonSerializer JsonSerializer; + protected readonly IHtmlGenerator Generator; + protected readonly HtmlEncoder Encoder; + protected readonly IServiceProvider ServiceProvider; + protected readonly IAbpTagHelperLocalizer TagHelperLocalizer; + protected virtual string TagName { get; set; } = "abp-date-picker"; + protected IStringLocalizer L { get; } + protected InputTagHelper InputTagHelper { get; set; } + protected abstract TagHelperOutput TagHelperOutput { get; set; } + + protected AbpDatePickerBaseTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, + HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, + IAbpTagHelperLocalizer tagHelperLocalizer) + { + JsonSerializer = jsonSerializer; + Generator = generator; + Encoder = encoder; + ServiceProvider = serviceProvider; + L = l; + TagHelperLocalizer = tagHelperLocalizer; + + InputTagHelper = new InputTagHelper(Generator) { InputTypeName = "text" }; + } + + protected virtual T GetAttribute() where T : Attribute + { + return GetAttributeAndModelExpression(out _); + } + + protected abstract T GetAttributeAndModelExpression(out ModelExpression modelExpression) where T : Attribute; + + + public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + TagHelperOutput = new TagHelperOutput("input", GetInputAttributes(context, output), (_, _) => Task.FromResult(new DefaultTagHelperContent())); + + InputTagHelper.ViewContext = TagHelper.ViewContext; + + if (!TagHelper.Name.IsNullOrEmpty()) + { + InputTagHelper.Name = TagHelper.Name; + } + + if (!TagHelper.Value.IsNullOrEmpty()) + { + InputTagHelper.Value = TagHelper.Value; + } + + AddDisabledAttribute(TagHelperOutput); + AddAutoFocusAttribute(TagHelperOutput); + AddFormControls(context, output, TagHelperOutput); + AddReadOnlyAttribute(TagHelperOutput); + AddPlaceholderAttribute(TagHelperOutput); + AddInfoTextId(TagHelperOutput); + + // Open and close button + var openButtonContent = TagHelper.OpenButton + ? await ProcessButtonAndGetContentAsync(context, output, "calendar", "open") + : ""; + var clearButtonContent = TagHelper.ClearButton + ? await ProcessButtonAndGetContentAsync(context, output, "times", "clear", visible:!TagHelper.SingleOpenAndClearButton) + : ""; + + var labelContent = await GetLabelAsHtmlAsync(context, output, TagHelperOutput); + var infoContent = GetInfoAsHtml(context, output, TagHelperOutput); + var validationContent = await GetValidationAsHtmlAsync(context, output); + + var inputGroup = new TagHelperOutput("div", + new TagHelperAttributeList(new[] { new TagHelperAttribute("class", "input-group") }), + (_, _) => Task.FromResult(new DefaultTagHelperContent())); + inputGroup.Content.AppendHtml( + TagHelperOutput.Render(Encoder) + openButtonContent + clearButtonContent + ); + + var abpDatePickerTag = new TagHelperOutput(TagName, GetBaseTagAttributes(context, output, TagHelper), + (_, _) => Task.FromResult(new DefaultTagHelperContent())); + abpDatePickerTag.Content.AppendHtml(inputGroup.Render(Encoder)); + abpDatePickerTag.Content.AppendHtml(validationContent); + abpDatePickerTag.Content.AppendHtml(GetExtraInputHtml(context, output)); + + var innerHtml = labelContent + abpDatePickerTag.Render(Encoder) + infoContent; + + var order = GetOrder(); + + AddGroupToFormGroupContents( + context, + GetPropertyName(), + SurroundInnerHtmlAndGet(context, output, innerHtml), + order + ); + + + output.TagMode = TagMode.StartTagAndEndTag; + output.TagName = "div"; + LeaveOnlyGroupAttributes(context, output); + output.Attributes.AddClass("mb-3"); + + output.Content.AppendHtml(innerHtml); + } + + protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false && + (TagHelper.IsReadonly != false || GetAttribute() != null)) + { + inputTagHelperOutput.Attributes.Add("readonly", ""); + } + } + + protected virtual TagHelperAttributeList GetInputAttributes(TagHelperContext context, TagHelperOutput output) + { + var groupPrefix = "group-"; + + var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); + + var attrList = new TagHelperAttributeList(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + attrList.Add(tagHelperAttribute); + } + + attrList.Add("type", "text"); + + if (attrList.ContainsName("value")) + { + attrList.Remove(attrList.First(a => a.Name == "value")); + } + + if (!TagHelper.Name.IsNullOrEmpty() && !attrList.ContainsName("name")) + { + attrList.Add("name", TagHelper.Name); + } + + if (!attrList.ContainsName("autocomplete")) + { + attrList.Add("autocomplete", "off"); + } + + return attrList; + } + protected virtual void LeaveOnlyGroupAttributes(TagHelperContext context, TagHelperOutput output) + { + var groupPrefix = "group-"; + var tagHelperAttributes = output.Attributes.Where(a => a.Name.StartsWith(groupPrefix)).ToList(); + + output.Attributes.Clear(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + var nameWithoutPrefix = tagHelperAttribute.Name.Substring(groupPrefix.Length); + var newAttribute = new TagHelperAttribute(nameWithoutPrefix, tagHelperAttribute.Value); + output.Attributes.Add(newAttribute); + } + } + + protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml) + { + return "
" + + Environment.NewLine + innerHtml + Environment.NewLine + + "
"; + } + + protected abstract string GetPropertyName(); + + protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, + int order) + { + var list = context.GetValue>(FormGroupContents) ?? new List(); + + if (!list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\""))) + { + list.Add(new FormGroupItem { HtmlContent = html, Order = order, PropertyName = propertyName }); + } + } + + protected abstract int GetOrder(); + protected abstract void AddBaseTagAttributes(TagHelperAttributeList attributes); + + protected virtual string GetExtraInputHtml(TagHelperContext context, TagHelperOutput output) + { + return string.Empty; + } + + protected TagHelperAttributeList ConvertDatePickerOptionsToAttributeList(IAbpDatePickerOptions options) + { + var attrList = new TagHelperAttributeList(); + + if(options == null) + { + return attrList; + } + + if (options.Locale != null) + { + attrList.Add("data-locale", JsonSerializer.Serialize(options.Locale)); + } + + if (options.MinDate != null) + { + attrList.Add("data-min-date", options.MinDate); + } + + if (options.MaxDate != null) + { + attrList.Add("data-max-date", options.MaxDate); + } + + if (options.MaxSpan != null) + { + attrList.Add("data-max-span", JsonSerializer.Serialize(options.MaxSpan)); + } + + if (options.ShowDropdowns == false) + { + attrList.Add("data-show-dropdowns", options.ShowDropdowns.ToString().ToLowerInvariant()); + } + + if (options.MinYear != null) + { + attrList.Add("data-min-year", options.MinYear); + } + + if (options.MaxYear != null) + { + attrList.Add("data-max-year", options.MaxYear); + } + + switch (options.WeekNumbers) + { + case AbpDatePickerWeekNumbers.Normal: + attrList.Add("data-show-week-numbers", "true"); + break; + case AbpDatePickerWeekNumbers.Iso: + attrList.Add("data-show-i-s-o-week-numbers", "true"); + break; + } + + if (options.TimePicker != null) + { + attrList.Add("data-time-picker", options.TimePicker.ToString().ToLowerInvariant()); + } + + if (options.TimePickerIncrement != null) + { + attrList.Add("data-time-picker-increment", options.TimePickerIncrement); + } + + if (options.TimePicker24Hour != null) + { + attrList.Add("data-time-picker24-hour", options.TimePicker24Hour.ToString().ToLowerInvariant()); + } + + if (options.TimePickerSeconds != null) + { + attrList.Add("data-time-picker-seconds", options.TimePickerSeconds.ToString().ToLowerInvariant()); + } + + if (options.Opens != AbpDatePickerOpens.Center) + { + attrList.Add("data-opens", options.Opens.ToString().ToLowerInvariant()); + } + + if (options.Drops != AbpDatePickerDrops.Down) + { + attrList.Add("data-drops", options.Drops.ToString().ToLowerInvariant()); + } + + if (!options.ButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-button-classes", options.ButtonClasses); + } + + if (!options.ApplyButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-apply-button-classes", options.ApplyButtonClasses); + } + + if (!options.ClearButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-clear-button-classes", options.ClearButtonClasses); + } + + if (!options.TodayButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-today-button-classes", options.TodayButtonClasses); + } + + if (options.AutoApply != null) + { + attrList.Add("data-auto-apply", options.AutoApply.ToString().ToLowerInvariant()); + } + + if (options.LinkedCalendars != null) + { + attrList.Add("data-linked-calendars", options.LinkedCalendars.ToString().ToLowerInvariant()); + } + + if (options.AutoUpdateInput != null) + { + attrList.Add("data-auto-update-input", options.AutoUpdateInput.ToString().ToLowerInvariant()); + } + + if (!options.ParentEl.IsNullOrEmpty()) + { + attrList.Add("data-parent-el", options.ParentEl); + } + + if (!options.DateFormat.IsNullOrEmpty()) + { + attrList.Add("data-date-format", options.DateFormat); + } + + if(options.Ranges != null && options.Ranges.Any()) + { + var ranges = options.Ranges.ToDictionary(r => r.Label, r => r.Dates); + + attrList.Add("data-ranges", JsonSerializer.Serialize(ranges)); + } + + if(options.AlwaysShowCalendars != null) + { + attrList.Add("data-always-show-calendars", options.AlwaysShowCalendars.ToString().ToLowerInvariant()); + } + + if(options.ShowCustomRangeLabel == false) + { + attrList.Add("data-show-custom-range-label", options.ShowCustomRangeLabel.ToString().ToLowerInvariant()); + } + + if(options.Options != null) + { + attrList.Add("data-options", JsonSerializer.Serialize(options.Options)); + } + + if (options.IsUtc != null) + { + attrList.Add("data-is-utc", options.IsUtc.ToString().ToLowerInvariant()); + } + + if (options.IsIso != null) + { + attrList.Add("data-is-iso", options.IsIso.ToString().ToLowerInvariant()); + } + + if (!options.PickerId.IsNullOrWhiteSpace()) + { + attrList.Add("id", options.PickerId); + } + + if(!options.SingleOpenAndClearButton) + { + attrList.Add("data-single-open-and-clear-button", options.SingleOpenAndClearButton.ToString().ToLowerInvariant()); + } + + return attrList; + } + + protected TagHelperAttributeList GetBaseTagAttributes(TagHelperContext context, TagHelperOutput output, IAbpDatePickerOptions options) + { + var groupPrefix = "group-"; + + var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); + + var attrList = new TagHelperAttributeList(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + attrList.Add(tagHelperAttribute); + } + + if (attrList.ContainsName("type")) + { + attrList.Remove(attrList.First(a => a.Name == "type")); + } + + if (attrList.ContainsName("name")) + { + attrList.Remove(attrList.First(a => a.Name == "name")); + } + + if (attrList.ContainsName("id")) + { + attrList.Remove(attrList.First(a => a.Name == "id")); + } + + if (attrList.ContainsName("value")) + { + attrList.Remove(attrList.First(a => a.Name == "value")); + } + + foreach (var attr in ConvertDatePickerOptionsToAttributeList(options)) + { + attrList.Add(attr); + } + + var optionsAttribute = GetAttributeAndModelExpression(out var modelExpression); + if (optionsAttribute != null) + { + foreach (var attr in ConvertDatePickerOptionsToAttributeList(optionsAttribute.GetDatePickerOptions(modelExpression.ModelExplorer))) + { + attrList.Add(attr); + } + } + + AddBaseTagAttributes(attrList); + + return attrList; + } + + protected virtual bool IsOutputHidden(TagHelperOutput inputTag) + { + return inputTag.Attributes.Any(a => + a.Name.ToLowerInvariant() == "type" && a.Value?.ToString()?.ToLowerInvariant() == "hidden"); + } + + protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) + { + if (IsOutputHidden(inputTag)) + { + return string.Empty; + } + + string text; + ModelExplorer modelExplorer = null; + + if (!string.IsNullOrEmpty(TagHelper.InfoText)) + { + text = TagHelper.InfoText; + } + else + { + var infoAttribute = GetAttributeAndModelExpression(out var modelExpression); + if (infoAttribute != null) + { + modelExplorer = modelExpression.ModelExplorer; + text = infoAttribute.Text; + } + else + { + return string.Empty; + } + } + + var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + modelExplorer ??= GetModelExpression().ModelExplorer; + var localizedText = TagHelperLocalizer.GetLocalizedText(text, modelExplorer); + + var div = new TagBuilder("div"); + div.Attributes.Add("id", idAttr?.Value + "InfoText"); + div.AddCssClass("form-text"); + div.InnerHtml.Append(localizedText); + + inputTag.Attributes.Add("aria-describedby", idAttr?.Value + "InfoText"); + + return div.ToHtmlString(); + } + + protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, + TagHelperOutput inputTag) + { + if (IsOutputHidden(inputTag) || TagHelper.SuppressLabel) + { + return string.Empty; + } + if (string.IsNullOrEmpty(TagHelper.Label)) + { + return await GetLabelAsHtmlUsingTagHelperAsync(context, output) + GetRequiredSymbol(context, output); + } + + var label = new TagBuilder("label"); + label.Attributes.Add("for", GetIdAttributeValue(inputTag)); + label.InnerHtml.AppendHtml(TagHelper.Label); + + label.AddCssClass("form-label"); + + if (!TagHelper.LabelTooltip.IsNullOrEmpty()) + { + label.Attributes.Add("data-bs-toggle", "tooltip"); + label.Attributes.Add("data-bs-placement", TagHelper.LabelTooltipPlacement); + if (TagHelper.LabelTooltipHtml) + { + label.Attributes.Add("data-bs-html", "true"); + } + + label.Attributes.Add("title", TagHelper.LabelTooltip); + label.InnerHtml.AppendHtml($" "); + } + + return label.ToHtmlString(); + } + + protected virtual string GetIdAttributeValue(TagHelperOutput inputTag) + { + var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + + return idAttr != null ? idAttr.Value.ToString() : string.Empty; + } + + protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output) + { + if (!TagHelper.DisplayRequiredSymbol) + { + return ""; + } + + var isHaveRequiredAttribute = context.AllAttributes.Any(a => a.Name == "required"); + + return GetAttribute() != null || isHaveRequiredAttribute ? " * " : ""; + } + + protected abstract ModelExpression GetModelExpression(); + + protected virtual async Task GetLabelAsHtmlUsingTagHelperAsync(TagHelperContext context, + TagHelperOutput output) + { + var modelExpression = GetModelExpression(); + if (modelExpression == null) + { + return string.Empty; + } + var labelTagHelper = new LabelTagHelper(Generator) { + ViewContext = TagHelper.ViewContext, + For = modelExpression + }; + + var attributeList = new TagHelperAttributeList(); + + attributeList.AddClass("form-label"); + + if (!TagHelper.LabelTooltip.IsNullOrEmpty()) + { + attributeList.Add("data-bs-toggle", "tooltip"); + attributeList.Add("data-bs-placement", TagHelper.LabelTooltipPlacement); + if (TagHelper.LabelTooltipHtml) + { + attributeList.Add("data-bs-html", "true"); + } + + attributeList.Add("title", TagHelper.LabelTooltip); + } + + var innerOutput = + await labelTagHelper.ProcessAndGetOutputAsync(attributeList, context, "label", TagMode.StartTagAndEndTag); + if (!TagHelper.LabelTooltip.IsNullOrEmpty()) + { + innerOutput.Content.AppendHtml($" "); + } + + return innerOutput.Render(Encoder); + } + + protected virtual async Task ProcessButtonAndGetContentAsync(TagHelperContext context, + TagHelperOutput output, string icon, string type, bool visible = true) + { + var abpButtonTagHelper = ServiceProvider.GetRequiredService(); + var attributes = + new TagHelperAttributeList { new("type", "button"), new("tabindex", "-1"), new("data-type", type) }; + abpButtonTagHelper.ButtonType = AbpButtonType.Outline_Secondary; + abpButtonTagHelper.Icon = icon; + + abpButtonTagHelper.Disabled = TagHelper.IsDisabled; + + if (!visible) + { + attributes.AddClass("d-none"); + } + + return await abpButtonTagHelper.RenderAsync(attributes, context, Encoder, "button", TagMode.StartTagAndEndTag); + } + + protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) + { + if (GetAttribute() == null) + { + return; + } + + var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id"); + + if (idAttr == null) + { + return; + } + + inputTagHelperOutput.Attributes.Add("aria-describedby", GetInfoText()); + } + + public virtual string GetInfoText() + { + var infoAttribute = GetAttributeAndModelExpression(out var modelExpression); + + if (infoAttribute != null) + { + return TagHelperLocalizer.GetLocalizedText(infoAttribute.Text, modelExpression.ModelExplorer); + } + + return string.Empty; + } + + protected virtual void AddPlaceholderAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("placeholder")) + { + return; + } + + var attribute = GetAttributeAndModelExpression(out var modelExpression); + + if (attribute != null) + { + var placeholderLocalized = + TagHelperLocalizer.GetLocalizedText(attribute.Value, modelExpression.ModelExplorer); + + inputTagHelperOutput.Attributes.Add("placeholder", placeholderLocalized); + } + } + + protected virtual void AddFormControls(TagHelperContext context, TagHelperOutput output, + TagHelperOutput inputTagHelperOutput) + { + inputTagHelperOutput.Attributes.AddClass("form-control"); + var size = GetSize(context, output); + if (!size.IsNullOrEmpty()) + { + inputTagHelperOutput.Attributes.AddClass(size); + } + } + + protected virtual void AddAutoFocusAttribute(TagHelperOutput inputTagHelperOutput) + { + if (TagHelper.AutoFocus && !inputTagHelperOutput.Attributes.ContainsName("data-auto-focus")) + { + inputTagHelperOutput.Attributes.Add("data-auto-focus", "true"); + } + } + + protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false && + (TagHelper.IsDisabled || GetAttribute() != null)) + { + inputTagHelperOutput.Attributes.Add("disabled", ""); + } + } + + + protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) + { + // TODO: Test this method + var attribute = GetAttribute(); + + if (attribute != null) + { + TagHelper.Size = attribute.Size; + } + + return TagHelper.Size switch { + AbpFormControlSize.Small => "form-control-sm", + AbpFormControlSize.Medium => "form-control-md", + AbpFormControlSize.Large => "form-control-lg", + _ => "" + }; + } + + protected abstract Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output); + + protected virtual async Task GetValidationAsHtmlByInputAsync(TagHelperContext context, + TagHelperOutput output, + [NotNull]InputTagHelper inputTag) + { + var validationMessageTagHelper = + new ValidationMessageTagHelper(Generator) { For = inputTag.For, ViewContext = TagHelper.ViewContext }; + + var attributeList = new TagHelperAttributeList { { "class", "text-danger col-auto" } }; + + return await validationMessageTagHelper.RenderAsync(attributeList, context, Encoder, "span", + TagMode.StartTagAndEndTag); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs new file mode 100644 index 0000000000..c61cbfec78 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerDrops : byte +{ + Down = 1, + Up = 2, + Auto = 3 +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs new file mode 100644 index 0000000000..a74bf229ef --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs @@ -0,0 +1,10 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerOpens : byte +{ + Left = 1, + Right = 2, + Center = 3, +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs new file mode 100644 index 0000000000..15b4e2003d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public class AbpDatePickerOptions : IAbpDatePickerOptions +{ + public string PickerId { get; set; } + public DateTime? MinDate { get; set; } + public DateTime? MaxDate { get; set; } + public object MaxSpan { get; set; } + public bool? ShowDropdowns { get; set; } + public int? MinYear { get; set; } + public int? MaxYear { get; set; } + public AbpDatePickerWeekNumbers WeekNumbers { get; set; } = AbpDatePickerWeekNumbers.None; + public bool? TimePicker { get; set; } + public int? TimePickerIncrement { get; set; } + public bool? TimePicker24Hour { get; set; } + public bool? TimePickerSeconds { get; set; } + public List Ranges { get; set; } + public bool? ShowCustomRangeLabel { get; set; } + public bool? AlwaysShowCalendars { get; set; } + public AbpDatePickerOpens Opens { get; set; } = AbpDatePickerOpens.Center; + public AbpDatePickerDrops Drops { get; set; } = AbpDatePickerDrops.Down; + public string ButtonClasses { get; set; } + public string TodayButtonClasses { get; set; } + public string ApplyButtonClasses { get; set; } + public string ClearButtonClasses { get; set; } + public object Locale { get; set; } + public bool? AutoApply { get; set; } + public bool? LinkedCalendars { get; set; } + public bool? AutoUpdateInput { get; set; } + public string ParentEl { get; set; } + public string DateFormat { get; set; } + public bool OpenButton { get; set; } = true; + public bool ClearButton { get; set; } = true; + public bool SingleOpenAndClearButton { get; set; } = true; + public bool? IsUtc { get; set; } + public bool? IsIso { get; set; } + public object Options { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs new file mode 100644 index 0000000000..eea3d2ad31 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public class AbpDatePickerRange +{ + private readonly List _dates = new List(); + public string Label { get; set; } + public IReadOnlyList Dates => _dates; + + public AbpDatePickerRange() + { + + } + public AbpDatePickerRange(string label, DateTime start, DateTime end) + { + Label = label; + AddDate(start); + AddDate(end); + } + + public AbpDatePickerRange(string label, DateTime date) + { + Label = label; + AddDate(date); + } + + public AbpDatePickerRange(string label, DateTimeOffset start, DateTimeOffset end) + { + Label = label; + AddDate(start); + AddDate(end); + } + + public AbpDatePickerRange(string label, DateTimeOffset date) + { + Label = label; + AddDate(date); + } + + public AbpDatePickerRange(string label, string start, string end) + { + Label = label; + AddDate(start); + AddDate(end); + } + + public AbpDatePickerRange(string label, string date) + { + Label = label; + AddDate(date); + } + + public void AddDate(string date) + { + _dates.Add(DateTime.Parse(date).ToString("O")); + } + + public void AddDate(DateTime date) + { + _dates.Add(date.ToString("O")); + } + + public void AddDate(DateTimeOffset date) + { + _dates.Add(date.ToString("O")); + } + + public void AddDate(DateTime? date) + { + if (date.HasValue) + { + _dates.Add(date.Value.ToString("O")); + } + } + + public void AddDate(DateTimeOffset? date) + { + if (date.HasValue) + { + _dates.Add(date.Value.ToString("O")); + } + } + + public void AddDate(string date, string format) + { + _dates.Add(DateTime.ParseExact(date, format, null).ToString("O")); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs new file mode 100644 index 0000000000..8426b0071b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[HtmlTargetElement("abp-date-picker", TagStructure = TagStructure.NormalOrSelfClosing)] +public class AbpDatePickerTagHelper : AbpDatePickerBaseTagHelper +{ + [CanBeNull] + public ModelExpression AspFor { get; set; } + + public AbpDatePickerTagHelper(AbpDatePickerTagHelperService service) : base(service) + { + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs new file mode 100644 index 0000000000..e5eae85c53 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs @@ -0,0 +1,88 @@ +using System; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.Json; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public class AbpDatePickerTagHelperService : AbpDatePickerBaseTagHelperService +{ + public AbpDatePickerTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, IAbpTagHelperLocalizer tagHelperLocalizer) : base(jsonSerializer, generator, encoder, serviceProvider, l, tagHelperLocalizer) + { + + } + + protected override TagHelperOutput TagHelperOutput { get; set; } + + [CanBeNull] + protected virtual InputTagHelper DateTagHelper { get; set; } + + [CanBeNull] + protected virtual TagHelperOutput DateTagHelperOutput { get; set; } + protected override string GetPropertyName() + { + return TagHelper.AspFor?.Name ?? string.Empty; + } + + protected override T GetAttributeAndModelExpression(out ModelExpression modelExpression) + { + modelExpression = TagHelper.AspFor; + return modelExpression?.ModelExplorer.GetAttribute(); + } + + public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + if (TagHelper.AspFor != null) + { + DateTagHelper = new InputTagHelper(Generator) + { + InputTypeName = "hidden", + ViewContext = TagHelper.ViewContext, + For = TagHelper.AspFor, + }; + + var attributes = new TagHelperAttributeList { { "data-date", "true" }, { "type", "hidden" } }; + DateTagHelperOutput = await DateTagHelper.ProcessAndGetOutputAsync(attributes, context, "input"); + } + + await base.ProcessAsync(context, output); + } + + + protected override int GetOrder() + { + return TagHelper.AspFor?.Metadata.Order ?? 0; + } + + protected override void AddBaseTagAttributes(TagHelperAttributeList attributes) + { + if (TagHelper.AspFor != null && + TagHelper.AspFor.Model != null && + SupportedInputTypes.TryGetValue(TagHelper.AspFor.Metadata.ModelType, out var convertFunc)) + { + attributes.Add("data-date", convertFunc(TagHelper.AspFor.Model)); + } + } + + protected override ModelExpression GetModelExpression() + { + return TagHelper.AspFor; + } + + protected async override Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output) + { + return DateTagHelper != null ? await GetValidationAsHtmlByInputAsync(context, output, DateTagHelper) : string.Empty; + } + + protected override string GetExtraInputHtml(TagHelperContext context, TagHelperOutput output) + { + return DateTagHelperOutput?.Render(Encoder); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs new file mode 100644 index 0000000000..b542fcec4d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerWeekNumbers : byte +{ + None = 0, + Normal = 1, + Iso = 2 +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs new file mode 100644 index 0000000000..bfd1e354f6 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[HtmlTargetElement("abp-date-range-picker", TagStructure = TagStructure.NormalOrSelfClosing)] +public class AbpDateRangePickerTagHelper : AbpDatePickerBaseTagHelper +{ + [CanBeNull] + public ModelExpression AspForStart { get; set; } + + [CanBeNull] + public ModelExpression AspForEnd { get; set; } + + public AbpDateRangePickerTagHelper(AbpDateRangePickerTagHelperService tagHelperService) : + base(tagHelperService) + { + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs new file mode 100644 index 0000000000..45a083b789 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs @@ -0,0 +1,132 @@ +using System; +using System.Linq; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.Json; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperService +{ + public AbpDateRangePickerTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, + HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, + IAbpTagHelperLocalizer tagHelperLocalizer) : + base(jsonSerializer, generator, encoder, serviceProvider, l, + tagHelperLocalizer) + { + } + + protected override string TagName { get; set; } = "abp-date-range-picker"; + + protected override T GetAttributeAndModelExpression(out ModelExpression modelExpression) + { + modelExpression = new[] { TagHelper.AspForStart, TagHelper.AspForEnd }.FirstOrDefault(x => x?.ModelExplorer?.GetAttribute() != null); + return modelExpression?.ModelExplorer.GetAttribute(); + } + + public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + if (TagHelper.AspForStart != null) + { + var startDateAttributes = new TagHelperAttributeList { { "data-start-date", "true" }, { "type", "hidden" } }; + StartDateTagHelper = new InputTagHelper(Generator) + { + ViewContext = TagHelper.ViewContext, + For = TagHelper.AspForStart, + InputTypeName = "hidden" + }; + + StartDateTagHelperOutput = await StartDateTagHelper.ProcessAndGetOutputAsync(startDateAttributes, context, "input"); + } + + if (TagHelper.AspForEnd != null) + { + var endDateAttributes = new TagHelperAttributeList { { "data-end-date", "true" }, { "type", "hidden" } }; + EndDateTagHelper = new InputTagHelper(Generator) + { + ViewContext = TagHelper.ViewContext, + For = TagHelper.AspForEnd, + InputTypeName = "hidden" + }; + + EndDateTagHelperOutput = await EndDateTagHelper.ProcessAndGetOutputAsync(endDateAttributes, context, "input"); + } + + await base.ProcessAsync(context, output); + } + + protected override TagHelperOutput TagHelperOutput { get; set; } + + [CanBeNull] + protected virtual InputTagHelper StartDateTagHelper { get; set; } + + [CanBeNull] + protected virtual TagHelperOutput StartDateTagHelperOutput { get; set; } + + [CanBeNull] + protected virtual InputTagHelper EndDateTagHelper { get; set; } + + [CanBeNull] + protected virtual TagHelperOutput EndDateTagHelperOutput { get; set; } + + protected override string GetPropertyName() + { + return TagHelper.AspForStart?.Name ?? string.Empty; + } + + protected override int GetOrder() + { + return TagHelper.Order; + } + + protected override void AddBaseTagAttributes(TagHelperAttributeList attributes) + { + if (TagHelper.AspForStart != null && + TagHelper.AspForStart.Model != null && + SupportedInputTypes.TryGetValue(TagHelper.AspForStart.Metadata.ModelType, out var convertFuncStart)) + { + attributes.Add("data-start-date", convertFuncStart(TagHelper.AspForStart.Model)); + } + + if (TagHelper.AspForEnd != null && + TagHelper.AspForEnd.Model != null && + SupportedInputTypes.TryGetValue(TagHelper.AspForEnd.Metadata.ModelType, out var convertFuncEnd)) + { + attributes.Add("data-end-date", convertFuncEnd(TagHelper.AspForEnd.Model)); + } + } + + protected override string GetExtraInputHtml(TagHelperContext context, TagHelperOutput output) + { + return StartDateTagHelperOutput?.Render(Encoder) + EndDateTagHelperOutput?.Render(Encoder); + } + + protected override ModelExpression GetModelExpression() + { + return TagHelper.AspForStart; + } + + protected async override Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output) + { + var validationHtml = string.Empty; + + if (StartDateTagHelper != null) + { + validationHtml += await GetValidationAsHtmlByInputAsync(context, output, StartDateTagHelper); + } + + if (EndDateTagHelper != null) + { + validationHtml += await GetValidationAsHtmlByInputAsync(context, output, EndDateTagHelper); + } + + return validationHtml; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs new file mode 100644 index 0000000000..840e21241e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[AttributeUsage(AttributeTargets.Property)] +public class DatePickerAttribute : Attribute +{ +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs new file mode 100644 index 0000000000..9cff72aa23 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ViewFeatures; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[AttributeUsage(AttributeTargets.Property)] +public class DatePickerOptionsAttribute : Attribute +{ + public string DatePickerOptionsPropertyName { get; set; } + + public DatePickerOptionsAttribute(string datePickerOptionsPropertyName) + { + DatePickerOptionsPropertyName = datePickerOptionsPropertyName; + } + + public IAbpDatePickerOptions GetDatePickerOptions(ModelExplorer explorer) + { + var properties = explorer.Container.Properties.Where(p => p.Metadata.PropertyName != null && p.Metadata.PropertyName.Equals(DatePickerOptionsPropertyName)).ToList(); + + while (properties.Count == 0) + { + explorer = explorer.Container; + if(explorer.Container == null) + { + return null; + } + + properties = explorer.Container.Properties.Where(p => p.Metadata.PropertyName != null && p.Metadata.PropertyName.Equals(DatePickerOptionsPropertyName)).ToList(); + } + + return properties.FirstOrDefault(p=> p.Model is IAbpDatePickerOptions)?.Model as IAbpDatePickerOptions; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs new file mode 100644 index 0000000000..04412ed4fc --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs @@ -0,0 +1,19 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[AttributeUsage(AttributeTargets.Property)] +public class DateRangePickerAttribute : Attribute +{ + public string PickerId { get; set; } + + public bool IsStart { get; set; } + + public bool IsEnd => !IsStart; + + public DateRangePickerAttribute(string pickerId, bool isStart = false) + { + PickerId = pickerId; + IsStart = isStart; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs new file mode 100644 index 0000000000..118c409da9 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public interface IAbpDatePickerOptions +{ + public string PickerId { get; set; } + + /// + /// Min date allowed + /// + DateTime? MinDate { get; set; } + + /// + /// Max date allowed + /// + DateTime? MaxDate { get; set; } + + /// + /// The maximum span between the selected start and end dates. Can have any property you can add to a moment object (i.e. days, months) + /// + object MaxSpan { get; set; } + + /// + /// Show year and month select boxes above calendars to jump to a specific month and year. + /// + bool? ShowDropdowns { get; set; } + + /// + /// The minimum year shown in the dropdowns when showDropdowns is set to true. + /// + int? MinYear { get; set; } + + /// + /// The maximum year shown in the dropdowns when showDropdowns is set to true. + /// + int? MaxYear { get; set; } + + /// + /// Show week numbers at the start of each week on the calendars. + /// + AbpDatePickerWeekNumbers WeekNumbers { get; set; } + + /// + /// Adds select boxes to choose times in addition to dates. + /// + bool? TimePicker { get; set; } + + /// + /// Increment of the minutes selection list for times (i.e. 30 to allow only selection of times ending in 0 or 30). + /// + int? TimePickerIncrement { get; set; } + + /// + /// Use 24-hour instead of 12-hour times, removing the AM/PM selection. + /// + bool? TimePicker24Hour { get; set; } + + /// + /// Show seconds in the timePicker. + /// + bool? TimePickerSeconds { get; set; } + + /// + /// Set predefined date ranges the user can select from. Each key is the label for the range, and its value an array with two dates representing the bounds of the range. + /// + List Ranges { get; set; } + + /// + /// Displays "Custom Range" at the end of the list of predefined ranges, when the ranges option is used. This option will be highlighted whenever the current date range selection does not match one of the predefined ranges. Clicking it will display the calendars to select a new range. + /// + bool? ShowCustomRangeLabel { get; set; } + + /// + /// Normally, if you use the ranges option to specify pre-defined date ranges, calendars for choosing a custom date range are not shown until the user clicks "Custom Range". When this option is set to true, the calendars for choosing a custom date range are always shown instead. + /// + bool? AlwaysShowCalendars { get; set; } + + /// + /// Whether the picker appears aligned to the left, to the right, or centered under the HTML element it's attached to. + /// + AbpDatePickerOpens Opens { get; set; } + + /// + /// Whether the picker appears below (default) or above the HTML element it's attached to. + /// + AbpDatePickerDrops Drops { get; set; } + + /// + /// CSS class names that will be added to both the today, clear, and apply buttons. + /// + [CanBeNull] + string ButtonClasses { get; set; } + + /// + /// CSS class names that will be added only to the today button. + /// + [CanBeNull] + string TodayButtonClasses { get; set; } + + /// + /// CSS class names that will be added only to the apply button. + /// + [CanBeNull] + string ApplyButtonClasses { get; set; } + + /// + /// CSS class names that will be added only to the clear button. + /// + [CanBeNull] + string ClearButtonClasses { get; set; } + + /// + /// Allows you to provide localized strings for buttons and labels, customize the date format, and change the first day of week for the calendars. + /// + [CanBeNull] + object Locale { get; set; } + + /// + /// Hide the apply button, and automatically apply a new date range as soon as two dates are clicked. + /// + bool? AutoApply { get; set; } + + /// + /// When enabled, the two calendars displayed will always be for two sequential months (i.e. January and February), and both will be advanced when clicking the left or right arrows above the calendars. When disabled, the two calendars can be individually advanced and display any month/year. + /// + bool? LinkedCalendars { get; set; } + + /// + /// Indicates whether the date range picker should automatically update the value of the input element it's attached to at initialization and when the selected dates change. + /// + bool? AutoUpdateInput { get; set; } + + /// + /// jQuery selector of the parent element that the date range picker will be added to, if not provided this will be 'body' + /// + [CanBeNull] + string ParentEl { get; set; } + + [CanBeNull] + string DateFormat { get; set; } + + bool OpenButton { get; set; } + + bool ClearButton { get; set; } + + bool SingleOpenAndClearButton { get; set; } + + bool? IsUtc { get; set; } + + bool? IsIso { get; set; } + + /// + /// Other non-mapped attributes will be automatically added to the input element as is. + /// + [CanBeNull] + object Options { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/fi.json b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/fi.json index 0547630188..70668c8dc9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/fi.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/fi.json @@ -4,7 +4,7 @@ "GivenTenantIsNotExist": "Annettua vuokralaista ei ole olemassa: {0}", "GivenTenantIsNotAvailable": "Annettua vuokralaista ei ole saatavilla: {0}", "Tenant": "Vuokralainen", - "Switch": "vaihtaa", + "Switch": "Vaihda", "Name": "Nimi", "SwitchTenantHint": "Jätä nimikenttä tyhjäksi, jos haluat vaihtaa isäntäpuolelle.", "SwitchTenant": "Vaihda vuokralainen", diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs index 3181d8e1a2..9e5754f393 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs @@ -7,6 +7,13 @@ public class FlagIconCssStyleContributor : BundleContributor { public override void ConfigureBundle(BundleConfigurationContext context) { - context.Files.AddIfNotContains("/libs/flag-icon-css/css/flag-icons.min.css"); + if (context.FileProvider.GetFileInfo("/libs/flag-icons/css/flag-icons.min.css").Exists) + { + context.Files.AddIfNotContains("/libs/flag-icons/css/flag-icons.min.css"); + } + else if (context.FileProvider.GetFileInfo("/libs/flag-icon-css/css/flag-icons.min.css").Exists) + { + context.Files.AddIfNotContains("/libs/flag-icon-css/css/flag-icons.min.css"); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/QRCode/QRCodeScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/QRCode/QRCodeScriptContributor.cs new file mode 100644 index 0000000000..ee164746a8 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/QRCode/QRCodeScriptContributor.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.QRCode; + +public class QRCodeScriptContributor : BundleContributor +{ + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files.AddIfNotContains("/libs/qrcode/qrcode.min.js"); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs index 4818158a97..b18767050b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs @@ -1,16 +1,28 @@ using System.Collections.Generic; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; using Volo.Abp.Modularity; +using Volo.Abp.Localization; namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2; [DependsOn(typeof(CoreScriptContributor))] public class Select2ScriptContributor : BundleContributor { + public const string PackageName = "select2"; public override void ConfigureBundle(BundleConfigurationContext context) { - //TODO: Add select2.full.min.js or localize! + //TODO: Add select2.full.min.js context.Files.AddIfNotContains("/libs/select2/js/select2.min.js"); } + public override void ConfigureDynamicResources(BundleConfigurationContext context) + { + var fileName = context.LazyServiceProvider.LazyGetRequiredService>().Value.GetCurrentUICultureLanguageFilesMap(PackageName); + var filePath = $"/libs/select2/js/i18n/{fileName}.js"; + if (context.FileProvider.GetFileInfo(filePath).Exists) + { + context.Files.AddIfNotContains(filePath); + } + } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj index cad3da097a..c576f7897d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj @@ -30,8 +30,7 @@ - - + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs index 70780d642c..e38995a685 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Controllers/ErrorController.cs @@ -14,12 +14,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers; public class ErrorController : AbpController { - private readonly IExceptionToErrorInfoConverter _errorInfoConverter; - private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder; - private readonly IStringLocalizer _localizer; - private readonly AbpErrorPageOptions _abpErrorPageOptions; - private readonly IExceptionNotifier _exceptionNotifier; - private readonly AbpExceptionHandlingOptions _exceptionHandlingOptions; + protected readonly IExceptionToErrorInfoConverter ErrorInfoConverter; + protected readonly IHttpExceptionStatusCodeFinder StatusCodeFinder; + protected readonly IStringLocalizer Localizer; + protected readonly AbpErrorPageOptions AbpErrorPageOptions; + protected readonly IExceptionNotifier ExceptionNotifier; + protected readonly AbpExceptionHandlingOptions ExceptionHandlingOptions; public ErrorController( IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, @@ -29,33 +29,33 @@ public class ErrorController : AbpController IExceptionNotifier exceptionNotifier, IOptions exceptionHandlingOptions) { - _errorInfoConverter = exceptionToErrorInfoConverter; - _statusCodeFinder = httpExceptionStatusCodeFinder; - _localizer = localizer; - _exceptionNotifier = exceptionNotifier; - _exceptionHandlingOptions = exceptionHandlingOptions.Value; - _abpErrorPageOptions = abpErrorPageOptions.Value; + ErrorInfoConverter = exceptionToErrorInfoConverter; + StatusCodeFinder = httpExceptionStatusCodeFinder; + Localizer = localizer; + ExceptionNotifier = exceptionNotifier; + ExceptionHandlingOptions = exceptionHandlingOptions.Value; + AbpErrorPageOptions = abpErrorPageOptions.Value; } - public async Task Index(int httpStatusCode) + public virtual async Task Index(int httpStatusCode) { var exHandlerFeature = HttpContext.Features.Get(); var exception = exHandlerFeature != null ? exHandlerFeature.Error - : new Exception(_localizer["UnhandledException"]); + : new Exception(Localizer["UnhandledException"]); - await _exceptionNotifier.NotifyAsync(new ExceptionNotificationContext(exception)); + await ExceptionNotifier.NotifyAsync(new ExceptionNotificationContext(exception)); - var errorInfo = _errorInfoConverter.Convert(exception, options => + var errorInfo = ErrorInfoConverter.Convert(exception, options => { - options.SendExceptionsDetailsToClients = _exceptionHandlingOptions.SendExceptionsDetailsToClients; - options.SendStackTraceToClients = _exceptionHandlingOptions.SendStackTraceToClients; + options.SendExceptionsDetailsToClients = ExceptionHandlingOptions.SendExceptionsDetailsToClients; + options.SendStackTraceToClients = ExceptionHandlingOptions.SendStackTraceToClients; }); if (httpStatusCode == 0) { - httpStatusCode = (int)_statusCodeFinder.GetStatusCode(HttpContext, exception); + httpStatusCode = (int)StatusCodeFinder.GetStatusCode(HttpContext, exception); } HttpContext.Response.StatusCode = httpStatusCode; @@ -69,9 +69,9 @@ public class ErrorController : AbpController }); } - private string GetErrorPageUrl(int statusCode) + protected virtual string GetErrorPageUrl(int statusCode) { - var page = _abpErrorPageOptions.ErrorViewUrls.GetOrDefault(statusCode.ToString()); + var page = AbpErrorPageOptions.ErrorViewUrls.GetOrDefault(statusCode.ToString()); if (string.IsNullOrWhiteSpace(page)) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 7f469e9179..945df5d0c6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -108,6 +108,7 @@ $select.select2({ ajax: { url: url, + delay: 250, dataType: "json", data: function (params) { let query = {}; @@ -135,6 +136,7 @@ width: '100%', dropdownParent: parentSelector ? $(parentSelector) : $('body'), allowClear: allowClear, + language: abp.localization.currentCulture.cultureName, placeholder: { id: '-1', text: placeholder @@ -191,6 +193,567 @@ }); } + abp.libs.bootstrapDateRangePicker = { + packageName: "bootstrap-daterangepicker", + + createDateRangePicker: function (options) { + options = options || {}; + options.singleDatePicker = false; + return this.createDatePicker(options); + }, + createSinglePicker: function (options) { + options = options || {}; + options.singleDatePicker = true; + return this.createDatePicker(options); + }, + createDatePicker: function (options) { + var $container = $('
') + var label = $('') + if (options.label) { + label.text(options.label) + } + + $container.append(label) + var $datePicker = options.singleDatePicker ? $('') : $(''); + $container.append($datePicker) + + var $inputGroup = $('
'); + var $dateInput = $(''); + + if (options.placeholder) { + $dateInput.attr('placeholder', options.placeholder) + } + + if (options.value) { + $dateInput.val(options.value) + } + + if (options.name) { + $dateInput.attr('name', options.name) + } + + if (options.id) { + $dateInput.attr('id', options.id) + } + + if (options.required) { + $dateInput.attr('required', true) + } + + if (options.disabled) { + $dateInput.attr('disabled', true) + } + + if (options.readonly) { + $dateInput.attr('readonly', true) + } + + if(options.placeholder) { + $dateInput.attr('placeholder', options.placeholder) + } + + if (options.size) { + switch (options.size) { + case 'Small': + $dateInput.addClass('form-control-sm') + break; + case 'Medium': + $dateInput.addClass('form-control-md') + break; + case 'Large': + $dateInput.addClass('form-control-lg') + break; + default: + break; + } + } + + $inputGroup.append($dateInput); + + if (options.openButton !== false) { + var $openButton = $(''); + $inputGroup.append($openButton); + if(options.disabled) { + $openButton.attr('disabled', 'disabled') + } + } + + if (options.clearButton !== false) { + var $clearButton = $(''); + $inputGroup.append($clearButton); + if(options.disabled) { + $clearButton.attr('disabled', 'disabled') + } + } + + $datePicker.append($inputGroup); + + if (options.startDateName) { + var $hiddenStartDateElement = $(''); + $datePicker.append($hiddenStartDateElement); + } + + if (options.endDateName) { + var $hiddenEndDateElement = $(''); + $datePicker.append($hiddenEndDateElement); + } + + if (options.dateName) { + var $hiddenDateElement = $(''); + $datePicker.append($hiddenDateElement); + } + + $datePicker.data('options', options); + abp.dom.initializers.initializeDateRangePickers($datePicker); + $container[0].datePicker = $datePicker[0]; + return $container; + } + }; + + + abp.dom.initializers.initializeDateRangePickers = function ($rootElement) { + function setOptions (options, $datePickerElement, singleDatePicker) { + + options.singleDatePicker = singleDatePicker; + + var defaultOptions = { + showDropdowns: true, + opens: "center", + drops: "down", + autoApply: true, + autoUpdateInput: false, + showTodayButton: true, + showClearButton: true, + minYear: parseInt(moment().subtract(100, 'year').locale('en').format('YYYY')), + maxYear: parseInt(moment().add(100, 'year').locale('en').format('YYYY')), + locale: { + direction: abp.localization.currentCulture.isRightToLeft ? 'rtl' : 'ltr', + todayLabel: abp.localization.localize('Today', 'AbpUi'), + clearLabel: abp.localization.localize('Clear', 'AbpUi'), + applyLabel: abp.localization.localize('Apply', 'AbpUi'), + }, + singleOpenAndClearButton: true + }; + var locale = defaultOptions.locale; + $.extend(options, defaultOptions); + $.extend(options, $datePickerElement.data()); + if ($.isEmptyObject(options.locale)) { + options.locale = locale; + } else { + locale = options.locale; + } + + $.extend(options, $datePickerElement.data("options")); + if ($.isEmptyObject(options.locale)) { + options.locale = locale; + } + + if (options.timePicker && options.timePicker24Hour === undefined) { + options.timePicker24Hour = moment.localeData().longDateFormat('LT').indexOf('A') < 1; + } + + if (options.dateFormat) { + options.locale = options.locale || {}; + options.locale.format = options.dateFormat; + } + + if (options.separator) { + options.locale = options.locale || {}; + options.locale.separator = options.separator; + } + + if (options.ranges) { + $.each(options.ranges, function (key, value) { + let start = value[0]; + let end; + if (value.length > 1) { + end = value[1]; + } else { + end = value[0]; + } + options.ranges[key] = [getMoment(start, options), getMoment(end, options)]; + }); + } + + if (typeof options.template !== 'string' && !(options.template instanceof $)) + options.template = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
'; + } + + function replaceOpenButton (hasDate,singleOpenAndClearButton, $openButton, $clearButton) { + var hiddenClass = 'd-none'; + + if (singleOpenAndClearButton) { + if (hasDate) { + $openButton.addClass(hiddenClass); + $clearButton.removeClass(hiddenClass); + $clearButton.insertAfter($openButton); + } else { + $openButton.removeClass(hiddenClass); + $clearButton.addClass(hiddenClass); + $openButton.insertAfter($clearButton); + } + } + } + + function getMoment (date, options, dateFormat) { + var isUtc = options.isUtc; + dateFormat = dateFormat || options.dateFormat; + if (!date) { + return isUtc ? moment.utc() : moment(); + } + + if (isUtc) { + return moment.utc(date, dateFormat); + } else { + return moment(date, dateFormat); + } + } + + function getStartDate(options, startDate){ + startDate = startDate ? startDate : options.startDate; + startDate = startDate ? getMoment(startDate, options) : null; + if (options.singleDatePicker && !startDate) { + startDate = options.date ? getMoment(options.date, options) : null; + } + + if(startDate && startDate.isValid()){ + return startDate; + } + + return null; + } + + function getEndDate(options, endDate){ + if (options.singleDatePicker) { + return null; + } + endDate = endDate ? endDate : options.endDate; + endDate = endDate ? getMoment(endDate, options) : null; + + if(endDate && endDate.isValid()){ + return endDate; + } + + return null; + } + + function getTodayButton(options, $input){ + if (options.showTodayButton) { + var $todayBtn = $(''); + if(options.todayButtonClasses){ + $todayBtn.addClass(options.todayButtonClasses); + }else{ + $todayBtn.addClass('btn-default'); + } + + $todayBtn.on('click', function () { + var today = getMoment(undefined, options); + $input.data('daterangepicker').setStartDate(today); + $input.data('daterangepicker').setEndDate(today); + $input.data('daterangepicker').clickApply(); + }); + + return $todayBtn; + } + + return null; + } + + function getClearButton(options, $input, $dateRangePicker){ + if (options.showClearButton) { + var $clearBtn = $(''); + if(options.clearButtonClasses){ + $clearBtn.addClass(options.clearButtonClasses); + }else{ + $clearBtn.addClass('btn-default'); + } + $clearBtn.on('click', function () { + $input.val('').trigger('change'); + $dateRangePicker.hide(); + }); + + return $clearBtn; + } + return null; + } + + function addExtraButtons(options, $dateRangePicker, $input) { + var extraButtons = [getTodayButton(options, $input), getClearButton(options, $input, $dateRangePicker)]; + + if ($dateRangePicker.container.hasClass('auto-apply')) { + var $div = $('
'); + $div.css('display', 'block'); + $.each(extraButtons, function (index, value) { + $div.prepend(value); + }); + + $div.insertAfter($dateRangePicker.container.find('.drp-buttons')); + } else { + $.each(extraButtons, function (index, value) { + $dateRangePicker.container.find('.drp-buttons').prepend(value); + }); + } + } + + function addOpenButtonClick($openButton, $dateRangePicker){ + if(!$openButton){ + return; + } + $dateRangePicker.outsideClick = function (e) { + var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button itself then call this.hide() + if ( + // ie modal dialog fix + e.type == "focusin" || + target.closest(this.element).length || + target.closest(this.container).length || + target.closest('.calendar-table').length || + target.closest($openButton).length + ) { + return; + } + + this.hide(); + this.element.trigger('outsideClick.daterangepicker', this); + }; + + $openButton.on('click', function () { + $dateRangePicker.toggle(); + }); + } + + function extendDateFormat (format,options) { + if (options.timePicker) { + if (options.timePicker24Hour) { + if (options.timePickerSeconds) { + format += " HH:mm:ss"; + } else { + format += " HH:mm"; + } + } else { + if (options.timePickerSeconds) { + format += ' ' + " hh:mm:ss A" + } else { + format += " hh:mm A"; + } + } + } + + return format; + } + + function fillInput($input, startDate, endDate, options) { + if (options.singleDatePicker) { + if (startDate) { + $input.val(startDate.format(options.dateFormat)); + } + } else { + if (startDate && endDate) { + $input.val(startDate.format(options.dateFormat) + options.separator + endDate.format(options.dateFormat)); + } + } + } + + $rootElement + .findWithSelf('abp-date-picker,abp-date-range-picker') + .each(function () { + var $this = $(this); + var $input = $this.find('.input-group input[type="text"]') + if ($input.data('daterangepicker')) { + return; + } + + var $openButton = $this.find('button[data-type="open"]') + var $clearButton = $this.find('button[data-type="clear"]') + var singleDatePicker = $this.is('abp-date-picker') + var options = {}; + + setOptions(options, $this, singleDatePicker); + + var isIso = options.isIso; + var dateFormat = options.dateFormat; + var separator = options.separator; + var defaultDateFormat = extendDateFormat("YYYY-MM-DD", options); + + var singleOpenAndClearButton = options.singleOpenAndClearButton && $clearButton.length > 0 && $openButton.length > 0; + + var startDate = getStartDate(options); + + var endDate = getEndDate(options); + if (startDate) { + options.startDate = startDate; + } + if (endDate) { + options.endDate = endDate; + } + + $input.daterangepicker(options); + + var $dateRangePicker = $input.data('daterangepicker'); + + addExtraButtons(options, $dateRangePicker, $input); + + addOpenButtonClick($openButton, $dateRangePicker); + + if (!dateFormat) { + dateFormat = extendDateFormat(moment.localeData().longDateFormat('L'), options); + options.dateFormat = dateFormat; + } + + if (!separator) { + separator = $dateRangePicker.locale.separator; + options.separator = separator; + } + + if(options.autoUpdateInput){ + fillInput($input, startDate, endDate, options); + } + + $input.on('apply.daterangepicker', function (ev, picker) { + if (singleDatePicker) { + $(this).val(picker.startDate.format(dateFormat)); + } else { + $(this).val(picker.startDate.format(dateFormat) + separator + picker.endDate.format(dateFormat)); + } + + $(this).trigger('change'); + }); + + $input.on('cancel.daterangepicker', function (ev, picker) { + $(this).val(''); + $(this).trigger('change'); + }); + + $input.on('show.daterangepicker', function (ev, picker) { + var momentStartDate = getMoment(startDate, options); + var momentEndDate = getMoment(endDate, options); + if (momentStartDate.isValid()) { + picker.setStartDate(momentStartDate); + } + if (momentEndDate.isValid()) { + picker.setEndDate(momentEndDate); + } + }); + + $clearButton.on('click', function () { + $input.val(''); + $input.trigger('change'); + }); + + var firstTrigger = true; + $input.on('change', function () { + if ($(this).val() !== '') { + replaceOpenButton(true, singleOpenAndClearButton, $openButton, $clearButton); + } else { + replaceOpenButton(false, singleOpenAndClearButton, $openButton, $clearButton); + } + var dates = $(this).val().split(separator); + if (dates.length === 2) { + startDate = formatDate(getStartDate(options, dates[0])); + endDate = formatDate(getEndDate(options, dates[1])); + } else { + if (dates[0]) { + startDate = formatDate(getStartDate(options, dates[0])); + } + else { + if(!firstTrigger){ + startDate = null; + } + } + + if(!firstTrigger){ + endDate = null; + } + } + + if (!startDate) { + replaceOpenButton(false, singleOpenAndClearButton, $openButton, $clearButton); + $(this).val(''); + } + + if (!singleDatePicker) { + var input1 = $this.find("input[data-start-date]") + input1.val(startDate); + var input2 = $this.find("input[data-end-date]") + input2.val(endDate); + } else { + var input = $this.find("input[data-date]") + input.val(startDate); + } + + if (singleDatePicker) { + $this.data('date', startDate); + $input.data('date', startDate); + } else { + $this.data('startDate', startDate); + $this.data('endDate', endDate); + $input.data('startDate', startDate); + $input.data('endDate', endDate); + } + + firstTrigger = false; + }); + + function formatDate(date) { + if (date) { + if (isIso) { + return date.locale('en').format(); + } + return date.locale('en').format(defaultDateFormat) + } + + return null; + } + + function getFormattedStartDate() { + if (startDate) { + return getMoment(startDate, options).format(dateFormat); + } + + return null; + } + + function getFormattedEndDate() { + if (endDate) { + return getMoment(endDate, options).format(dateFormat); + } + + return null; + } + + if (singleDatePicker) { + $this[0].getFormattedDate = getFormattedStartDate; + $input[0].getFormattedDate = getFormattedStartDate; + $dateRangePicker.getFormattedDate = getFormattedStartDate; + } else { + $dateRangePicker.getFormattedStartDate = getFormattedStartDate; + $dateRangePicker.getFormattedEndDate = getFormattedEndDate; + + $this[0].getFormattedStartDate = getFormattedStartDate; + $this[0].getFormattedEndDate = getFormattedEndDate; + + $input[0].getFormattedStartDate = getFormattedStartDate; + $input[0].getFormattedEndDate = getFormattedEndDate; + } + + $input.trigger('change'); + }); + } + abp.dom.onNodeAdded(function (args) { abp.dom.initializers.initializeToolTips(args.$el.findWithSelf('[data-toggle="tooltip"]')); abp.dom.initializers.initializePopovers(args.$el.findWithSelf('[data-toggle="popover"]')); @@ -215,6 +778,7 @@ abp.dom.initializers.initializePopovers($('[data-toggle="popover"]')); abp.dom.initializers.initializeTimeAgos($('.timeago')); abp.dom.initializers.initializeDatepickers($(document)); + abp.dom.initializers.initializeDateRangePickers($(document)); abp.dom.initializers.initializeForms($('form')); abp.dom.initializers.initializeAutocompleteSelects($('.auto-complete-select')); $('[data-auto-focus="true"]').first().findWithSelf('input,select').focus(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs index 54d766ec08..23b3d08602 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs @@ -39,7 +39,7 @@ public class AbpAspNetCoreMvcUiWidgetsModule : AbpModule { var widgetTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (WidgetAttribute.IsWidget(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index ec3690ca8e..0a12d0332a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -43,6 +43,7 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.UI; using Volo.Abp.UI.Navigation; +using Volo.Abp.Validation.Localization; namespace Volo.Abp.AspNetCore.Mvc; @@ -174,10 +175,17 @@ public class AbpAspNetCoreMvcModule : AbpModule context.Services.Replace(ServiceDescriptor.Singleton()); context.Services.AddSingleton(); - Configure(mvcOptions => - { - mvcOptions.AddAbp(context.Services); - }); + context.Services.AddOptions() + .Configure((mvcOptions, serviceProvider) => + { + mvcOptions.AddAbp(context.Services); + + // serviceProvider is root service provider. + var stringLocalizer = serviceProvider.GetRequiredService>(); + mvcOptions.ModelBindingMessageProvider.SetValueIsInvalidAccessor(_ => stringLocalizer["The value '{0}' is invalid."]); + mvcOptions.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(() => stringLocalizer["The field must be a number."]); + mvcOptions.ModelBindingMessageProvider.SetValueMustBeANumberAccessor(value => stringLocalizer["The field {0} must be a number.", value]); + }); Configure(options => { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs index 9bffcabb41..10f7e28811 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs @@ -8,16 +8,16 @@ namespace Volo.Abp.AspNetCore.Mvc.ApiExploring; [Route("api/abp/api-definition")] public class AbpApiDefinitionController : AbpController, IRemoteService { - private readonly IApiDescriptionModelProvider _modelProvider; + protected readonly IApiDescriptionModelProvider ModelProvider; public AbpApiDefinitionController(IApiDescriptionModelProvider modelProvider) { - _modelProvider = modelProvider; + ModelProvider = modelProvider; } [HttpGet] - public ApplicationApiDescriptionModel Get(ApplicationApiDescriptionModelRequestDto model) + public virtual ApplicationApiDescriptionModel Get(ApplicationApiDescriptionModelRequestDto model) { - return _modelProvider.CreateApiModel(model); + return ModelProvider.CreateApiModel(model); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs index 427aaf65a6..1836360f06 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs @@ -9,22 +9,22 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; [Route("api/abp/application-configuration")] public class AbpApplicationConfigurationController : AbpControllerBase, IAbpApplicationConfigurationAppService { - private readonly IAbpApplicationConfigurationAppService _applicationConfigurationAppService; - private readonly IAbpAntiForgeryManager _antiForgeryManager; + protected readonly IAbpApplicationConfigurationAppService ApplicationConfigurationAppService; + protected readonly IAbpAntiForgeryManager AntiForgeryManager; public AbpApplicationConfigurationController( IAbpApplicationConfigurationAppService applicationConfigurationAppService, IAbpAntiForgeryManager antiForgeryManager) { - _applicationConfigurationAppService = applicationConfigurationAppService; - _antiForgeryManager = antiForgeryManager; + ApplicationConfigurationAppService = applicationConfigurationAppService; + AntiForgeryManager = antiForgeryManager; } [HttpGet] public virtual async Task GetAsync( ApplicationConfigurationRequestOptions options) { - _antiForgeryManager.SetCookie(); - return await _applicationConfigurationAppService.GetAsync(options); + AntiForgeryManager.SetCookie(); + return await ApplicationConfigurationAppService.GetAsync(options); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs index 7fafee261c..de38e89104 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs @@ -17,11 +17,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; [ApiExplorerSettings(IgnoreApi = true)] public class AbpApplicationConfigurationScriptController : AbpController { - private readonly AbpApplicationConfigurationAppService _configurationAppService; - private readonly IJsonSerializer _jsonSerializer; - private readonly AbpAspNetCoreMvcOptions _options; - private readonly IJavascriptMinifier _javascriptMinifier; - private readonly IAbpAntiForgeryManager _antiForgeryManager; + protected readonly AbpApplicationConfigurationAppService ConfigurationAppService; + protected readonly IJsonSerializer JsonSerializer; + protected readonly AbpAspNetCoreMvcOptions Options; + protected readonly IJavascriptMinifier JavascriptMinifier; + protected readonly IAbpAntiForgeryManager AntiForgeryManager; public AbpApplicationConfigurationScriptController( AbpApplicationConfigurationAppService configurationAppService, @@ -30,42 +30,42 @@ public class AbpApplicationConfigurationScriptController : AbpController IJavascriptMinifier javascriptMinifier, IAbpAntiForgeryManager antiForgeryManager) { - _configurationAppService = configurationAppService; - _jsonSerializer = jsonSerializer; - _options = options.Value; - _javascriptMinifier = javascriptMinifier; - _antiForgeryManager = antiForgeryManager; + ConfigurationAppService = configurationAppService; + JsonSerializer = jsonSerializer; + Options = options.Value; + JavascriptMinifier = javascriptMinifier; + AntiForgeryManager = antiForgeryManager; } [HttpGet] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] - public async Task Get() + public virtual async Task Get() { var script = CreateAbpExtendScript( - await _configurationAppService.GetAsync( + await ConfigurationAppService.GetAsync( new ApplicationConfigurationRequestOptions { IncludeLocalizationResources = false } ) ); - _antiForgeryManager.SetCookie(); + AntiForgeryManager.SetCookie(); return Content( - _options.MinifyGeneratedScript == true - ? _javascriptMinifier.Minify(script) + Options.MinifyGeneratedScript == true + ? JavascriptMinifier.Minify(script) : script, MimeTypes.Application.Javascript ); } - private string CreateAbpExtendScript(ApplicationConfigurationDto config) + protected virtual string CreateAbpExtendScript(ApplicationConfigurationDto config) { var script = new StringBuilder(); script.AppendLine("(function(){"); script.AppendLine(); - script.AppendLine($"$.extend(true, abp, {_jsonSerializer.Serialize(config, indented: true)})"); + script.AppendLine($"$.extend(true, abp, {JsonSerializer.Serialize(config, indented: true)})"); script.AppendLine(); script.AppendLine("abp.event.trigger('abp.configurationInitialized');"); script.AppendLine(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index fdaf0e8ff1..05a3f52c72 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -24,6 +24,7 @@ public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency { if (!ShouldHandleException(context)) { + LogException(context, out _); return; } @@ -57,25 +58,7 @@ public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency { //TODO: Trigger an AbpExceptionHandled event or something like that. - var exceptionHandlingOptions = context.GetRequiredService>().Value; - var exceptionToErrorInfoConverter = context.GetRequiredService(); - var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options => - { - options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; - options.SendStackTraceToClients = exceptionHandlingOptions.SendStackTraceToClients; - }); - - var logLevel = context.Exception.GetLogLevel(); - - var remoteServiceErrorInfoBuilder = new StringBuilder(); - remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); - remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService().Serialize(remoteServiceErrorInfo, indented: true)); - - var logger = context.GetService>(NullLogger.Instance); - - logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); - - logger.LogException(context.Exception, logLevel); + LogException(context, out var remoteServiceErrorInfo); await context.GetRequiredService().NotifyAsync(new ExceptionNotificationContext(context.Exception)); @@ -96,4 +79,24 @@ public class AbpExceptionFilter : IAsyncExceptionFilter, ITransientDependency context.Exception = null; //Handled! } + + protected virtual void LogException(ExceptionContext context, out RemoteServiceErrorInfo remoteServiceErrorInfo) + { + var exceptionHandlingOptions = context.GetRequiredService>().Value; + var exceptionToErrorInfoConverter = context.GetRequiredService(); + remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, options => + { + options.SendExceptionsDetailsToClients = exceptionHandlingOptions.SendExceptionsDetailsToClients; + options.SendStackTraceToClients = exceptionHandlingOptions.SendStackTraceToClients; + }); + + var remoteServiceErrorInfoBuilder = new StringBuilder(); + remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); + remoteServiceErrorInfoBuilder.AppendLine(context.GetRequiredService().Serialize(remoteServiceErrorInfo, indented: true)); + + var logger = context.GetService>(NullLogger.Instance); + var logLevel = context.Exception.GetLogLevel(); + logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); + logger.LogException(context.Exception, logLevel); + } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs index d8da85f871..c3da22706e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs @@ -39,7 +39,7 @@ public class AbpApplicationLocalizationScriptController : AbpController [HttpGet] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] - public async Task GetAsync(ApplicationLocalizationRequestDto input) + public virtual async Task GetAsync(ApplicationLocalizationRequestDto input) { var script = CreateScript( await LocalizationAppService.GetAsync(input) @@ -53,7 +53,7 @@ public class AbpApplicationLocalizationScriptController : AbpController ); } - private string CreateScript(ApplicationLocalizationDto localizationDto) + protected virtual string CreateScript(ApplicationLocalizationDto localizationDto) { var script = new StringBuilder(); @@ -66,4 +66,4 @@ public class AbpApplicationLocalizationScriptController : AbpController return script.ToString(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs index c15d9b5bb8..ef7196fb0c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/AbpServiceProxyScriptController.cs @@ -14,30 +14,30 @@ namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting; [ApiExplorerSettings(IgnoreApi = true)] public class AbpServiceProxyScriptController : AbpController { - private readonly IProxyScriptManager _proxyScriptManager; - private readonly AbpAspNetCoreMvcOptions _options; - private readonly IJavascriptMinifier _javascriptMinifier; + protected readonly IProxyScriptManager ProxyScriptManager; + protected readonly AbpAspNetCoreMvcOptions Options; + protected readonly IJavascriptMinifier JavascriptMinifier; public AbpServiceProxyScriptController(IProxyScriptManager proxyScriptManager, IOptions options, IJavascriptMinifier javascriptMinifier) { - _proxyScriptManager = proxyScriptManager; - _options = options.Value; - _javascriptMinifier = javascriptMinifier; + ProxyScriptManager = proxyScriptManager; + Options = options.Value; + JavascriptMinifier = javascriptMinifier; } [HttpGet] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] - public ActionResult GetAll(ServiceProxyGenerationModel model) + public virtual ActionResult GetAll(ServiceProxyGenerationModel model) { model.Normalize(); - var script = _proxyScriptManager.GetScript(model.CreateOptions()); + var script = ProxyScriptManager.GetScript(model.CreateOptions()); return Content( - _options.MinifyGeneratedScript == true - ? _javascriptMinifier.Minify(script) + Options.MinifyGeneratedScript == true + ? JavascriptMinifier.Minify(script) : script, MimeTypes.Application.Javascript ); diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs index 903e60a16f..13400a7ff9 100644 --- a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs @@ -91,7 +91,7 @@ public class AbpAspNetCoreSignalRModule : AbpModule { var hubTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (IsHubClass(context) && !IsDisabledForAutoMap(context)) { diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs index b6527f10c8..7c6fdacc11 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs @@ -24,7 +24,7 @@ public class AbpAuditingModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(AuditingInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(AuditingInterceptorRegistrar.RegisterIfNeeded); } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs index 939814cba9..623733e8e5 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq.Expressions; +using System.Threading; using System.Threading.Tasks; namespace Volo.Abp.Auditing; @@ -76,7 +77,8 @@ public class AbpAuditingOptions IgnoredTypes = new List { typeof(Stream), - typeof(Expression) + typeof(Expression), + typeof(CancellationToken) }; EntityHistorySelectors = new EntityHistorySelectorList(); diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs index 9a1a4c52b4..cb244599c2 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs @@ -22,7 +22,7 @@ public class AbpAuthorizationModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(AuthorizationInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(AuthorizationInterceptorRegistrar.RegisterIfNeeded); AutoAddDefinitionProviders(context.Services); } @@ -64,7 +64,7 @@ public class AbpAuthorizationModule : AbpModule { var definitionProviders = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IPermissionDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/fi.json b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/fi.json index 16700a0891..bbd590ca45 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/fi.json +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/fi.json @@ -1,10 +1,10 @@ { "culture": "fi", "texts": { - "Volo.Authorization:010001": "Käyttöoikeuden varmistus epäonnistui! Annettua politiikkaa ei ole myönnetty.", + "Volo.Authorization:010001": "Käyttöoikeuden varmistus epäonnistui! Annettua käytäntöä ei ole myönnetty.", "Volo.Authorization:010002": "Käyttöoikeuden varmistus epäonnistui! Annettua käytäntöä ei ole myönnetty: {PolicyName}", - "Volo.Authorization:010003": "Käyttöoikeuden varmistus epäonnistui! Annettua käytäntöä ei ole myönnetty tietylle resurssille: {ResourceName}", - "Volo.Authorization:010004": "Käyttöoikeuden varmistus epäonnistui! Annettua vaatimusta ei ole annettu tietylle resurssille: {ResourceName}", - "Volo.Authorization:010005": "Käyttöoikeuden varmistus epäonnistui! Annettuja vaatimuksia ei ole annettu tietylle resurssille: {ResourceName}" + "Volo.Authorization:010003": "Käyttöoikeuden varmistus epäonnistui! Annettua käytäntöä ei ole myönnetty resurssille: {ResourceName}", + "Volo.Authorization:010004": "Käyttöoikeuden varmistus epäonnistui! Annettua vaatimusta ei ole annettu resurssille: {ResourceName}", + "Volo.Authorization:010005": "Käyttöoikeuden varmistus epäonnistui! Annettuja vaatimuksia ei ole annettu resurssille: {ResourceName}" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj index d8d2b83e5a..e03023a72a 100644 --- a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj +++ b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs index 99d4d9e4df..8d3dc6caf5 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs @@ -21,7 +21,7 @@ public class AbpBackgroundJobsAbstractionsModule : AbpModule { var jobTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IBackgroundJob<>)) || ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IAsyncBackgroundJob<>))) diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs index 4cf298f712..aa6cad070a 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AsyncBackgroundJob.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -6,7 +7,7 @@ namespace Volo.Abp.BackgroundJobs; public abstract class AsyncBackgroundJob : IAsyncBackgroundJob { - //TODO: Add UOW, Localization and other useful properties..? + //TODO: Add UOW, Localization, CancellationTokenProvider and other useful properties..? public ILogger> Logger { get; set; } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs index 57beeb77b5..b1770942fe 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJob.cs @@ -1,3 +1,4 @@ +using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -5,7 +6,7 @@ namespace Volo.Abp.BackgroundJobs; public abstract class BackgroundJob : IBackgroundJob { - //TODO: Add UOW, Localization and other useful properties..? + //TODO: Add UOW, Localization, CancellationTokenProvider and other useful properties..? public ILogger> Logger { get; set; } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs index 7a6f54fbd7..7798a8d9a6 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/BackgroundJobExecuter.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; using Volo.Abp.ExceptionHandling; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs; @@ -46,13 +47,19 @@ public class BackgroundJobExecuter : IBackgroundJobExecuter, ITransientDependenc { using(CurrentTenant.Change(GetJobArgsTenantId(context.JobArgs))) { - if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob.ExecuteAsync)) - { - await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs })); - } - else + var cancellationTokenProvider = + context.ServiceProvider.GetRequiredService(); + + using (cancellationTokenProvider.Use(context.CancellationToken)) { - jobExecuteMethod.Invoke(job, new[] { context.JobArgs }); + if (jobExecuteMethod.Name == nameof(IAsyncBackgroundJob.ExecuteAsync)) + { + await ((Task)jobExecuteMethod.Invoke(job, new[] { context.JobArgs })); + } + else + { + jobExecuteMethod.Invoke(job, new[] { context.JobArgs }); + } } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs index dc39b1bd0f..022067d3ed 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; namespace Volo.Abp.BackgroundJobs; diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs index 140db1e72a..8c8c17ca93 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.BackgroundJobs; +using System.Threading; + +namespace Volo.Abp.BackgroundJobs; /// /// Defines interface of a background job. diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs index a5de60d298..ae7e098070 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/JobExecutionContext.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs; @@ -11,10 +12,17 @@ public class JobExecutionContext : IServiceProviderAccessor public object JobArgs { get; } - public JobExecutionContext(IServiceProvider serviceProvider, Type jobType, object jobArgs) + public CancellationToken CancellationToken { get; } + + public JobExecutionContext( + IServiceProvider serviceProvider, + Type jobType, + object jobArgs, + CancellationToken cancellationToken = default) { ServiceProvider = serviceProvider; JobType = jobType; JobArgs = jobArgs; + CancellationToken = cancellationToken; } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs index 2583ada9fc..a94426adad 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs @@ -12,22 +12,22 @@ namespace Volo.Abp.BackgroundJobs.Hangfire; public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency { protected AbpBackgroundJobOptions Options { get; } - + public HangfireBackgroundJobManager(IOptions options) { Options = options.Value; } - + public virtual Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) { return Task.FromResult(delay.HasValue ? BackgroundJob.Schedule>( - adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)),args), + adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default), delay.Value ) : BackgroundJob.Enqueue>( - adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)) ,args) + adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)), args, default) )); } diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs index 7ba0cd7db4..58d2863618 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Hangfire; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -21,8 +22,8 @@ public class HangfireJobExecutionAdapter Options = options.Value; } - [Queue("{0}")] - public async Task ExecuteAsync(string queue, TArgs args) + [Queue("{0}")] + public async Task ExecuteAsync(string queue, TArgs args, CancellationToken cancellationToken = default) { if (!Options.IsJobExecutionEnabled) { @@ -38,7 +39,7 @@ public class HangfireJobExecutionAdapter using (var scope = ServiceScopeFactory.CreateScope()) { var jobType = Options.GetJob(typeof(TArgs)).JobType; - var context = new JobExecutionContext(scope.ServiceProvider, jobType, args); + var context = new JobExecutionContext(scope.ServiceProvider, jobType, args, cancellationToken: cancellationToken); await JobExecuter.ExecuteAsync(context); } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs b/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs index 3127cc5910..588e844153 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo/Abp/BackgroundJobs/Quartz/QuartzJobExecutionAdapter.cs @@ -40,7 +40,7 @@ public class QuartzJobExecutionAdapter : IJob { var args = JsonSerializer.Deserialize(context.JobDetail.JobDataMap.GetString(nameof(TArgs))); var jobType = Options.GetJob(typeof(TArgs)).JobType; - var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args); + var jobContext = new JobExecutionContext(scope.ServiceProvider, jobType, args, cancellationToken: context.CancellationToken); try { await JobExecuter.ExecuteAsync(jobContext); diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs index 8de0a5ff6e..4aeaf59885 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs @@ -68,7 +68,8 @@ public class BackgroundJobWorker : AsyncPeriodicBackgroundWorkerBase, IBackgroun var context = new JobExecutionContext( workerContext.ServiceProvider, jobConfiguration.JobType, - jobArgs); + jobArgs, + workerContext.CancellationToken); try { diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index 1e3cf13549..3bcc507e39 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -309,7 +309,7 @@ public abstract class AbpCrudPageBase< { CurrentSorting = e.Columns .Where(c => c.SortDirection != SortDirection.Default) - .Select(c => c.Field + (c.SortDirection == SortDirection.Descending ? " DESC" : "")) + .Select(c => c.SortField + (c.SortDirection == SortDirection.Descending ? " DESC" : "")) .JoinAsString(","); CurrentPage = e.Page; @@ -608,7 +608,8 @@ public abstract class AbpCrudPageBase< yield return new TableColumn { Title = lookupPropertyDefinition.GetLocalizedDisplayName(StringLocalizerFactory), - Data = $"ExtraProperties[{propertyInfo.Name}]" + Data = $"ExtraProperties[{propertyInfo.Name}]", + PropertyName = propertyInfo.Name }; } else @@ -616,7 +617,8 @@ public abstract class AbpCrudPageBase< var column = new TableColumn { Title = propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory), - Data = $"ExtraProperties[{propertyInfo.Name}]" + Data = $"ExtraProperties[{propertyInfo.Name}]", + PropertyName = propertyInfo.Name }; if (propertyInfo.IsDate() || propertyInfo.IsDateTime()) diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor index c674ec3612..88a0a1df4a 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/AbpExtensibleDataGrid.razor @@ -34,15 +34,16 @@ { if (column.Actions.Any()) { + var entityActionType = column.Actions.Count == 1 ? ActionType.Button : ActionType.Dropdown; - + @foreach (var action in column.Actions) { if (action.ConfirmationMessage != null) { + @{ var entity = context as IHasExtraProperties; diff --git a/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj b/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj index 5b52e2b9e4..83a3253b07 100644 --- a/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj +++ b/framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs index cc198e877b..ec2074434a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs @@ -58,7 +58,7 @@ public class AuthService : IAuthService, ITransientDependency { if (!response.IsSuccessStatusCode) { - Logger.LogError("Remote server returns '{response.StatusCode}'"); + Logger.LogError($"Remote server returns '{response.StatusCode}'"); return null; } @@ -127,6 +127,26 @@ public class AuthService : IAuthService, ITransientDependency } } + public async Task CheckMultipleOrganizationsAsync(string username) + { + var url = $"{CliUrls.WwwAbpIo}api/license/check-multiple-organizations?username={username}"; + + var client = CliHttpClientFactory.CreateClient(); + + using (var response = await client.GetHttpResponseMessageWithRetryAsync(url, CancellationTokenProvider.Token, Logger)) + { + if (!response.IsSuccessStatusCode) + { + throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); + } + + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(responseContent); + } + } + private async Task LogoutAsync(string accessToken) { try diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs index ad2916ca0b..f91fd0dc00 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs @@ -9,4 +9,6 @@ public interface IAuthService Task LoginAsync(string userName, string password, string organizationName = null); Task LogoutAsync(); + + Task CheckMultipleOrganizationsAsync(string username); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs index aacb26e5f4..3b14c96330 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs @@ -1,8 +1,11 @@ - +using System; + namespace Volo.Abp.Cli.Auth; public class LoginInfo { + public Guid? Id { get; set; } + public string Name { get; set; } public string Surname { get; set; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs index a3b6d4a411..0d5b3b31e5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs @@ -2,13 +2,11 @@ using Microsoft.Extensions.Logging.Abstractions; using System; using System.Text; -using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Auth; -using Volo.Abp.Cli.Http; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; @@ -26,17 +24,13 @@ public class LoginCommand : IConsoleCommand, ITransientDependency public ICancellationTokenProvider CancellationTokenProvider { get; } public IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } - private readonly CliHttpClientFactory _cliHttpClientFactory; - public LoginCommand(AuthService authService, ICancellationTokenProvider cancellationTokenProvider, - IRemoteServiceExceptionHandler remoteServiceExceptionHandler, - CliHttpClientFactory cliHttpClientFactory) + IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { AuthService = authService; CancellationTokenProvider = cancellationTokenProvider; RemoteServiceExceptionHandler = remoteServiceExceptionHandler; - _cliHttpClientFactory = cliHttpClientFactory; Logger = NullLogger.Instance; } @@ -111,7 +105,7 @@ public class LoginCommand : IConsoleCommand, ITransientDependency private async Task HasMultipleOrganizationAndThisNotSpecified(CommandLineArgs commandLineArgs, string organization) { if (string.IsNullOrWhiteSpace(organization) && - await CheckMultipleOrganizationsAsync(commandLineArgs.Target)) + await AuthService.CheckMultipleOrganizationsAsync(commandLineArgs.Target)) { Logger.LogError($"You have multiple organizations, please specify your organization with `--organization` parameter."); return true; @@ -168,26 +162,6 @@ public class LoginCommand : IConsoleCommand, ITransientDependency return false; } - private async Task CheckMultipleOrganizationsAsync(string username) - { - var url = $"{CliUrls.WwwAbpIo}api/license/check-multiple-organizations?username={username}"; - - var client = _cliHttpClientFactory.CreateClient(); - - using (var response = await client.GetHttpResponseMessageWithRetryAsync(url, CancellationTokenProvider.Token, Logger)) - { - if (!response.IsSuccessStatusCode) - { - throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); - } - - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); - - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(responseContent); - } - } - public string GetUsageInfo() { var sb = new StringBuilder(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs index 9d17bf4c4f..d8f007dc2c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System.Text; using System.Threading.Tasks; @@ -41,7 +40,7 @@ public class LoginInfoCommand : IConsoleCommand, ITransientDependency var sb = new StringBuilder(); sb.AppendLine(""); - sb.AppendLine($"Login info:"); + sb.AppendLine("Login info:"); sb.AppendLine($"Name: {loginInfo.Name}"); sb.AppendLine($"Surname: {loginInfo.Surname}"); sb.AppendLine($"Username: {loginInfo.Username}"); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SuiteAppSettingsService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SuiteAppSettingsService.cs new file mode 100644 index 0000000000..d274234ded --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SuiteAppSettingsService.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using Volo.Abp.Cli.Utils; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands.Services; + +public class SuiteAppSettingsService : ITransientDependency +{ + private const int DefaultPort = 3000; + + public CmdHelper CmdHelper { get; } + + public SuiteAppSettingsService(CmdHelper cmdHelper) + { + CmdHelper = cmdHelper; + } + + public async Task GetSuitePortAsync() + { + return await GetSuitePortAsync(GetCurrentSuiteVersion()); + } + + public async Task GetSuitePortAsync(string version) + { + var filePath = GetFilePathOrNull(version); + + if (filePath == null) + { + return DefaultPort; + } + + var content = File.ReadAllText(filePath); + + var contentAsJson = JObject.Parse(content); + + var url = contentAsJson["AbpSuite"]?["ApplicationUrl"]?.ToString(); + + if (url == null) + { + return DefaultPort; + } + + return Convert.ToInt32(url.Split(":").Last()); + } + + private string GetFilePathOrNull(string version) + { + if (version == null) + { + return null; + } + + var path = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".dotnet", + "tools", + ".store", + "volo.abp.suite", + version, + "volo.abp.suite", + version, + "tools", + "net7.0", + "any", + "appsettings.json" + ); + + if (!File.Exists(path)) + { + return null; + } + + return path; + } + + private string GetCurrentSuiteVersion() + { + var dotnetToolList = CmdHelper.RunCmdAndGetOutput("dotnet tool list -g", out int exitCode); + + var suiteLine = dotnetToolList.Split(Environment.NewLine) + .FirstOrDefault(l => l.ToLower().StartsWith("volo.abp.suite ")); + + if (string.IsNullOrEmpty(suiteLine)) + { + return null; + } + + return suiteLine.Split(" ", StringSplitOptions.RemoveEmptyEntries)[1]; + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs index 83c21d4773..b35efb6f36 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs @@ -35,23 +35,26 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency private readonly PackageVersionCheckerService _packageVersionCheckerService; private readonly AuthService _authService; private readonly CliHttpClientFactory _cliHttpClientFactory; + private readonly SuiteAppSettingsService _suiteAppSettingsService; private const string SuitePackageName = "Volo.Abp.Suite"; public ILogger Logger { get; set; } - private const string AbpSuiteHost = "http://localhost:3000"; + private int _abpSuitePort = 3000; public SuiteCommand( AbpNuGetIndexUrlService nuGetIndexUrlService, PackageVersionCheckerService packageVersionCheckerService, ICmdHelper cmdHelper, AuthService authService, - CliHttpClientFactory cliHttpClientFactory) + CliHttpClientFactory cliHttpClientFactory, + SuiteAppSettingsService suiteAppSettingsService) { CmdHelper = cmdHelper; _nuGetIndexUrlService = nuGetIndexUrlService; _packageVersionCheckerService = packageVersionCheckerService; _authService = authService; _cliHttpClientFactory = cliHttpClientFactory; + _suiteAppSettingsService = suiteAppSettingsService; Logger = NullLogger.Instance; } @@ -72,17 +75,20 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency commandLineArgs.Options.ContainsKey(Options.Preview.Long); var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); + var currentSuiteVersionAsString = GetCurrentSuiteVersion(); switch (operationType) { case "": case null: - await InstallSuiteIfNotInstalledAsync(); + await InstallSuiteIfNotInstalledAsync(currentSuiteVersionAsString); + _abpSuitePort = await _suiteAppSettingsService.GetSuitePortAsync(currentSuiteVersionAsString); RunSuite(); break; case "generate": - await InstallSuiteIfNotInstalledAsync(); + await InstallSuiteIfNotInstalledAsync(currentSuiteVersionAsString); + _abpSuitePort = await _suiteAppSettingsService.GetSuitePortAsync(currentSuiteVersionAsString); var suiteProcess = StartSuite(); System.Threading.Thread.Sleep(500); //wait for initialization of the app await GenerateCrudPageAsync(commandLineArgs); @@ -130,7 +136,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } var IsSolutionBuiltResponse = await client.GetAsync( - $"{AbpSuiteHost}/api/abpSuite/solutions/{solutionId.ToString()}/is-built" + $"http://localhost:{_abpSuitePort}/api/abpSuite/solutions/{solutionId.ToString()}/is-built" ); var IsSolutionBuilt = Convert.ToBoolean(await IsSolutionBuiltResponse.Content.ReadAsStringAsync()); @@ -148,7 +154,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency ); var responseMessage = await client.PostAsync( - $"{AbpSuiteHost}/api/abpSuite/crudPageGenerator/{solutionId.ToString()}/save-and-generate-entity", + $"http://localhost:{_abpSuitePort}/api/abpSuite/crudPageGenerator/{solutionId.ToString()}/save-and-generate-entity", entityContent ); @@ -178,7 +184,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } var responseMessage = await client.GetHttpResponseMessageWithRetryAsync( - "http://localhost:3000/api/abpSuite/solutions", + $"http://localhost:{_abpSuitePort}/api/abpSuite/solutions", _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)), Logger, timeIntervals.ToArray()); @@ -216,7 +222,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency ); var responseMessage = await client.PostAsync( - "http://localhost:3000/api/abpSuite/addSolution", + $"http://localhost:{_abpSuitePort}/api/abpSuite/addSolution", entityContent, _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)) ); @@ -234,11 +240,9 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } } - private async Task InstallSuiteIfNotInstalledAsync() + private async Task InstallSuiteIfNotInstalledAsync(string currentSuiteVersion) { - var currentSuiteVersionAsString = GetCurrentSuiteVersion(); - - if (string.IsNullOrEmpty(currentSuiteVersionAsString)) + if (string.IsNullOrEmpty(currentSuiteVersion)) { await InstallSuiteAsync(); } @@ -430,6 +434,19 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency Logger.LogWarning("Couldn't check ABP Suite installed status: " + ex.Message); } + if (IsSuiteAlreadyRunning()) + { + Logger.LogInformation("Opening suite..."); + CmdHelper.Open($"http://localhost:{_abpSuitePort}"); + return; + } + + if (IsPortAlreadyInUse()) + { + Logger.LogError($"Port \"{_abpSuitePort}\" is already in use."); + return; + } + CmdHelper.RunCmd("abp-suite"); } @@ -453,23 +470,32 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency return null; } + if (IsPortAlreadyInUse()) + { + Logger.LogError($"Port \"{_abpSuitePort}\" is already in use."); + return null; + } + return CmdHelper.RunCmdAndGetProcess("abp-suite --no-browser"); } private bool IsSuiteAlreadyRunning() + { + return GetProcessesRelatedWithSuite().Any(); + } + + private bool IsPortAlreadyInUse() { var ipGP = IPGlobalProperties.GetIPGlobalProperties(); var endpoints = ipGP.GetActiveTcpListeners(); - return endpoints.Any(e => e.Port == 3000); + return endpoints.Any(e => e.Port == _abpSuitePort); } private void KillSuite() { try { - var suiteProcesses = (from p in Process.GetProcesses() - where p.ProcessName.ToLower().Contains("abp-suite") - select p); + var suiteProcesses = GetProcessesRelatedWithSuite(); foreach (var suiteProcess in suiteProcesses) { @@ -483,6 +509,13 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } } + private IEnumerable GetProcessesRelatedWithSuite() + { + return (from p in Process.GetProcesses() + where p.ProcessName.ToLower().Contains("abp-suite") + select p); + } + public string GetUsageInfo() { var sb = new StringBuilder(); diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs index 2947526fa5..286cc05210 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs @@ -5,9 +5,9 @@ namespace Microsoft.Extensions.DependencyInjection; public static class ServiceCollectionRegistrationActionExtensions { - // OnRegistred + // OnRegistered - public static void OnRegistred(this IServiceCollection services, Action registrationAction) + public static void OnRegistered(this IServiceCollection services, Action registrationAction) { GetOrCreateRegistrationActionList(services).Add(registrationAction); } diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index c7e1bef3b2..57f2c59d57 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -209,7 +209,22 @@ public static class AbpStringExtensions return str; } - return str.Substring(0, pos) + replace + str.Substring(pos + search.Length); + var searchLength = search.Length; + var replaceLength = replace.Length; + var newLength = str.Length - searchLength + replaceLength; + + Span buffer = newLength <= 1024 ? stackalloc char[newLength] : new char[newLength]; + + // Copy the part of the original string before the search term + str.AsSpan(0, pos).CopyTo(buffer); + + // Copy the replacement text + replace.AsSpan().CopyTo(buffer.Slice(pos)); + + // Copy the remainder of the original string + str.AsSpan(pos + searchLength).CopyTo(buffer.Slice(pos + replaceLength)); + + return buffer.ToString(); } /// diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs index 931dc8c07e..b573d7d958 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs @@ -42,7 +42,7 @@ public class AbpDataModule : AbpModule { var contributors = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IDataSeedContributor).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs index 03b192c851..f7a4f27e5f 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs @@ -123,10 +123,17 @@ public static class EntityHelper return typeof(IEntity).IsAssignableFrom(type); } + public static Func IsValueObjectPredicate = type => typeof(ValueObject).IsAssignableFrom(type); + public static bool IsValueObject([NotNull] Type type) { Check.NotNull(type, nameof(type)); - return typeof(ValueObject).IsAssignableFrom(type); + return IsValueObjectPredicate(type); + } + + public static bool IsValueObject(object obj) + { + return obj != null && IsValueObject(obj.GetType()); } public static void CheckEntity([NotNull] Type type) diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj index 19c1b4f869..85b832eefb 100644 --- a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo.Abp.DistributedLocking.Abstractions.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs index fdec4f1d3f..490f024d36 100644 --- a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLock.cs @@ -1,21 +1,27 @@ using System; -using System.Collections.Concurrent; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using AsyncKeyedLock; using Volo.Abp.DependencyInjection; namespace Volo.Abp.DistributedLocking; public class LocalAbpDistributedLock : IAbpDistributedLock, ISingletonDependency { - private readonly ConcurrentDictionary _localSyncObjects = new(); + private readonly AsyncKeyedLocker _localSyncObjects = new(o => + { + o.PoolSize = 20; + o.PoolInitialFill = 1; + }); protected IDistributedLockKeyNormalizer DistributedLockKeyNormalizer { get; } public LocalAbpDistributedLock(IDistributedLockKeyNormalizer distributedLockKeyNormalizer) { DistributedLockKeyNormalizer = distributedLockKeyNormalizer; } - + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public async Task TryAcquireAsync( string name, TimeSpan timeout = default, @@ -23,14 +29,13 @@ public class LocalAbpDistributedLock : IAbpDistributedLock, ISingletonDependency { Check.NotNullOrWhiteSpace(name, nameof(name)); var key = DistributedLockKeyNormalizer.NormalizeKey(name); - - var semaphore = _localSyncObjects.GetOrAdd(key, _ => new SemaphoreSlim(1, 1)); - if (!await semaphore.WaitAsync(timeout, cancellationToken)) + var timeoutReleaser = await _localSyncObjects.LockAsync(key, timeout, cancellationToken); + if (!timeoutReleaser.EnteredSemaphore) { + timeoutReleaser.Dispose(); return null; } - - return new LocalAbpDistributedLockHandle(semaphore); + return new LocalAbpDistributedLockHandle(timeoutReleaser); } } diff --git a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs index f4f6d640bc..d08451657e 100644 --- a/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs +++ b/framework/src/Volo.Abp.DistributedLocking.Abstractions/Volo/Abp/DistributedLocking/LocalAbpDistributedLockHandle.cs @@ -1,20 +1,20 @@ -using System.Threading; +using System; using System.Threading.Tasks; namespace Volo.Abp.DistributedLocking; public class LocalAbpDistributedLockHandle : IAbpDistributedLockHandle { - private readonly SemaphoreSlim _semaphore; + private readonly IDisposable _disposable; - public LocalAbpDistributedLockHandle(SemaphoreSlim semaphore) + public LocalAbpDistributedLockHandle(IDisposable disposable) { - _semaphore = semaphore; + _disposable = disposable; } public ValueTask DisposeAsync() { - _semaphore.Release(); + _disposable.Dispose(); return default; } } diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs index 881a6437d9..9a70469df8 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/BackgroundEmailSendingJob.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.BackgroundJobs; using Volo.Abp.DependencyInjection; diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/fi.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/fi.json index ac197f1634..5560d3a598 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/fi.json +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/fi.json @@ -4,7 +4,7 @@ "DisplayName:Abp.Mailing.DefaultFromAddress": "Oletus osoitteesta", "DisplayName:Abp.Mailing.DefaultFromDisplayName": "Oletus näyttönimestä", "DisplayName:Abp.Mailing.Smtp.Host": "Isäntä", - "DisplayName:Abp.Mailing.Smtp.Port": "Satama", + "DisplayName:Abp.Mailing.Smtp.Port": "Portti", "DisplayName:Abp.Mailing.Smtp.UserName": "Käyttäjänimi", "DisplayName:Abp.Mailing.Smtp.Password": "Salasana", "DisplayName:Abp.Mailing.Smtp.Domain": "Verkkotunnus", diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index e9e1f2c618..96d7b4111e 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -4,11 +4,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Linq.Dynamic.Core; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Storage; using Volo.Abp.Domain.Entities; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.DependencyInjection; @@ -73,6 +75,16 @@ public class EfCoreRepository : RepositoryBase, IE { return (await GetDbContextAsync()).Set(); } + + protected async Task GetDbConnectionAsync() + { + return (await GetDbContextAsync()).Database.GetDbConnection(); + } + + protected async Task GetDbTransactionAsync() + { + return (await GetDbContextAsync()).Database.CurrentTransaction?.GetDbTransaction(); + } protected virtual AbpEntityOptions AbpEntityOptions => _entityOptionsLazy.Value; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs index c887175655..801e772e26 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs @@ -93,7 +93,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency } var entityId = GetEntityId(entity); - if (entityId == null && changeType != EntityChangeType.Created && !(entity is ValueObject)) + if (entityId == null && changeType != EntityChangeType.Created && !EntityHelper.IsValueObject(entity)) { return null; } @@ -151,7 +151,7 @@ public class EntityHistoryHelper : IEntityHistoryHelper, ITransientDependency return keys.JoinAsString(","); } - if (entityAsObj is ValueObject) + if (EntityHelper.IsValueObject(entityAsObj)) { return null; } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs index fe3d9f3032..21e663e5e1 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs @@ -47,7 +47,7 @@ public class AbpEventBusModule : AbpModule var localHandlers = new List(); var distributedHandlers = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(ILocalEventHandler<>))) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs index 7411c61fdb..cde88956b5 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs @@ -22,7 +22,7 @@ public class AbpFeaturesModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(FeatureInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(FeatureInterceptorRegistrar.RegisterIfNeeded); AutoAddDefinitionProviders(context.Services); } @@ -57,7 +57,7 @@ public class AbpFeaturesModule : AbpModule { var definitionProviders = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IFeatureDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs index 14cd0d405b..1a1e2ece3b 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs @@ -124,7 +124,7 @@ public class FeatureDefinition : ICanCreateChildFeature } /// - /// Sets a property in the dictionary. + /// Adds one or more providers to the list. /// This is a shortcut for nested calls on this object. /// public virtual FeatureDefinition WithProviders(params string[] providers) diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs index 8541d04306..3c8cd5708a 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs @@ -17,7 +17,7 @@ public class AbpGlobalFeaturesModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(GlobalFeatureInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(GlobalFeatureInterceptorRegistrar.RegisterIfNeeded); } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs b/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs index d44a294799..49080939c2 100644 --- a/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs +++ b/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/Conventions/AbpHttpClientProxyServiceConvention.cs @@ -6,6 +6,7 @@ using System.Reflection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ApplicationModels; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Volo.Abp.Application.Services; @@ -13,6 +14,7 @@ using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.Http.Client.StaticProxying; using Volo.Abp.Http.Modeling; using Volo.Abp.Reflection; @@ -24,14 +26,17 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention protected readonly IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder; protected readonly List ControllerWithAttributeRoute; protected readonly List ActionWithAttributeRoute; + protected readonly AbpHttpClientStaticProxyingOptions StaticProxyingOptions; public AbpHttpClientProxyServiceConvention( IOptions options, IConventionalRouteBuilder conventionalRouteBuilder, - IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder) + IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder, + IOptions staticProxyingOptions) : base(options, conventionalRouteBuilder) { ClientProxyApiDescriptionFinder = clientProxyApiDescriptionFinder; + StaticProxyingOptions = staticProxyingOptions.Value; ControllerWithAttributeRoute = new List(); ActionWithAttributeRoute = new List(); } @@ -73,6 +78,27 @@ public class AbpHttpClientProxyServiceConvention : AbpServiceConvention } } + protected override void ConfigureParameters(ControllerModel controller) + { + foreach (var action in controller.Actions) + { + foreach (var prm in action.Parameters) + { + if (prm.BindingInfo != null) + { + continue; + } + + if (StaticProxyingOptions.BindingFromQueryTypes.Contains(prm.ParameterInfo.ParameterType)) + { + prm.BindingInfo = BindingInfo.GetBindingInfo(new[] { new FromQueryAttribute() }); + } + } + } + + base.ConfigureParameters(controller); + } + protected virtual bool ShouldBeRemove(ApplicationModel application, ControllerModel controllerModel) { return application.Controllers diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/StaticProxying/AbpHttpClientStaticProxyingOptions.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/StaticProxying/AbpHttpClientStaticProxyingOptions.cs new file mode 100644 index 0000000000..f7c74303a9 --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/StaticProxying/AbpHttpClientStaticProxyingOptions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.Http.Client.StaticProxying; + +public class AbpHttpClientStaticProxyingOptions +{ + public List BindingFromQueryTypes { get; } + + public AbpHttpClientStaticProxyingOptions() + { + BindingFromQueryTypes = new List(); + } +} diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs index 4dda1f5ca5..ab65909cf9 100644 --- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs @@ -83,7 +83,7 @@ public class AbpNewtonsoftJsonSerializer : IJsonSerializer, ITransientDependency if (!camelCase) { - // Default contract resolver is AbpCamelCasePropertyNamesContractResolver} + //Default contract resolver is AbpCamelCasePropertyNamesContractResolver} settings.ContractResolver = new AbpDefaultContractResolver(RootServiceProvider.GetRequiredService()); } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index de89dfa506..6c009894e3 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -610,7 +610,7 @@ public class MongoDbRepository return Task.CompletedTask; } - private void TriggerEntityCreateEvents(TEntity entity) + protected virtual void TriggerEntityCreateEvents(TEntity entity) { EntityChangeEventHelper.PublishEntityCreatedEvent(entity); } diff --git a/framework/src/Volo.Abp.MultiLingualObjects/Volo.Abp.MultiLingualObjects.csproj b/framework/src/Volo.Abp.MultiLingualObjects/Volo.Abp.MultiLingualObjects.csproj index da83bc80f4..77da44eb47 100644 --- a/framework/src/Volo.Abp.MultiLingualObjects/Volo.Abp.MultiLingualObjects.csproj +++ b/framework/src/Volo.Abp.MultiLingualObjects/Volo.Abp.MultiLingualObjects.csproj @@ -1,20 +1,21 @@ - - - - - - - netstandard2.0 - Volo.Abp.MultiLingualObject - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - false - false - false - - - - - - - - + + + + + + + netstandard2.0 + Volo.Abp.MultiLingualObject + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + enable + + + + + + + diff --git a/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/IMultiLingualObjectManager.cs b/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/IMultiLingualObjectManager.cs index 904f3abd32..4edbd984bd 100644 --- a/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/IMultiLingualObjectManager.cs +++ b/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/IMultiLingualObjectManager.cs @@ -5,16 +5,30 @@ namespace Volo.Abp.MultiLingualObjects; public interface IMultiLingualObjectManager { - Task GetTranslationAsync( + Task GetTranslationAsync( TMultiLingual multiLingual, - string culture = null, + string? culture = null, bool fallbackToParentCultures = true) where TMultiLingual : IMultiLingualObject where TTranslation : class, IObjectTranslation; - Task GetTranslationAsync( - ICollection translations, - string culture = null, + Task GetTranslationAsync( + IEnumerable translations, + string? culture = null, bool fallbackToParentCultures = true) + where TTranslation : class, IObjectTranslation; + + + Task> GetBulkTranslationsAsync( + IEnumerable> translationsCombined, + string? culture = null, + bool fallbackToParentCultures = true) + where TTranslation : class, IObjectTranslation; + + Task> GetBulkTranslationsAsync( + IEnumerable multiLinguals, + string? culture = null, + bool fallbackToParentCultures = true) + where TMultiLingual : IMultiLingualObject where TTranslation : class, IObjectTranslation; } diff --git a/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager.cs b/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager.cs index afb4509917..908431e997 100644 --- a/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager.cs +++ b/framework/src/Volo.Abp.MultiLingualObjects/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager.cs @@ -19,16 +19,16 @@ public class MultiLingualObjectManager : IMultiLingualObjectManager, ITransientD { SettingProvider = settingProvider; } - public virtual async Task GetTranslationAsync( - ICollection translations, - string culture, + public virtual async Task GetTranslationAsync( + IEnumerable translations, + string? culture, bool fallbackToParentCultures) where TTranslation : class, IObjectTranslation { culture ??= CultureInfo.CurrentUICulture.Name; - if (translations.IsNullOrEmpty()) + if (translations == null || !translations.Any()) { return null; } @@ -65,9 +65,9 @@ public class MultiLingualObjectManager : IMultiLingualObjectManager, ITransientD return translation; } - public virtual Task GetTranslationAsync( + public virtual Task GetTranslationAsync( TMultiLingual multiLingual, - string culture = null, + string? culture = null, bool fallbackToParentCultures = true) where TMultiLingual : IMultiLingualObject where TTranslation : class, IObjectTranslation @@ -75,13 +75,13 @@ public class MultiLingualObjectManager : IMultiLingualObjectManager, ITransientD return GetTranslationAsync(multiLingual.Translations, culture: culture, fallbackToParentCultures: fallbackToParentCultures); } - protected virtual TTranslation GetTranslationBasedOnCulturalRecursive( - CultureInfo culture, ICollection translations, int currentDepth) + protected virtual TTranslation? GetTranslationBasedOnCulturalRecursive( + CultureInfo culture, IEnumerable translations, int currentDepth) where TTranslation : class, IObjectTranslation { if (culture == null || culture.Name.IsNullOrWhiteSpace() || - translations.IsNullOrEmpty() || + translations == null || !translations.Any() || currentDepth > MaxCultureFallbackDepth) { return null; @@ -89,5 +89,108 @@ public class MultiLingualObjectManager : IMultiLingualObjectManager, ITransientD var translation = translations.FirstOrDefault(pt => pt.Language.Equals(culture.Name, StringComparison.OrdinalIgnoreCase)); return translation ?? GetTranslationBasedOnCulturalRecursive(culture.Parent, translations, currentDepth + 1); - } + } + + public virtual async Task> GetBulkTranslationsAsync(IEnumerable> translationsCombined, string? culture, bool fallbackToParentCultures) + where TTranslation : class, IObjectTranslation + { + culture ??= CultureInfo.CurrentUICulture.Name; + + if (translationsCombined == null || !translationsCombined.Any()) + { + return new(); + } + + var someHaveNoTranslations = false; + var res = new List(); + foreach (var translations in translationsCombined) + { + if (!translations.Any()) + { + //if the src has no translations, don't try to find a translation + res.Add(null); + continue; + } + var translation = translations.FirstOrDefault(pt => pt.Language == culture); + if (translation != null) + { + res.Add(translation); + } + else + { + if (fallbackToParentCultures) + { + translation = GetTranslationBasedOnCulturalRecursive( + CultureInfo.CurrentUICulture.Parent, + translations, + 0 + ); + + if (translation != null) + { + res.Add(translation); + } + else + { + res.Add(null); + someHaveNoTranslations = true; + } + } + else + { + res.Add(null); + someHaveNoTranslations = true; + } + } + } + + + if (someHaveNoTranslations) + { + var defaultLanguage = await SettingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage); + + var index = 0; + foreach (var translations in translationsCombined) + { + if (!translations.Any()) + { + //don't try to find a translation + } + else + { + var translation = res[index]; + if (translation != null) + { + continue; + } + translation = translations.FirstOrDefault(pt => pt.Language == defaultLanguage); + if (translation != null) + { + res[index] = translation; + } + else + { + res[index] = translations.FirstOrDefault(); + } + } + index++; + } + } + return res; + } + + public virtual async Task> GetBulkTranslationsAsync(IEnumerable multiLinguals, string? culture, bool fallbackToParentCultures) + where TMultiLingual : IMultiLingualObject + where TTranslation : class, IObjectTranslation + { + var resInitial = await GetBulkTranslationsAsync(multiLinguals.Select(x => x.Translations), culture, fallbackToParentCultures); + var index = 0; + var res = new List<(TMultiLingual entity, TTranslation? translation)>(); + foreach (var item in multiLinguals) + { + var t = resInitial[index++]; + res.Add((item, t)); + } + return res; + } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs index 75ca252ca7..921aca8d7e 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs @@ -63,7 +63,7 @@ public class AbpSecurityModule : AbpModule { var contributorTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IAbpClaimsPrincipalContributor).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs index ebaaef54e1..eb05fbb949 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs @@ -36,7 +36,7 @@ public class AbpSettingsModule : AbpModule { var definitionProviders = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(ISettingDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleController.cs b/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleController.cs index 4d061d0195..dffb4b8a3a 100644 --- a/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleController.cs +++ b/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleController.cs @@ -12,16 +12,16 @@ namespace Volo.Abp.Swashbuckle; [ApiExplorerSettings(IgnoreApi = true)] public class AbpSwashbuckleController : AbpController { - private readonly IAbpAntiForgeryManager _antiForgeryManager; + protected readonly IAbpAntiForgeryManager AntiForgeryManager; public AbpSwashbuckleController(IAbpAntiForgeryManager antiForgeryManager) { - _antiForgeryManager = antiForgeryManager; + AntiForgeryManager = antiForgeryManager; } [HttpGet] - public void SetCsrfCookie() + public virtual void SetCsrfCookie() { - _antiForgeryManager.SetCookie(); + AntiForgeryManager.SetCookie(); } } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs index 74f0589355..cce61484b3 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs @@ -23,7 +23,7 @@ public class AbpTextTemplatingCoreModule : AbpModule var definitionProviders = new List(); var contentContributors = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(ITemplateDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/fi.json b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/fi.json index f7301d9c31..0efd4fee49 100644 --- a/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/fi.json +++ b/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/fi.json @@ -2,6 +2,6 @@ "culture": "fi", "texts": { "DisplayName:Abp.Timing.Timezone": "Aikavyöhyke", - "Description:Abp.Timing.Timezone": "Levityksen aikavyöhyke" + "Description:Abp.Timing.Timezone": "Sovelluksen aikavyöhyke" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs index 1a69de7f2c..9f48aebf97 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using JetBrains.Annotations; using Volo.Abp.Data; @@ -5,7 +6,7 @@ using Volo.Abp.UI.Navigation; namespace Volo.Abp.UI.Navigation; -public class ApplicationMenu : IHasMenuItems +public class ApplicationMenu : IHasMenuItems, IHasMenuGroups { /// /// Unique name of the menu in the application. @@ -31,6 +32,10 @@ public class ApplicationMenu : IHasMenuItems [NotNull] public ApplicationMenuItemList Items { get; } + /// + [NotNull] + public ApplicationMenuGroupList Groups { get; } + /// /// Can be used to store a custom object related to this menu. /// @@ -47,6 +52,7 @@ public class ApplicationMenu : IHasMenuItems DisplayName = displayName ?? Name; Items = new ApplicationMenuItemList(); + Groups = new ApplicationMenuGroupList(); } /// @@ -60,6 +66,17 @@ public class ApplicationMenu : IHasMenuItems return this; } + /// + /// Adds a to . + /// + /// to be added + /// This object + public ApplicationMenu AddGroup([NotNull] ApplicationMenuGroup group) + { + Groups.Add(group); + return this; + } + /// /// Adds a custom data item to with given key & value. /// diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs index eec549cf9c..624abde425 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs @@ -64,4 +64,54 @@ public static class ApplicationMenuExtensions return menuWithItems; } + + [NotNull] + public static ApplicationMenuGroup GetMenuGroup( + [NotNull] this IHasMenuGroups menuWithGroups, + string groupName) + { + var menuGroup = menuWithGroups.GetMenuGroupOrNull(groupName); + if (menuGroup == null) + { + throw new AbpException($"Could not find a group item with given name: {groupName}"); + } + + return menuGroup; + } + + [CanBeNull] + public static ApplicationMenuGroup GetMenuGroupOrNull( + [NotNull] this IHasMenuGroups menuWithGroups, + string menuGroupName) + { + Check.NotNull(menuWithGroups, nameof(menuWithGroups)); + + return menuWithGroups.Groups.FirstOrDefault(group => group.Name == menuGroupName); + } + + public static bool TryRemoveMenuGroup( + [NotNull] this IHasMenuGroups menuWithGroups, + string menuGroupName) + { + Check.NotNull(menuWithGroups, nameof(menuWithGroups)); + + return menuWithGroups.Groups.RemoveAll(group => group.Name == menuGroupName) > 0; + } + + [NotNull] + public static IHasMenuGroups SetMenuGroupOrder( + [NotNull] this IHasMenuGroups menuWithGroups, + string menuGroupName, + int order) + { + Check.NotNull(menuWithGroups, nameof(menuWithGroups)); + + var menuGroup = menuWithGroups.GetMenuGroupOrNull(menuGroupName); + if (menuGroup != null) + { + menuGroup.Order = order; + } + + return menuWithGroups; + } } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs new file mode 100644 index 0000000000..469c0ad355 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs @@ -0,0 +1,67 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.UI.Navigation; + +public class ApplicationMenuGroup +{ + private string _displayName; + + /// + /// Default value of a group item. + /// + public const int DefaultOrder = 1000; + + /// + /// Unique name of the group in the application. + /// + [NotNull] + public string Name { get; } + + /// + /// Display name of the group. + /// + [NotNull] + public string DisplayName { + get { return _displayName; } + set { + Check.NotNullOrWhiteSpace(value, nameof(value)); + _displayName = value; + } + } + + /// + /// Can be used to render the element with a specific Id for DOM selections. + /// + public string ElementId { get; set; } + + /// + /// The Display order of the group. + /// Default value: 1000. + /// + public int Order { get; set; } + + public ApplicationMenuGroup( + [NotNull] string name, + [NotNull] string displayName, + string elementId = null, + int order = DefaultOrder) + { + Check.NotNullOrWhiteSpace(name, nameof(name)); + Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); + + Name = name; + DisplayName = displayName; + ElementId = elementId; + Order = order; + } + + private string GetDefaultElementId() + { + return "MenuGroup_" + Name; + } + + public override string ToString() + { + return $"[ApplicationMenuGroup] Name = {Name}"; + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs new file mode 100644 index 0000000000..f280f5d4f9 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.UI.Navigation; + +public class ApplicationMenuGroupList: List +{ + public ApplicationMenuGroupList() + { + + } + + public ApplicationMenuGroupList(int capacity) + : base(capacity) + { + + } + + public ApplicationMenuGroupList(IEnumerable collection) + : base(collection) + { + + } + + public void Normalize() + { + Order(); + } + + private void Order() + { + var orderedItems = this.OrderBy(item => item.Order).ToArray(); + Clear(); + AddRange(orderedItems); + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index 32241ba7ac..dc1614e3e5 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -92,6 +92,11 @@ public class ApplicationMenuItem : IHasMenuItems, IHasSimpleStateCheckers public string CssClass { get; set; } + /// + /// Can be used to group menu items. + /// + public string GroupName { get; set; } + public ApplicationMenuItem( [NotNull] string name, [NotNull] string displayName, @@ -101,6 +106,7 @@ public class ApplicationMenuItem : IHasMenuItems, IHasSimpleStateCheckers>(); Items = new ApplicationMenuItemList(); diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs new file mode 100644 index 0000000000..fbbe7a63a4 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.UI.Navigation; + +public interface IHasMenuGroups +{ + /// + /// Menu groups. + /// + ApplicationMenuGroupList Groups { get; } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index aa933c6e09..349aa8e5a5 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -96,6 +96,7 @@ public class MenuManager : IMenuManager, ITransientDependency } NormalizeMenu(menu); + NormalizeMenuGroup(menu); return menu; } @@ -159,4 +160,23 @@ public class MenuManager : IMenuManager, ITransientDependency menuWithItems.Items.Normalize(); } + + protected virtual void NormalizeMenuGroup(ApplicationMenu applicationMenu) + { + foreach (var menuGroup in applicationMenu.Items.Where(x => !x.GroupName.IsNullOrWhiteSpace()).GroupBy(x => x.GroupName)) + { + var group = applicationMenu.GetMenuGroupOrNull(menuGroup.First().GroupName); + if (group != null) + { + continue; + } + + foreach (var menuItem in menuGroup) + { + menuItem.GroupName = null; + } + } + + applicationMenu.Groups.Normalize(); + } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json index 4717b1fe9b..bcbab76211 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json @@ -48,6 +48,7 @@ "Search": "بحث", "ItemWillBeDeletedMessageWithFormat": "سيتم حذف {0}!", "ItemWillBeDeletedMessage": "سوف يتم حذف هذا البند!", - "ManageYourAccount": "إدارة حسابك" + "ManageYourAccount": "إدارة حسابك", + "OthersGroup": "آخرون" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json index 1fe7ea6a23..5dc41952a6 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json @@ -48,6 +48,7 @@ "Search": "Vyhledávání", "ItemWillBeDeletedMessageWithFormat": "{0} bude smazáno!", "ItemWillBeDeletedMessage": "Tato položka bude smazána!", - "ManageYourAccount": "Spravujte svůj účet" + "ManageYourAccount": "Spravujte svůj účet", + "OthersGroup": "Jiný" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json index edb4f7563a..dc99f75586 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json @@ -48,6 +48,7 @@ "Search": "Suche", "ItemWillBeDeletedMessageWithFormat": "{0} wird gelöscht!", "ItemWillBeDeletedMessage": "Dieses Element wird gelöscht!", - "ManageYourAccount": "Verwalten Sie Ihr Benutzerkonto" + "ManageYourAccount": "Verwalten Sie Ihr Benutzerkonto", + "OthersGroup":"Andere" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json index 6bba8ee140..24a7642eb0 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json @@ -48,6 +48,7 @@ "Search": "Αναζήτηση", "ItemWillBeDeletedMessageWithFormat": "Το {0} θα διαγραφεί", "ItemWillBeDeletedMessage": "Αυτό το στοιχείο θα διαγραφεί!", - "ManageYourAccount": "Διαχείριση Λογαριασμού" + "ManageYourAccount": "Διαχείριση Λογαριασμού", + "OthersGroup":"άλλος" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json index a26c5ddf9e..4b88af7d26 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json @@ -48,6 +48,7 @@ "Search": "Search", "ItemWillBeDeletedMessageWithFormat": "{0} will be deleted!", "ItemWillBeDeletedMessage": "This item will be deleted!", - "ManageYourAccount": "Manage your account" + "ManageYourAccount": "Manage your account", + "OthersGroup": "Other" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 2a22849731..b97ca73d1d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -48,6 +48,9 @@ "Search": "Search", "ItemWillBeDeletedMessageWithFormat": "{0} will be deleted!", "ItemWillBeDeletedMessage": "This item will be deleted!", - "ManageYourAccount": "Manage your account" + "ManageYourAccount": "Manage your account", + "OthersGroup": "Other", + "Today": "Today", + "Apply": "Apply" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json index f2b40a785b..c28e8049bc 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json @@ -48,6 +48,7 @@ "Search": "Buscar", "ItemWillBeDeletedMessageWithFormat": "{0} serán borrados!", "ItemWillBeDeletedMessage": "Este elemento será borrado", - "ManageYourAccount": "Administrar cuenta" + "ManageYourAccount": "Administrar cuenta", + "OthersGroup": "Otra" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json index c2f81b9c52..4fd179573b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json @@ -48,6 +48,7 @@ "Search": "جستجو", "ItemWillBeDeletedMessageWithFormat": "{0} حذف خواهد شد!", "ItemWillBeDeletedMessage": "این مورد حذف خواهد شد!", - "ManageYourAccount": "حساب خود را مدیریت کنید" + "ManageYourAccount": "حساب خود را مدیریت کنید", + "OthersGroup": "دیگر" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json index 1f5c6b7724..25811c92eb 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json @@ -1,21 +1,21 @@ { "culture": "fi", "texts": { - "Languages": "Kieli (kielet", + "Languages": "Kielet", "AreYouSure": "Oletko varma?", - "Cancel": "Peruuttaa", - "Clear": "Asia selvä", - "Yes": "Joo", + "Cancel": "Peruuta", + "Clear": "Tyhjennä", + "Yes": "Kyllä", "No": "Ei", "Ok": "Ok", - "Close": "kiinni", - "Save": "Tallentaa", - "SavingWithThreeDot": "Tallentaa...", + "Close": "Sulje", + "Save": "Tallenna", + "SavingWithThreeDot": "Tallennetaan...", "Actions": "Toiminnot", - "Delete": "Poistaa", + "Delete": "Poista", "SuccessfullyDeleted": "Poistettu onnistuneesti", - "Edit": "Muokata", - "Refresh": "virkistää", + "Edit": "Muokkaa", + "Refresh": "Virkistä", "Language": "Kieli", "LoadMore": "Lataa lisää", "ProcessingWithThreeDot": "Käsitellään...", @@ -23,22 +23,22 @@ "Welcome": "Tervetuloa", "Login": "Kirjaudu sisään", "Register": "Rekisteröidy", - "Logout": "Kirjautua ulos", + "Logout": "Kirjaudu ulos", "Submit": "Lähetä", "Back": "Takaisin", "PagerSearch": "Hae", "PagerNext": "Seuraava", "PagerPrevious": "Edellinen", "PagerFirst": "Ensimmäinen", - "PagerLast": "Kestää", - "PagerInfo": "Näytetään _START_ - _END_/_TOTAL_ merkinnästä", - "PagerInfo{0}{1}{2}": "Näytetään {0} - {1}/{2} merkinnästä", - "PagerInfoEmpty": "Näytetään 0 - 0/0 merkinnästä", - "PagerInfoFiltered": "(suodatettu _MAX_ merkinnän kokonaismäärästä)", - "NoDataAvailableInDatatable": "Tietoja ei ole käytettävissä", + "PagerLast": "Viimeinen", + "PagerInfo": "Näytetään _START_ - _END_/_TOTAL_ tietueesta", + "PagerInfo{0}{1}{2}": "Näytetään {0} - {1}/{2} tietueesta", + "PagerInfoEmpty": "Näytetään 0 - 0/0 tietueesta", + "PagerInfoFiltered": "(suodatettu _MAX_ tietueen kokonaismäärästä)", + "NoDataAvailableInDatatable": "Tietoja ei löydy", "Total": "kaikki yhteensä", "Selected": "valittu", - "PagerShowMenuEntries": "Näytä _MENU_ merkinnät", + "PagerShowMenuEntries": "Näytä _MENU_ tietueet", "DatatableActionDropdownDefaultText": "Toiminnot", "ChangePassword": "Vaihda salasana", "PersonalInfo": "Profiilini", @@ -48,6 +48,7 @@ "Search": "Hae", "ItemWillBeDeletedMessageWithFormat": "{0} poistetaan!", "ItemWillBeDeletedMessage": "Tämä kohde poistetaan!", - "ManageYourAccount": "Hallitse tiliäsi" + "ManageYourAccount": "Hallitse tiliäsi", + "OthersGroup": "Muut" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json index 0fc43162b2..b850315dfe 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json @@ -48,6 +48,7 @@ "Search": "Recherche", "ItemWillBeDeletedMessageWithFormat": "{0} sera supprimé!", "ItemWillBeDeletedMessage": "Cet objet va être supprimé!", - "ManageYourAccount": "Gérer votre compte" + "ManageYourAccount": "Gérer votre compte", + "OthersGroup": "Autre" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json index 2c451bc797..0a20f1dcbb 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json @@ -48,6 +48,7 @@ "Search": "खोज", "ItemWillBeDeletedMessageWithFormat": "{0} हटा दिया जाएगा!", "ItemWillBeDeletedMessage": "यह आइटम हटा दिया जाएगा!", - "ManageYourAccount": "अपने खाते का प्रबंधन" + "ManageYourAccount": "अपने खाते का प्रबंधन", + "OthersGroup": "अन्य" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json index 9cbef79b12..a6285a4cee 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json @@ -48,6 +48,7 @@ "Search": "Pretraga", "ItemWillBeDeletedMessageWithFormat": "{0} zapis će biti obrisan!", "ItemWillBeDeletedMessage": "Ovaj zapis će biti obrisan!", - "ManageYourAccount": "Upravljaj korisničkim računom" + "ManageYourAccount": "Upravljaj korisničkim računom", + "OthersGroup": "Drugi" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json index 595e2f8b62..98c0c46f54 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json @@ -48,6 +48,7 @@ "Search": "Keresés", "ItemWillBeDeletedMessageWithFormat": "{0} törlésre kerül!", "ItemWillBeDeletedMessage": "Ez az elem törlődik!", - "ManageYourAccount": "Kezelje fiókját" + "ManageYourAccount": "Kezelje fiókját", + "OthersGroup": "Egyéb" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json index a931570496..12b1565c2e 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json @@ -48,6 +48,7 @@ "Search": "Leita", "ItemWillBeDeletedMessageWithFormat": "{0} verður eytt!", "ItemWillBeDeletedMessage": "Þessum lið verður eytt!", - "ManageYourAccount": "Stillingar notandaaðgangs" + "ManageYourAccount": "Stillingar notandaaðgangs", + "OthersGroup": "Annað" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json index 3c4328619e..f07bf67e2d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json @@ -48,6 +48,7 @@ "Search": "Ricerca", "ItemWillBeDeletedMessageWithFormat": "{0} sarà eliminato!", "ItemWillBeDeletedMessage": "Questo elemento sarà eliminato!", - "ManageYourAccount": "Gestisci il tuo account" + "ManageYourAccount": "Gestisci il tuo account", + "OthersGroup": "Altra" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json index d23d2356b4..5875fe07b9 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json @@ -48,6 +48,7 @@ "Search": "Zoeken", "ItemWillBeDeletedMessageWithFormat": "{0} wordt verwijderd!", "ItemWillBeDeletedMessage": "Dit item wordt verwijderd!", - "ManageYourAccount": "Beheer uw account" + "ManageYourAccount": "Beheer uw account", + "OthersGroup": "Ander" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json index e7cd503b4f..f2b8227137 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json @@ -48,6 +48,7 @@ "Search": "Szukaj", "ItemWillBeDeletedMessageWithFormat": "{0} zostanie usunięty!", "ItemWillBeDeletedMessage": "Ten element zostanie usunięty!", - "ManageYourAccount": "Zarządzaj kontem" + "ManageYourAccount": "Zarządzaj kontem", + "OthersGroup": "Inny" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json index 03855ec698..928c9299fb 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json @@ -48,6 +48,7 @@ "Search": "Procurar", "ItemWillBeDeletedMessageWithFormat": "{0} será excluído!", "ItemWillBeDeletedMessage": "Este item será excluído!", - "ManageYourAccount": "Gerenciar sua conta" + "ManageYourAccount": "Gerenciar sua conta", + "OthersGroup": "Outra" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json index 7064064671..544b893c39 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json @@ -48,6 +48,7 @@ "Search": "Caută", "ItemWillBeDeletedMessageWithFormat": "{0} va fi şters!", "ItemWillBeDeletedMessage": "Acest articol va fi şters!", - "ManageYourAccount": "Administraţi-vă contul" + "ManageYourAccount": "Administraţi-vă contul", + "OthersGroup": "Alte" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json index dc648a2138..66f24ca65d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json @@ -48,6 +48,7 @@ "Search": "поиск", "ItemWillBeDeletedMessageWithFormat": "{0} будет удален!", "ItemWillBeDeletedMessage": "Этот предмет будет удален!", - "ManageYourAccount": "Настройте свой аккаунт" + "ManageYourAccount": "Настройте свой аккаунт", + "OthersGroup": "Другой" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json index 59b2628310..28278f04f2 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json @@ -48,6 +48,7 @@ "Search": "Hľadať", "ItemWillBeDeletedMessageWithFormat": "{0} sa vymaže!", "ItemWillBeDeletedMessage": "Táto položka bude vymazaná!", - "ManageYourAccount": "Spravovať svoje konto" + "ManageYourAccount": "Spravovať svoje konto", + "OthersGroup": "Iné" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json index 7a50fbaf25..c05c1dc202 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json @@ -48,6 +48,7 @@ "Search": "Iskanje", "ItemWillBeDeletedMessageWithFormat": "{0} bo izbrisan!", "ItemWillBeDeletedMessage": "Ta element bo izbrisan!", - "ManageYourAccount": "Upravljajte svoj račun" + "ManageYourAccount": "Upravljajte svoj račun", + "OthersGroup": "Ostalo" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index 67ae56793a..9dc46b85a8 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -48,6 +48,9 @@ "Search": "Arama", "ItemWillBeDeletedMessageWithFormat": "{0} silinecektir!", "ItemWillBeDeletedMessage": "Bu nesne silinecektir!", - "ManageYourAccount": "Hesap yönetimi" + "ManageYourAccount": "Hesap yönetimi", + "OthersGroup": "Diğer", + "Today": "Bugün", + "Apply": "Uygula" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json index 4062990743..1b8bc5fb5b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json @@ -48,6 +48,7 @@ "Search": "Tìm kiếm", "ItemWillBeDeletedMessageWithFormat": "{0} sẽ bị xóa!", "ItemWillBeDeletedMessage": "Vật phẩm này sẽ bị xoá!", - "ManageYourAccount": "Quản lý tài khoản của bạn" + "ManageYourAccount": "Quản lý tài khoản của bạn", + "OthersGroup": "Khác" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json index 7c9d2798ff..133faa7386 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json @@ -48,6 +48,7 @@ "Search": "搜索", "ItemWillBeDeletedMessageWithFormat": "{0} 将被删除!", "ItemWillBeDeletedMessage": "此项将被删除!", - "ManageYourAccount": "管理你的账户" + "ManageYourAccount": "管理你的账户", + "OthersGroup": "其他" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json index 449dd67480..7bac7da3b8 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json @@ -48,6 +48,7 @@ "Search": "查詢", "ItemWillBeDeletedMessageWithFormat": "{0} 將被刪除!", "ItemWillBeDeletedMessage": "此項目將被刪除!", - "ManageYourAccount": "管理個人帳號" + "ManageYourAccount": "管理個人帳號", + "OthersGroup": "其他" } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs index 036e101397..541340183a 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs @@ -7,6 +7,6 @@ public class AbpUnitOfWorkModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(UnitOfWorkInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(UnitOfWorkInterceptorRegistrar.RegisterIfNeeded); } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index cc29fd23a8..8713b2ec7b 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -193,7 +193,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency if (_databaseApis.ContainsKey(key)) { - throw new AbpException("There is already a database API in this unit of work with given key: " + key); + throw new AbpException("There is already a database API in this unit of work with given key."); } _databaseApis.Add(key, api); @@ -221,7 +221,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency if (_transactionApis.ContainsKey(key)) { - throw new AbpException("There is already a transaction API in this unit of work with given key: " + key); + throw new AbpException("There is already a transaction API in this unit of work with given key."); } _transactionApis.Add(key, api); diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs index 476bf2de06..321599c35c 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs @@ -16,7 +16,7 @@ public class AbpValidationModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ValidationInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(ValidationInterceptorRegistrar.RegisterIfNeeded); AutoAddObjectValidationContributors(context.Services); } @@ -39,7 +39,7 @@ public class AbpValidationModule : AbpModule { var contributorTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IObjectValidationContributor).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json index 2cdb6999b5..252bee394f 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "يجب أن يكون الحقل {0} سلسلة أحرف طولها {1} كحد أدنى و {2} كحد أقصى.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "الحقل {0} ليس عنوانا URL صالحًا مؤهلاً بالكامل سواء كان عنوان http أو https أو ftp", "The field {0} is invalid.": "الحقل {0} غير صالح.", + "The value '{0}' is invalid.": "القيمة '{0}' غير صالحة.", + "The field {0} must be a number.": "يجب أن يكون الحقل {0} رقمًا.", + "The field must be a number.": "يجب أن يكون الحقل رقمًا.", "ThisFieldIsNotAValidCreditCardNumber.": "هذا الحقل لا يمثل رقم بطاقة ائتمان صالح.", "ThisFieldIsNotValid.": "هذا الحقل غير صالح.", "ThisFieldIsNotAValidEmailAddress.": "هذا الحقل لا يمثل عنوان بريد إلكتروني صالح.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json index dce07f8c91..60e2113906 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musí být řetězec o minimální délce {2} a maximální délce {1} znaků.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Pole {0} není platná plně kvalifikovaná adresa http, https, nebo ftp URL.", "The field {0} is invalid.": "Pole {0} je neplatné.", + "The value '{0}' is invalid.": "Hodnota '{0}' je neplatná.", + "The field {0} must be a number.": "Pole {0} musí být číslo.", + "The field must be a number.": "Pole musí být číslo.", "ThisFieldIsNotAValidCreditCardNumber.": "V poli {0} není platné číslo kreditní karty.", "ThisFieldIsNotValid.": "{0} není platný.", "ThisFieldIsNotAValidEmailAddress.": "V poli {0} není platný email.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json index a72a44a3bb..209d8536ae 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Das Feld {0} muss eine Zeichenfolge mit einer Mindestlänge von {2} und einer Maximallänge von {1} sein.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Das Feld {0} ist keine gültige, vollqualifizierte http-, https- oder ftp-URL.", "The field {0} is invalid.": "Das Feld {0} ist ungültig.", + "The value '{0}' is invalid.": "Der Wert '{0}' ist ungültig.", + "The field {0} must be a number.": "Das Feld {0} muss eine Zahl sein.", + "The field must be a number.": "Das Feld muss eine Zahl sein.", "ThisFieldIsNotAValidCreditCardNumber.": "Dieses Feld ist keine gültige Kreditkartennummer.", "ThisFieldIsNotValid.": "Dieses Feld ist ungültig.", "ThisFieldIsNotAValidEmailAddress.": "Dieses Feld ist keine gültige E-Mail-Adresse.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json index e2df0315f3..bed1964ac4 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Το πεδίο {0} πρέπει να είναι μια συμβολοσειρά με ελάχιστο μήκος {2} και μέγιστο μήκος {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Το πεδίο {0} δεν είναι έγκυρη πλήρως πιστοποιημένη διεύθυνση URL http, https ή ftp.", "The field {0} is invalid.": "Το πεδίο {0} δεν είναι έγκυρο.", + "The value '{0}' is invalid.": "Η τιμή '{0}' δεν είναι έγκυρη.", + "The field {0} must be a number.": "Το πεδίο {0} πρέπει να είναι αριθμός.", + "The field must be a number.": "Το πεδίο πρέπει να είναι αριθμός.", "ThisFieldIsNotAValidCreditCardNumber.": "Αυτό το πεδίο δεν περιέχει έγκυρο αριθμό πιστωτικής κάρτας.", "ThisFieldIsNotValid.": "Αυτό το πεδίο δεν είναι έγκυρο.", "ThisFieldIsNotAValidEmailAddress.": "Αυτό το πεδίο δεν περιέχει έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json index a53b55a853..0874616561 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json @@ -17,6 +17,9 @@ "The field {0} is invalid.": "The field {0} is invalid.", "ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.", "ThisFieldIsNotValid.": "This field is not valid.", + "The value '{0}' is invalid.": "The value '{0}' is invalid.", + "The field {0} must be a number.": "The field {0} must be a number.", + "The field must be a number.": "The field must be a number.", "ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.", "ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "This field only accepts files with the following extensions: {0}", "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}": "This field must be a string or array type with a maximum length of '{0}'.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json index 29035fb57f..8a866ef936 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "The {0} field is not a valid fully-qualified http, https, or ftp URL.", "The field {0} is invalid.": "The field {0} is invalid.", + "The value '{0}' is invalid.": "The value '{0}' is invalid.", + "The field {0} must be a number.": "The field {0} must be a number.", + "The field must be a number.": "The field must be a number.", "ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.", "ThisFieldIsNotValid.": "This field is not valid.", "ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.", @@ -33,4 +36,4 @@ "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "This field is not a valid fully-qualified http, https, or ftp URL.", "ThisFieldIsInvalid.": "This field is invalid." } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json index 55884667f6..969cb3f3a9 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "El campo {0} debe ser una cadena con una longitud mínima de {2} y máxima de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "El campo {0} no es una URL (http, https o ftp) valida.", "The field {0} is invalid.": "El campo {0} no es valido.", + "The value '{0}' is invalid.": "El valor '{0}' no es válido.", + "The field {0} must be a number.": "El campo {0} debe ser un número.", + "The field must be a number.": "El campo debe ser un número.", "ThisFieldIsNotAValidCreditCardNumber.": "El campo no es un número de tarjeta de crédito valido.", "ThisFieldIsNotValid.": "Este campo no es valido.", "ThisFieldIsNotAValidEmailAddress.": "Este campo no es una dirección de e-mail valida.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json index bdec7afe06..39ec042dcb 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "فیلد {0} باید رشته ای با حداقل طول {2} و حداکثر باشد طول {1}. ", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "فیلد {0} یک نشانی اینترنتی http ، https ، یا ftp کاملاً واجد شرایط نیست.", "The field {0} is invalid.": "فیلد {0} نامعتبر است.", + "The value '{0}' is invalid.": "مقدار '{0}' نامعتبر است.", + "The field {0} must be a number.": "فیلد {0} باید یک عدد باشد.", + "The field must be a number.": "فیلد باید یک عدد باشد.", "ThisFieldIsNotAValidCreditCardNumber.": "این قسمت شماره کارت اعتباری معتبری نیست.", "ThisFieldIsNotValid.": "این قسمت معتبر نیست.", "ThisFieldIsNotAValidEmailAddress.": "این قسمت آدرس ایمیل معتبری نیست.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json index f4501b87cf..7219c45ccf 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json @@ -6,29 +6,34 @@ "{0} is not valid.": "{0} ei kelpaa.", "The {0} field is not a valid e-mail address.": "{0} -kenttä ei ole kelvollinen sähköpostiosoite.", "The {0} field only accepts files with the following extensions: {1}": "{0} -kenttä hyväksyy vain tiedostot, joilla on seuraavat laajennukset: {1}", - "The field {0} must be a string or array type with a maximum length of '{1}'.": "Kentän {0} on oltava merkkijono- tai taulukotyyppi, jonka enimmäispituus on {1}.", - "The field {0} must be a string or array type with a minimum length of '{1}'.": "Kentän {0} on oltava merkkijono tai matriisityyppi, jonka vähimmäispituus on {1}.", + "The field {0} must be a string or array type with a maximum length of '{1}'.": "Kentän {0} on oltava merkkijono- tai taulukko, jonka enimmäispituus on {1}.", + "The field {0} must be a string or array type with a minimum length of '{1}'.": "Kentän {0} on oltava merkkijono tai taulukko, jonka vähimmäispituus on {1}.", "The {0} field is not a valid phone number.": "{0} -kenttä ei ole kelvollinen puhelinnumero.", "The field {0} must be between {1} and {2}.": "Kentän {0} on oltava välillä {1} - {2}.", "The field {0} must match the regular expression '{1}'.": "Kenttä {0} ei vastaa pyydettyä muotoa.", "The {0} field is required.": "{0} -kenttä on pakollinen.", "The field {0} must be a string with a maximum length of {1}.": "Kentän {0} on oltava merkkijono, jonka enimmäispituus on {1}.", "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Kentän {0} on oltava merkkijono, jonka vähimmäispituus on {2} ja enimmäispituus {1}.", - "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} -kenttä ei ole kelvollinen täysin hyväksytty http, https tai ftp URL.", + "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} -kenttä ei ole kelvollinen http, https tai ftp URL-osoite.", "The field {0} is invalid.": "Kenttä {0} on virheellinen.", + "The value '{0}' is invalid.": "Arvo '{0}' on virheellinen.", + "The field {0} must be a number.": "Kentän {0} on oltava numero.", + "The field must be a number.": "Kentän on oltava numero.", "ThisFieldIsNotAValidCreditCardNumber.": "Tämä kenttä ei ole kelvollinen luottokortin numero.", "ThisFieldIsNotValid.": "Tämä kenttä ei kelpaa.", "ThisFieldIsNotAValidEmailAddress.": "Tämä kenttä ei ole kelvollinen sähköpostiosoite.", "ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "Tämä kenttä hyväksyy vain tiedostot, joilla on seuraavat laajennukset: {0}", - "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}": "Tämän kentän on oltava merkkijono- tai taulukotyyppi, jonka enimmäispituus on {0}.", - "ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}": "Tämän kentän on oltava merkkijono- tai taulukotyyppi, jonka vähimmäispituus on {0}.", + "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}": "Tämän kentän on oltava merkkijono- tai taulukko, jonka enimmäispituus on {0}.", + "ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}": "Tämän kentän on oltava merkkijono- tai taulukko, jonka vähimmäispituus on {0}.", "ThisFieldIsNotAValidPhoneNumber.": "Tämä kenttä ei ole kelvollinen puhelinnumero.", "ThisFieldMustBeBetween{0}And{1}": "Tämän kentän on oltava välillä {0} - {1}.", + "ThisFieldMustBeGreaterThanOrEqual{0}": "Tämän kentän on oltava suurempi tai yhtä suuri kuin {0}.", + "ThisFieldMustBeLessOrEqual{0}": "Tämän kentän on oltava pienempi tai yhtä suuri kuin {0}.", "ThisFieldMustMatchTheRegularExpression{0}": "Tämän kentän on vastattava säännöllistä lauseketta {0}.", "ThisFieldIsRequired.": "Tämä kenttä pitää täyttää.", "ThisFieldMustBeAStringWithAMaximumLengthOf{0}": "Tämän kentän on oltava merkkijono, jonka enimmäispituus on {0}.", "ThisFieldMustBeAStringWithAMinimumLengthOf{1}AndAMaximumLengthOf{0}": "Tämän kentän on oltava merkkijono, jonka vähimmäispituus on {1} ja enimmäispituus {0}.", - "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "Tämä kenttä ei ole kelvollinen täysin hyväksytty http, https tai ftp URL.", + "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "Tämä kenttä ei ole kelvollinen http, https tai ftp URL-osoite.", "ThisFieldIsInvalid.": "Tämä kenttä on virheellinen." } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json index 558bc9ca11..0adf748127 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Le champ {0} doit être une chaîne d'une longueur minimale de {2} et d'une longueur maximale de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Le champ {0} n'est pas une URL http, https ou ftp complète valide.", "The field {0} is invalid.": "Le champ {0} n'est pas valide.", + "The value '{0}' is invalid.": "La valeur '{0}' n'est pas valide.", + "The field {0} must be a number.": "Le champ {0} doit être un nombre.", + "The field must be a number.": "Le champ doit être un nombre.", "ThisFieldIsNotAValidCreditCardNumber.": "Ce champ n'est pas un numéro de carte de crédit valide.", "ThisFieldIsNotValid.": "Ce champ n'est pas valide.", "ThisFieldIsNotAValidEmailAddress.": "Ce champ n'est pas une adresse e-mail valide.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json index fab1a394b4..d7ae279c18 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "फ़ील्ड {0} की लंबाई न्यूनतम {2} और अधिकतम लंबाई {1} होनी चाहिए।", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} फ़ील्ड मान्य पूर्णत: योग्य http, https, या ftp URL नहीं है।", "The field {0} is invalid.": "फ़ील्ड {0} अमान्य है।", + "The value '{0}' is invalid.": "मान '{0}' अमान्य है।", + "The field {0} must be a number.": "फ़ील्ड {0} एक संख्या होनी चाहिए।", + "The field must be a number.": "फ़ील्ड एक संख्या होनी चाहिए।", "ThisFieldIsNotAValidCreditCardNumber.": "यह फ़ील्ड मान्य क्रेडिट कार्ड नंबर नहीं है।", "ThisFieldIsNotValid.": "यह फ़ील्ड मान्य नहीं है।", "ThisFieldIsNotAValidEmailAddress.": "यह फ़ील्ड मान्य ई-मेल पता नहीं है।", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json index 6bb5cf7d5e..dcc01e9b0a 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Polje {0} mora biti text sa minimalnom du�inom od {2} i maksimalnom dužinom od {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} nije valjan potpuno kvalificirani http, https, ili ftp URL.", "The field {0} is invalid.": "Polje {0} nije važeće.", + "The value '{0}' is invalid.": "Vrijednost '{0}' nije važeća.", + "The field {0} must be a number.": "Polje {0} mora biti broj.", + "The field must be a number.": "Polje mora biti broj.", "ThisFieldIsNotAValidCreditCardNumber.": "Ovo polje nije važeći broj kreditne kartice.", "ThisFieldIsNotValid.": "Ovo polje nije valjano.", "ThisFieldIsNotAValidEmailAddress.": "Ovo polje nije valjana e-mail adresa.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json index 3db0f6f5c0..b06d9d3c47 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "A {0} mezőnek szöveget kell tartalmaznia minimum {2} és maximum {1} hosszan.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "A {0} mező nem érvényes fully-qualified http, https, vagy ftp URL cím.", "The field {0} is invalid.": "A {0} mező nem érvényes.", + "The value '{0}' is invalid.": "A(z) '{0}' érték érvénytelen.", + "The field {0} must be a number.": "A(z) {0} mezőnek számnak kell lennie.", + "The field must be a number.": "A mezőnek számnak kell lennie.", "ThisFieldIsNotAValidCreditCardNumber.": "A mező nem érvényes bankkártya számot tartalmaz.", "ThisFieldIsNotValid.": "A mező nem érvényes.", "ThisFieldIsNotAValidEmailAddress.": "A mező nem érvényes email cím.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json index 8f3ef3ae88..1f9c858d2a 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Reiturinn {0} verður að vera strengur með lágmarkslengd {2} og hámarkslengd {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Reiturinn {0} er ekki fullgild http, https, eða ftp slóð.", "The field {0} is invalid.": "Reiturinn {0} er ekki rétt útfylltur.", + "The value '{0}' is invalid.": "Gildið '{0}' er ógilt.", + "The field {0} must be a number.": "Reiturinn {0} verður að vera númer.", + "The field must be a number.": "Reiturinn verður að vera númer.", "ThisFieldIsNotAValidCreditCardNumber.": "Þessi reitur hefur ekki gilt kreditkortanúmer.", "ThisFieldIsNotValid.": "Reiturinn er ekki rétt útfylltur.", "ThisFieldIsNotAValidEmailAddress.": "Þessi reitur hefur ekki gilt netfang.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json index bad68c117f..4cf02600bc 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Il campo {0} deve essere una stringa con una lunghezza minima di {2} e una lunghezza massima di {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Il campo {0} non è un URL http, https o ftp completo e valido.", "The field {0} is invalid.": "Il campo {0} non è valido.", + "The value '{0}' is invalid.": "Il valore '{0}' non è valido.", + "The field {0} must be a number.": "Il campo {0} deve essere un numero.", + "The field must be a number.": "Il campo deve essere un numero.", "ThisFieldIsNotAValidCreditCardNumber.": "Questo campo non è un numero di carta di credito valido.", "ThisFieldIsNotValid.": "Questo campo non è valido.", "ThisFieldIsNotAValidEmailAddress.": "Questo campo non è un indirizzo e-mail valido.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json index ff0edfa54d..096d2fcbc3 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Het veld {0} moet een tekenreeks zijn met een minimale lengte van {2} en een maximale lengte van {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Het veld {0} is geen geldige, volledig gekwalificeerde http-, https- of ftp-URL.", "The field {0} is invalid.": "Het veld {0} is ongeldig.", + "The value '{0}' is invalid.": "De waarde '{0}' is ongeldig.", + "The field {0} must be a number.": "Het veld {0} moet een getal zijn.", + "The field must be a number.": "Het veld moet een getal zijn.", "ThisFieldIsNotAValidCreditCardNumber.": "Dit veld is geen geldig krediet kaartnummer.", "ThisFieldIsNotValid.": "Dir veld is ongeldig.", "ThisFieldIsNotAValidEmailAddress.": "Dit veld is geen geldig e-mail adres.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json index c4a6cfe9d6..29baf6efff 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musi być łańcuchem znaków o minimalnej długości {2} i maksymalnej długości {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Pole {0} nie jest prawidłowym, w pełni kwalifikowanym adresem URL http, https lub ftp.", "The field {0} is invalid.": "Pole {0} jest niepoprawne.", + "The value '{0}' is invalid.": "Wartość '{0}' jest nieprawidłowa.", + "The field {0} must be a number.": "Pole {0} musi być liczbą.", + "The field must be a number.": "Pole musi być liczbą.", "ThisFieldIsNotAValidCreditCardNumber.": "To pole nie jest prawidłowym numerem karty kredytowej.", "ThisFieldIsNotValid.": "To pole jest nieprawidłowe.", "ThisFieldIsNotAValidEmailAddress.": "To pole nie jest prawidłowym adresem e-mail.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json index 1168a19317..a0bec74d8c 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "O campo {0} deve ser uma palavra com o tamanho mínimo de {2} e tamanho máximo de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "O campo {0} não é um http, https, ou FTP válido.", "The field {0} is invalid.": "O campo {0} é inválido.", + "The value '{0}' is invalid.": "O valor '{0}' é inválido.", + "The field {0} must be a number.": "O campo {0} deve ser um número.", + "The field must be a number.": "O campo deve ser um número.", "ThisFieldIsNotAValidCreditCardNumber.": "Não é um cartão de crédito válido.", "ThisFieldIsNotValid.": "Campo inválido.", "ThisFieldIsNotAValidEmailAddress.": "E-mail inválido.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json index ce03ecb52b..5fe4e459a2 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Câmpul {0} trebuie să fie un string cu lungimea minimă de {2} şi lungimea maximă de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Câmpul {0} nu este o adresă validă complet http, https sau ftp.", "The field {0} is invalid.": "Câmpul {0} este invalid.", + "The value '{0}' is invalid.": "Valoarea '{0}' este nevalidă.", + "The field {0} must be a number.": "Câmpul {0} trebuie să fie un număr.", + "The field must be a number.": "Câmpul trebuie să fie un număr.", "ThisFieldIsNotAValidCreditCardNumber.": "Acest câmp nu este un număr de card de credit valid.", "ThisFieldIsNotValid.": "Acest câmp nu este valid.", "ThisFieldIsNotAValidEmailAddress.": "Acest câmp nu este o adresă de e-mail validă.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json index 877a3bb1dc..a52c619933 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Поле {0} должно быть строкой с минимальной длиной {2} и максимальной длиной {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Поле {0} не является действительным полным http, https или ftp адресом.", "The field {0} is invalid.": "Значение в поле {0} недопустимо.", + "The value '{0}' is invalid.": "Значение '{0}' недопустимо.", + "The field {0} must be a number.": "Поле {0} должно быть числом.", + "The field must be a number.": "Поле должно быть числом.", "ThisFieldIsNotAValidCreditCardNumber.": "Это поле не содержит действительный номер кредитной карты.", "ThisFieldIsNotValid.": "Значение в этом поле недействительно.", "ThisFieldIsNotAValidEmailAddress.": "Это поле не содержит действительный адрес электронной почты.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json index d5f310aa66..856124c31f 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musí byť reťazec s minimálnou dĺžkou {2} a maximálnou dĺžkou {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "V poli {0} nie je platná plne kvalifikovaná adresa http, https alebo ftp URL.", "The field {0} is invalid.": "Pole {0} je neplatné.", + "The value '{0}' is invalid.": "Hodnota '{0}' je neplatná.", + "The field {0} must be a number.": "Pole {0} musí byť číslo.", + "The field must be a number.": "Pole musí byť číslo.", "ThisFieldIsNotAValidCreditCardNumber.": "V tomto poli nie je platné číslo kreditnej karty.", "ThisFieldIsNotValid.": "Toto pole nie je platné.", "ThisFieldIsNotAValidEmailAddress.": "V tomto poli nie je platná e-mailová adresa.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json index 374425728d..0eaa31916b 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Polje {0} mora biti niz z najmanjšo dolžino {2} in največjo dolžino {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Polje {0} ni veljaven popolnoma kvalificiran URL http, https ali ftp.", "The field {0} is invalid.": "Polje {0} ni veljavno.", + "The value '{0}' is invalid.": "Vrednost '{0}' ni veljavna.", + "The field {0} must be a number.": "Polje {0} mora biti številka.", + "The field must be a number.": "Polje mora biti številka.", "ThisFieldIsNotAValidCreditCardNumber.": "To polje ni veljavna številka kreditne kartice.", "ThisFieldIsNotValid.": "To polje ni veljavno.", "ThisFieldIsNotAValidEmailAddress.": "To polje ni veljaven e-poštni naslov.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json index 9d784c57d9..cb30adde0d 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "{0} alanı en az {2}, en fazla {1} uzunluğunda bir metin olmalıdır.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} alanı geçerli bir http, https, ya da ftp adresi olmalıdır.", "The field {0} is invalid.": "{0} alanı geçerli değil.", + "The value '{0}' is invalid.": "{0} değeri geçerli değil.", + "The field {0} must be a number.": "{0} alanı bir sayı olmalıdır.", + "The field must be a number.": "Bu alan bir sayı olmalıdır.", "ThisFieldIsNotAValidCreditCardNumber.": "Bu alan geçerli bir kredi kartı numarası olmalıdır.", "ThisFieldIsNotValid.": "Bu alan geçerli değil.", "ThisFieldIsNotAValidEmailAddress.": "Bu alan geçerli bir e-posta adresi olmalıdır.", @@ -33,4 +36,4 @@ "ThisFieldMustBeGreaterThanOrEqual{0}": "Bu alan {0}'dan büyük veya eşit olmalıdır.", "ThisFieldMustBeLessOrEqual{0}": "Bu alan {0}'dan küçük veya eşit olmalıdır." } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json index 9bfc2c10ca..984f5c2e2b 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Trường {0} phải là một chuỗi với độ dài tối thiểu {2} và tối đa là {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Trường {0} không phải là một http, https, hoặc ftp URL đủ điều kiện hợp lệ.", "The field {0} is invalid.": "Trường {0} không có hiệu lực", + "The value '{0}' is invalid.": "Giá trị '{0}' không hợp lệ.", + "The field {0} must be a number.": "Trường {0} phải là một số.", + "The field must be a number.": "Trường phải là một số.", "ThisFieldIsNotAValidCreditCardNumber.": "Trường này không phải là số thẻ tín dụng hợp lệ.", "ThisFieldIsNotValid.": "Trường này không hợp lệ.", "ThisFieldIsNotAValidEmailAddress.": "Trường này không phải là địa chỉ e-mail hợp lệ.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json index 3c1a566112..262b2e08fa 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "字段{0}必须是最小长度为{2}并且最大长度{1}的字符串.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "字段{0}不是有效的完全限定的http,https或ftp URL.", "The field {0} is invalid.": "字段{0}是无效值.", + "The value '{0}' is invalid.": "'{0}'是无效值", + "The field {0} must be a number.": "字段{0}必须是数字.", + "The field must be a number.": "该字段必须是数字.", "ThisFieldIsNotAValidCreditCardNumber.": "字段不是有效的信用卡号码.", "ThisFieldIsNotValid.": "验证未通过.", "ThisFieldIsNotAValidEmailAddress.": "字段不是有效的邮箱地址.", @@ -33,4 +36,4 @@ "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "字段{0}不是有效的完全限定的http,https或ftp URL.", "ThisFieldIsInvalid.": "该字段无效." } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json index ec0fabd121..0f14ca2a40 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "欄位{0}必須是最小長度為{2}並且最大長度{1}的字串.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "欄位{0}不是有效的完全限定的http,https或ftp URL.", "The field {0} is invalid.": "此欄位{0}是無效值.", + "The value '{0}' is invalid.": "'{0}'是無效值", + "The field {0} must be a number.": "欄位{0}必須是號碼.", + "The field must be a number.": "此欄位{0}必須是號碼.", "ThisFieldIsNotAValidCreditCardNumber.": "此欄位不是有效的信用卡號碼.", "ThisFieldIsNotValid.": "此驗證未通過.", "ThisFieldIsNotAValidEmailAddress.": "此欄位不是有效的郵箱地址.", diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs index b41ea093ff..7d5d4d0561 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs @@ -14,7 +14,7 @@ public class AbpAuthorizationTestModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(onServiceRegistredContext => + context.Services.OnRegistered(onServiceRegistredContext => { if (typeof(IMyAuthorizedService1).IsAssignableFrom(onServiceRegistredContext.ImplementationType) && !DynamicProxyIgnoreTypes.Contains(onServiceRegistredContext.ImplementationType)) diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs index 42fe0da502..db7b5f5cc8 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/BackgroundJobExecuter_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Shouldly; using Xunit; @@ -59,7 +60,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase jobObject.ExecutedValues.ShouldContain("42"); } - + [Fact] public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant() { @@ -77,7 +78,7 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase new MyJobArgs("42", tenantId) ) ); - + await _backgroundJobExecuter.ExecuteAsync( new JobExecutionContext( ServiceProvider, @@ -91,4 +92,48 @@ public class BackgroundJobExecuter_Tests : BackgroundJobsTestBase jobObject.TenantId.ShouldBe(tenantId); asyncJobObject.TenantId.ShouldBe(tenantId); } + + [Fact] + public async Task Should_Cancel_Job() + { + //Arrange + var cts = new CancellationTokenSource(); + cts.Cancel(); + + var jobObject = GetRequiredService(); + jobObject.ExecutedValues.ShouldBeEmpty(); + + //Act + await _backgroundJobExecuter.ExecuteAsync( + new JobExecutionContext( + ServiceProvider, + typeof(MyJob), + new MyJobArgs("42"), + cts.Token + ) + ); + + //Assert + jobObject.Canceled.ShouldBeTrue(); + + //Arrange + var asyncCts = new CancellationTokenSource(); + asyncCts.Cancel(); + + var asyncJobObject = GetRequiredService(); + asyncJobObject.ExecutedValues.ShouldBeEmpty(); + + //Act + await _backgroundJobExecuter.ExecuteAsync( + new JobExecutionContext( + ServiceProvider, + typeof(MyAsyncJob), + new MyAsyncJobArgs("42"), + asyncCts.Token + ) + ); + + //Assert + asyncJobObject.Canceled.ShouldBeTrue(); + } } diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs index 79c5ea887a..d738b36130 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyAsyncJob.cs @@ -1,26 +1,39 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs; public class MyAsyncJob : AsyncBackgroundJob, ISingletonDependency { public List ExecutedValues { get; } = new List(); - + public Guid? TenantId { get; set; } - + private readonly ICurrentTenant _currentTenant; + private readonly ICancellationTokenProvider _cancellationTokenProvider; - public MyAsyncJob(ICurrentTenant currentTenant) + public bool Canceled { get; set; } + + public MyAsyncJob( + ICurrentTenant currentTenant, + ICancellationTokenProvider cancellationTokenProvider) { _currentTenant = currentTenant; + _cancellationTokenProvider = cancellationTokenProvider; } public override Task ExecuteAsync(MyAsyncJobArgs args) { + if (_cancellationTokenProvider.Token.IsCancellationRequested) + { + Canceled = true; + } + ExecutedValues.Add(args.Value); TenantId = _currentTenant.Id; return Task.CompletedTask; diff --git a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs index 3b01ec05d1..1f9658162d 100644 --- a/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs +++ b/framework/test/Volo.Abp.BackgroundJobs.Tests/Volo/Abp/BackgroundJobs/MyJob.cs @@ -1,25 +1,38 @@ using System; using System.Collections.Generic; +using System.Threading; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs; public class MyJob : BackgroundJob, ISingletonDependency { public List ExecutedValues { get; } = new List(); - + public Guid? TenantId { get; set; } private readonly ICurrentTenant _currentTenant; - - public MyJob(ICurrentTenant currentTenant) + private readonly ICancellationTokenProvider _cancellationTokenProvider; + + public bool Canceled { get; set; } + + public MyJob( + ICurrentTenant currentTenant, + ICancellationTokenProvider cancellationTokenProvider) { _currentTenant = currentTenant; + _cancellationTokenProvider = cancellationTokenProvider; } public override void Execute(MyJobArgs args) { + if (_cancellationTokenProvider.Token.IsCancellationRequested) + { + Canceled = true; + } + ExecutedValues.Add(args.Value); TenantId = _currentTenant.Id; } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs index f4b584701f..e244237598 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs @@ -19,7 +19,7 @@ public abstract class AbpInterceptionTestBase : AbpAsyncIntegrat services.AddTransient(); services.AddTransient(); - services.OnRegistred(registration => + services.OnRegistered(registration => { if (typeof(SimpleInterceptionTargetClass) == registration.ImplementationType) { diff --git a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs index 276be829b2..37e6b07b8f 100644 --- a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs +++ b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs @@ -109,7 +109,7 @@ public class ApplicationService_FluentValidation_Tests : AbpIntegratedTest + context.Services.OnRegistered(onServiceRegistredContext => { if (typeof(IMyAppService).IsAssignableFrom(onServiceRegistredContext.ImplementationType) && !DynamicProxyIgnoreTypes.Contains(onServiceRegistredContext.ImplementationType)) diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/fi.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/fi.json index b2d289d3c7..45a513ca1e 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/fi.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/fi.json @@ -2,6 +2,11 @@ "culture": "fi", "texts": { "ThisFieldIsRequired": "Tämä kenttä pitää täyttää", - "MaxLenghtErrorMessage": "Tämä kenttä voi olla enintään {0} merkkiä" + "MaxLenghtErrorMessage": "Tämä kenttä voi olla enintään {0} merkkiä", + "Enum:BookType.Undefined": "Määrittämätön ValidationResourcesta", + "Enum:BookType.0": "Määrittämätön arvo 0 ValidationResourcesta", + "BookType.Adventure": "Seikkailu ValidationResourcesta", + "BookType.1": "Seikkailu arvolla 1 ValidationResourcesta", + "Biography": "Elämäkerta ValidationResourcesta" } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hans.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hans.json index a6ebb5d590..9d7b5324c9 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hans.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/zh-Hans.json @@ -2,6 +2,11 @@ "culture": "zh-Hans", "texts": { "ThisFieldIsRequired": "此字段是必填字段", - "MaxLenghtErrorMessage": "该字段最多可包含'{0}'个字符" + "MaxLenghtErrorMessage": "该字段最多可包含'{0}'个字符", + "Enum:BookType.Undefined": "", + "Enum:BookType.0": "", + "BookType.Adventure": "", + "BookType.1": "", + "Biography": "" } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs index 95a1bbd32f..594efff5a3 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs @@ -1,4 +1,4 @@ -using Volo.Abp.Localization.TestResources.Base.Validation; +using Volo.Abp.Localization.TestResources.Base.Validation; namespace Volo.Abp.Localization.TestResources.Source; diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/fi.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/fi.json index 74eabcd747..d4e546f1e3 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/fi.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/fi.json @@ -6,6 +6,11 @@ "CarPlural": "Autot", "MaxLenghtErrorMessage": "Tämän kentän pituus voi olla enintään {0} merkkiä", "Universe": "Maailmankaikkeus", - "FortyTwo": "Neljäkymmentäkaksi" + "FortyTwo": "Neljäkymmentäkaksi", + "Enum:BookType.Undefined": "Määrittelemätön", + "Enum:BookType.0": "Määrittämätön arvolla 0", + "BookType.Adventure": "Seikkailu", + "BookType.1": "Seikkailu arvolla 1", + "Biography": "Elämäkerta" } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hans.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hans.json index 52bba48434..f3828e90e2 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hans.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/zh-Hans.json @@ -6,6 +6,11 @@ "CarPlural": "汽车", "MaxLenghtErrorMessage": "此字段的长度最多为'{0}'个字符", "Universe": "宇宙", - "FortyTwo": "四十二" + "FortyTwo": "四十二", + "Enum:BookType.Undefined": "Undefined", + "Enum:BookType.0": "", + "BookType.Adventure": "", + "BookType.1": "", + "Biography": "" } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo.Abp.MultiLingualObjects.Tests.csproj b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo.Abp.MultiLingualObjects.Tests.csproj index a037cfbcf3..b26ea500bf 100644 --- a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo.Abp.MultiLingualObjects.Tests.csproj +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo.Abp.MultiLingualObjects.Tests.csproj @@ -1,18 +1,21 @@ - + - - net7.0 - - + + net7.0 + + enable + - - - - - - - + + + + + + + + + diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/AbpMultiLingualObjectsTestModule.cs b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/AbpMultiLingualObjectsTestModule.cs index f099b4fa6c..6fc3a45132 100644 --- a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/AbpMultiLingualObjectsTestModule.cs +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/AbpMultiLingualObjectsTestModule.cs @@ -1,19 +1,34 @@ -using Volo.Abp.Autofac; -using Volo.Abp.Localization; -using Volo.Abp.Modularity; -using Volo.Abp.ObjectMapping; -using Volo.Abp.Settings; - -namespace Volo.Abp.MultiLingualObjects; - -[DependsOn( - typeof(AbpAutofacModule), - typeof(AbpLocalizationModule), - typeof(AbpSettingsModule), - typeof(AbpObjectMappingModule), - typeof(AbpMultiLingualObjectsModule), - typeof(AbpTestBaseModule) -)] -public class AbpMultiLingualObjectsTestModule : AbpModule -{ -} +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; +using Volo.Abp.AutoMapper; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.ObjectMapping; +using Volo.Abp.Settings; + +namespace Volo.Abp.MultiLingualObjects; + +[DependsOn( + typeof(AbpAutofacModule), + typeof(AbpLocalizationModule), + typeof(AbpSettingsModule), + typeof(AbpObjectMappingModule), + typeof(AbpMultiLingualObjectsModule), + typeof(AbpTestBaseModule), + typeof(AbpAutoMapperModule) +)] +public class AbpMultiLingualObjectsTestModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.DefinitionProviders.Add(); + }); + context.Services.AddAutoMapperObjectMapper(); + Configure(options => + { + options.AddMaps(validate: true); + }); + } +} diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager_Tests.cs b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager_Tests.cs index afe15bff99..e442d80953 100644 --- a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager_Tests.cs +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectManager_Tests.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.AutoMapper; using Volo.Abp.Localization; using Volo.Abp.MultiLingualObjects.TestObjects; using Volo.Abp.Testing; @@ -14,40 +16,63 @@ public class MultiLingualObjectManager_Tests : AbpIntegratedTest _books; + private readonly IMapperAccessor _mapperAccessor; + private readonly Dictionary _testTranslations = new() + { + ["ar"] = "C# التعمق في", + ["zh-Hans"] = "深入理解C#", + ["en"] = "C# in Depth" + }; + public MultiLingualObjectManager_Tests() { - _multiLingualObjectManager = ServiceProvider.GetRequiredService(); - + _multiLingualObjectManager = ServiceProvider.GetRequiredService(); + + //Single Lookup + _book = GetTestBook("en", "zh-Hans"); + //Bulk lookup + _books = new List + { + //has no translations + GetTestBook(), + //english only + GetTestBook("en"), + //arabic only + GetTestBook("ar"), + //arabic + english + GetTestBook("en","ar"), + //arabic + english + chineese + GetTestBook("en", "ar", "zh-Hans") + }; + _mapperAccessor = ServiceProvider.GetRequiredService(); + } + MultiLingualBook GetTestBook(params string[] included) + { var id = Guid.NewGuid(); - _book = new MultiLingualBook(id, 100) - { - Translations = new List() - }; - - var en = new MultiLingualBookTranslation - { - Language = "en", - Name = "C# in Depth", - }; - var zh = new MultiLingualBookTranslation - { - Language = "zh-Hans", - Name = "深入理解C#", - }; - - _book.Translations.Add(en); - _book.Translations.Add(zh); - } + //Single book + var res = new MultiLingualBook(id, 100); + foreach (var language in included) + { + res.Translations.Add(new MultiLingualBookTranslation + { + Language = language, + Name = _testTranslations[language], + }); + } + + return res; + } + [Fact] public async Task GetTranslationAsync() { using (CultureHelper.Use("en-us")) { var translation = await _multiLingualObjectManager.GetTranslationAsync(_book); - - translation.Name.ShouldBe("C# in Depth"); + translation.ShouldNotBeNull(); + translation.Name.ShouldBe(_testTranslations["en"]); } } @@ -57,8 +82,8 @@ public class MultiLingualObjectManager_Tests : AbpIntegratedTest(_book, culture: "en"); + translation.ShouldNotBeNull(); + translation.Name.ShouldBe(_testTranslations["en"]); + } + } + + + [Fact] + public async Task GetBulkTranslationsAsync() + { + using (CultureHelper.Use("en-us")) + { + var translations = await _multiLingualObjectManager.GetBulkTranslationsAsync(_books); + foreach (var (entity, translation) in translations) + { + if (entity.Translations.Any(x => x.Language == "en")) + { + translation.ShouldNotBeNull(); + translation.Name.ShouldBe(_testTranslations["en"]); + } + else + { + translation.ShouldBeNull(); + } + } + } + } - translation.Name.ShouldBe("C# in Depth"); + [Fact] + public async Task GetBulkTranslationsFromListAsync() + { + using (CultureHelper.Use("en-us")) + { + var translations = await _multiLingualObjectManager.GetBulkTranslationsAsync(_books.Select(x => x.Translations)); + foreach (var translation in translations) + { + translation?.Name.ShouldBe(_testTranslations["en"]); + } } } + + [Fact] + public async Task TestBulkMapping() + { + using (CultureHelper.Use("en-us")) + { + var translations = await _multiLingualObjectManager.GetBulkTranslationsAsync(_books); + var translationsDict = translations.ToDictionary(x => x.entity.Id, x => x.translation); + var mapped = _mapperAccessor.Mapper.Map, List>(_books, options => + { + options.Items.Add(nameof(MultiLingualBookTranslation), translationsDict); + }); + Assert.Equal(mapped.Count, _books.Count); + for (int i = 0; i < mapped.Count; i++) + { + var og = _books[i]; + var m = mapped[i]; + Assert.Equal(og.Translations.FirstOrDefault(x => x.Language == "en")?.Name, m.Name); + } + } + } } diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectTestProfile.cs b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectTestProfile.cs new file mode 100644 index 0000000000..89cc9a51b7 --- /dev/null +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/MultiLingualObjectTestProfile.cs @@ -0,0 +1,23 @@ +namespace Volo.Abp.MultiLingualObjects; + +using System; +using System.Collections.Generic; +using global::AutoMapper; +using Volo.Abp.MultiLingualObjects.TestObjects; + +public class MultiLingualObjectTestProfile : Profile +{ + public MultiLingualObjectTestProfile() + { + CreateMap() + .ForMember(x => x.Name, + x => x.MapFrom((src, target, member, context) => + { + if (context.Items.TryGetValue(nameof(MultiLingualBookTranslation), out var translationsRaw) && translationsRaw is IReadOnlyDictionary translations) + { + return translations.GetValueOrDefault(src.Id)?.Name; + } + return null; + })); + } +} diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBook.cs b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBook.cs index 92a295e0c5..3b880f48f2 100644 --- a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBook.cs +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBook.cs @@ -1,19 +1,19 @@ -using System; -using System.Collections.Generic; - -namespace Volo.Abp.MultiLingualObjects.TestObjects; - -public class MultiLingualBook : IMultiLingualObject -{ - public MultiLingualBook(Guid id, decimal price) - { - Id = id; - Price = price; - } - - public Guid Id { get; } - - public decimal Price { get; set; } - - public ICollection Translations { get; set; } -} +using System; +using System.Collections.Generic; + +namespace Volo.Abp.MultiLingualObjects.TestObjects; + +public class MultiLingualBook : IMultiLingualObject +{ + public MultiLingualBook(Guid id, decimal price) + { + Id = id; + Price = price; + } + + public Guid Id { get; } + + public decimal Price { get; set; } + + public ICollection Translations { get; set; } = new List(); +} diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookDto.cs b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookDto.cs index ea7e7e9afd..8d61449961 100644 --- a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookDto.cs +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookDto.cs @@ -1,12 +1,12 @@ -using System; - -namespace Volo.Abp.MultiLingualObjects.TestObjects; - -public class MultiLingualBookDto -{ - public Guid Id { get; set; } - - public string Name { get; set; } - - public decimal Price { get; set; } -} +using System; + +namespace Volo.Abp.MultiLingualObjects.TestObjects; + +public class MultiLingualBookDto +{ + public Guid Id { get; set; } + + public string? Name { get; set; } + + public decimal Price { get; set; } +} diff --git a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookTranslation.cs b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookTranslation.cs index 06cfc33b55..adf482fa17 100644 --- a/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookTranslation.cs +++ b/framework/test/Volo.Abp.MultiLingualObjects.Tests/Volo/Abp/MultiLingualObjects/TestObjects/MultiLingualBookTranslation.cs @@ -1,8 +1,8 @@ -namespace Volo.Abp.MultiLingualObjects.TestObjects; - -public class MultiLingualBookTranslation : IObjectTranslation -{ - public string Name { get; set; } - - public string Language { get; set; } -} +namespace Volo.Abp.MultiLingualObjects.TestObjects; + +public class MultiLingualBookTranslation : IObjectTranslation +{ + public string? Name { get; set; } + + public required string Language { get; set; } +} diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs index 6088984cb9..c482963d75 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs @@ -16,6 +16,7 @@ public class AbpUiNavigationTestModule : AbpModule options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor1()); options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor2()); options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor3()); + options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor4()); options.MainMenuNames.Add(MenuManager_Tests.TestMenuContributor3.MenuName); }); diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs index b27de60c10..421e072b0f 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs @@ -46,7 +46,7 @@ public class MenuManager_Tests : AbpIntegratedTest mainMenu.Name.ShouldBe(StandardMenus.Main); mainMenu.DisplayName.ShouldBe("Main Menu"); - mainMenu.Items.Count.ShouldBe(2); + mainMenu.Items.Count.ShouldBe(5); mainMenu.Items[0].Name.ShouldBe("Dashboard"); mainMenu.Items[1].Name.ShouldBe(DefaultMenuNames.Application.Main.Administration); mainMenu.Items[1].Items[0].Name.ShouldBe("Administration.UserManagement"); @@ -63,12 +63,29 @@ public class MenuManager_Tests : AbpIntegratedTest mainMenu.Name.ShouldBe(StandardMenus.Main); - mainMenu.Items.Count.ShouldBe(3); + mainMenu.Items.Count.ShouldBe(6); mainMenu.Items.ShouldContain(x => x.Name == "Products"); mainMenu.Items.ShouldContain(x => x.Name == "Dashboard"); } + [Fact] + public async Task GetMainMenuAsync_GroupMenuItems() + { + var mainMenu = await _menuManager.GetMainMenuAsync(); + + mainMenu.Name.ShouldBe(StandardMenus.Main); + mainMenu.Items.Count.ShouldBe(6); + + mainMenu.Items[2].GroupName.ShouldBe("Layouts"); + mainMenu.Items[3].GroupName.ShouldBe("Layouts"); + mainMenu.Items[4].GroupName.ShouldBe(null); // No group defined + + var layoutsGroup = mainMenu.GetMenuGroup("Layouts"); + layoutsGroup.Name.ShouldBe("Layouts"); + layoutsGroup.DisplayName.ShouldBe("Layouts"); + } + /* Adds menu items: * - Administration * - User Management @@ -149,4 +166,29 @@ public class MenuManager_Tests : AbpIntegratedTest return Task.CompletedTask; } } + + /* Adds group and menu items: + * - Layouts + * - Toolbars + * - Page Header + */ + public class TestMenuContributor4 : IMenuContributor + { + public Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name != StandardMenus.Main) + { + return Task.CompletedTask; + } + + context.Menu.AddGroup(new ApplicationMenuGroup("Layouts", "Layouts")); + + context.Menu.AddItem(new ApplicationMenuItem("Toolbars", "Toolbars", url: "/layouts/toolbars", groupName: "Layouts")); + context.Menu.AddItem(new ApplicationMenuItem("PageHeader", "Page Header", url: "/layouts/page-header", groupName: "Layouts")); + + context.Menu.AddItem(new ApplicationMenuItem("Branding", "Branding", url: "/layouts/branding", groupName: "NotDefinedGroup")); + + return Task.CompletedTask; + } + } } diff --git a/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs b/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs index 535e9fb613..f58b000af4 100644 --- a/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs +++ b/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs @@ -201,7 +201,7 @@ public class ApplicationService_Validation_Tests : AbpIntegratedTest + context.Services.OnRegistered(onServiceRegistredContext => { if (typeof(IMyAppService).IsAssignableFrom(onServiceRegistredContext.ImplementationType) && !DynamicProxyIgnoreTypes.Contains(onServiceRegistredContext.ImplementationType)) diff --git a/latest-versions.json b/latest-versions.json index afd4f0f8a4..1e1ceca763 100644 --- a/latest-versions.json +++ b/latest-versions.json @@ -1,8 +1,8 @@ [ { - "version": "7.0.2", + "version": "7.1.0", "releaseDate": "", "type": "stable", "message": "" } -] \ No newline at end of file +] diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json index f074deeabd..027928ead3 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json @@ -14,7 +14,7 @@ "SelfRegistrationDisabledMessage": "Itserekisteröinti on poistettu käytöstä tälle sovellukselle. Rekisteröi uusi käyttäjä ottamalla yhteyttä sovelluksen järjestelmänvalvojaan.", "LocalLoginDisabledMessage": "Paikallinen sisäänkirjautuminen on poistettu käytöstä tälle sovellukselle.", "Login": "Kirjaudu sisään", - "Cancel": "Peruuttaa", + "Cancel": "Peruuta", "Register": "Rekisteröidy", "AreYouANewUser": "Oletko uusi käyttäjä?", "AlreadyRegistered": "Jo rekisteröity?", @@ -34,6 +34,8 @@ "DisplayName:PhoneNumber": "Puhelinnumero", "PersonalSettings": "Henkilökohtaiset asetukset", "PersonalSettingsSaved": "Henkilökohtaiset asetukset tallennettu", + "PersonalSettingsChangedConfirmationModalTitle": "Henkilötiedot muuttuneet", + "PersonalSettingsChangedConfirmationModalDescription": "Jos haluat ottaa nämä muutokset käyttöön, sinun on kirjauduttava uudelleen sisään. Haluatko kirjautua nyt ulos?", "PasswordChanged": "Salasana vaihdettu", "NewPasswordConfirmFailed": "Vahvista uusi salasana.", "NewPasswordSameAsOld": "Uusi salasana ei voi olla sama kuin vanha salasana.", @@ -43,8 +45,8 @@ "Description:Abp.Account.IsSelfRegistrationEnabled": "Voiko käyttäjä rekisteröidä tilin itse.", "DisplayName:Abp.Account.EnableLocalLogin": "Todennus paikallisella tilillä", "Description:Abp.Account.EnableLocalLogin": "Ilmaisee, salliko palvelin käyttäjien todentamisen paikallisella tilillä.", - "LoggedOutTitle": "Kirjautui ulos", - "LoggedOutText": "Sinut on kirjautunut ulos ja sinut ohjataan pian.", + "LoggedOutTitle": "Kirjauduttu ulos", + "LoggedOutText": "Sinut on kirjattu ulos ja sinut ohjataan pian takaisin sovellukseen.", "ReturnToText": "Napsauta tätä ja ohjaa uudelleen osoitteeseen {0}", "OrLoginWith": "Tai kirjaudu sisään:", "ForgotPassword": "Unohtuiko salasana?", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json index 37c8177620..1cfabd4d62 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json @@ -34,6 +34,8 @@ "DisplayName:PhoneNumber": "手机号码", "PersonalSettings": "个人设置", "PersonalSettingsSaved": "个人设置已保存", + "PersonalSettingsChangedConfirmationModalTitle": "个人信息已更改", + "PersonalSettingsChangedConfirmationModalDescription": "重新登录以应用这些更改,您要退出登录吗?", "PasswordChanged": "修改密码", "NewPasswordConfirmFailed": "请确认新密码", "NewPasswordSameAsOld": "新密码不能与旧密码相同", @@ -66,4 +68,4 @@ "AccessDenied": "拒绝访问!", "AccessDeniedMessage": "你无权访问此资源." } -} +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json index 4a13985c8a..8749163c1d 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json @@ -3,16 +3,16 @@ "texts": { "Menu:Account": "帳號", "UserName": "使用者名稱", - "EmailAddress": "電子信箱地址", - "UserNameOrEmailAddress": "使用者名稱或電子信箱地址", + "EmailAddress": "電子郵件地址", + "UserNameOrEmailAddress": "使用者名稱或電子郵件地址", "Password": "密碼", "RememberMe": "記住我", "UseAnotherServiceToLogin": "使用另一個服務登入", "UserLockedOutMessage": "登入失敗,使用者帳號已被鎖定.請稍後再試.", "InvalidUserNameOrPassword": "使用者名稱或密碼錯誤!", - "LoginIsNotAllowed": "無法登入!你的賬號未激活或者需要驗證郵箱地址/手機號碼.", + "LoginIsNotAllowed": "無法登入!你的帳號未啟用或者需要驗證電子郵件地址/手機號碼.", "SelfRegistrationDisabledMessage": "應用程式未開放註冊,請聯絡管理員以加入新使用者.", - "LocalLoginDisabledMessage": "應用程序未開放本地賬戶登錄.", + "LocalLoginDisabledMessage": "應用程式未開放本地帳戶登入.", "Login": "登入", "Cancel": "取消", "Register": "註冊", @@ -26,11 +26,11 @@ "DisplayName:NewPasswordConfirm": "確認新密碼", "PasswordChangedMessage": "你的密碼已修改成功.", "DisplayName:UserName": "使用者名稱", - "DisplayName:Email": "電子信箱", + "DisplayName:Email": "電子郵件信箱", "DisplayName:Name": "名字", "DisplayName:Surname": "姓", "DisplayName:Password": "密碼", - "DisplayName:EmailAddress": "電子信箱地址", + "DisplayName:EmailAddress": "電子郵件地址", "DisplayName:PhoneNumber": "電話號碼", "PersonalSettings": "個人設置", "PersonalSettingsSaved": "個人設置已保存", @@ -38,32 +38,32 @@ "NewPasswordConfirmFailed": "請確認新密碼", "NewPasswordSameAsOld": "新密碼不能與舊密碼相同", "Manage": "管理", - "MyAccount": "我的賬戶", + "MyAccount": "我的帳戶", "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "啟用自行註冊", "Description:Abp.Account.IsSelfRegistrationEnabled": "是否允許使用者自行註冊帳號.", "DisplayName:Abp.Account.EnableLocalLogin": "使用本地帳號進行身分驗證", "Description:Abp.Account.EnableLocalLogin": "伺服器是否允許使用者使用本地帳號進行身份驗證。", "LoggedOutTitle": "註銷", "LoggedOutText": "你已成功註銷並將馬上返回.", - "ReturnToText": "單擊此處返回到應用程序", + "ReturnToText": "點擊此處返回到應用程式", "OrLoginWith": "或是登入用:", "ForgotPassword": "忘記密碼?", - "SendPasswordResetLink_Information": "密碼重置鏈接將發送到您的電子郵件以重置密碼. 如果您在幾分鐘內沒有收到電子郵件,請重試.", + "SendPasswordResetLink_Information": "密碼重置連結將發送到您的電子郵件以重置密碼. 如果您在幾分鐘內沒有收到電子郵件,請重試.", "PasswordResetMailSentMessage": "帳戶恢復電子郵件已發送到您的電子郵件地址. 如果您在15分鐘內未在收件箱中看到此電子郵件,請檢查垃圾郵件,並標記為非垃圾郵件.", "ResetPassword": "重設密碼", "ConfirmPassword": "確認密碼", "ResetPassword_Information": "請輸入您的新密碼.", "YourPasswordIsSuccessfullyReset": "您的密碼已經被重置成功.", - "GoToTheApplication": "轉到應用程序", - "BackToLogin": "返回登錄", + "GoToTheApplication": "轉到應用程式", + "BackToLogin": "返回登入", "ProfileTab:Password": "更改密碼", - "ProfileTab:PersonalInfo": "個人信息", - "ReturnToApplication": "返回到應用程序", + "ProfileTab:PersonalInfo": "個人資訊", + "ReturnToApplication": "返回到應用程式", "Volo.Account:InvalidEmailAddress": "找不到給定的電子郵件地址:{0}", "PasswordReset": "重設密碼", - "PasswordResetInfoInEmail": "我們收到了帳戶恢復請求!如果你發起了此請求,請單擊以下鏈接以重置密碼.", + "PasswordResetInfoInEmail": "我們收到了帳戶恢復請求!如果你發起了此請求,請點擊以下連結以重置密碼.", "ResetMyPassword": "重置我的密碼", "AccessDenied": "拒絕訪問!", "AccessDeniedMessage": "您無權訪問此資源." } -} \ No newline at end of file +} diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs index 1920cdd8ad..ce1ecd0e82 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs @@ -1,6 +1,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Account.Settings; using Volo.Abp.Identity; +using Volo.Abp.Settings; namespace Volo.Abp.Account.Web.Pages.Account; @@ -28,7 +30,12 @@ public class LogoutModel : AccountPageModel return RedirectSafely(ReturnUrl, ReturnUrlHash); } - return RedirectToPage("/Account/Login"); + if (await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin)) + { + return RedirectToPage("/Account/Login"); + } + + return RedirectToPage("/"); } public virtual Task OnPostAsync() 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 e39ce6a00f..285cc214e1 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 @@ -6,8 +6,8 @@ "Menu:AuditLogging": "Tarkastuslokit", "AuditLogs": "Tarkastuslokit", "HttpStatus": "Http-tila", - "HttpMethod": "Http-menetelmä", - "HttpMethodFilter": "Http-menetelmän suodatin", + "HttpMethod": "Http-metodi", + "HttpMethodFilter": "Http-metodin suodatin", "HttpRequest": "Http-pyyntö", "User": "Käyttäjä", "UserNameFilter": "Käyttäjäsuodatin", @@ -32,33 +32,34 @@ "HttpStatusCode": "Http-tilakoodi", "HttpStatusCodeFilter": "Http-tilakoodisuodatin", "ServiceName": "Palvelu", - "MethodName": "Menetelmä", + "MethodName": "Metodi", "CorrelationId": "Korrelaatiotunnus", - "ApplicationName": "sovelluksen nimi", + "ApplicationName": "Sovelluksen nimi", "ExecutionDuration": "Kesto", "ExtraProperties": "Lisäominaisuudet", "MaxDuration": "Maks. Kesto", "MinDuration": "Min. Kesto", + "MinMaxDuration": "Kesto (Min. - Max.)", "{0}Milliseconds": "{0} millisekuntia", "ExecutionTime": "Aika", "Parameters": "Parametrit", - "EntityTypeFullName": "Yhteisön tyyppi Koko nimi", + "EntityTypeFullName": "Entiteetin tyyppi Koko nimi", "Entity": "Entiteetti", "ChangeType": "Vaihda tyyppiä", "ChangeTime": "Aika", "NewValue": "Uusi arvo", "OriginalValue": "Alkuperäinen arvo", - "PropertyName": "Kiinteistön nimi", - "PropertyTypeFullName": "Kiinteistötyyppi Koko nimi", - "Yes": "Joo", + "PropertyName": "Ominaisuuden nimi", + "PropertyTypeFullName": "Ominaisuustyyppi Koko nimi", + "Yes": "Kyllä", "No": "Ei", "Changes": "Muutokset", "AverageExecutionDurationInLogsPerDay": "Keskimääräinen suorituksen kesto", "AverageExecutionDurationInMilliseconds": "Keskimääräinen suorituksen kesto millisekunteina", "ErrorRateInLogs": "Virheprosentti lokeissa", - "Success": "Menestys", - "Fault": "Vika", - "NoChanges": "Ei muutoksia)", + "Success": "Onnistui", + "Fault": "Virhe", + "NoChanges": "Ei muutoksia", "EntityChanges": "Entiteetin muutokset", "EntityId": "Entiteetin tunnus", "EntityChangeStartTime": "Pienin muutospäivä", 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 e634ef3511..1c782932a4 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 @@ -39,6 +39,7 @@ "ExtraProperties": "额外属性", "MaxDuration": "最大持续时间", "MinDuration": "最小持续时间", + "MinMaxDuration": "持续时间(最小-最大)", "{0}Milliseconds": "{0} 毫秒", "ExecutionTime": "时间", "Parameters": "参数", diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs index 5f2c23ceb4..244063d37f 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.HangFire/Program.cs @@ -1,23 +1,40 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Hangfire; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.DemoApp.HangFire; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => + { + options.UseAutofac(); + })) { - options.UseAutofac(); - })) - { - application.Initialize(); + await application.InitializeAsync(); + + await CancelableBackgroundJobAsync(application.ServiceProvider); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } + + private async static Task CancelableBackgroundJobAsync(IServiceProvider serviceProvider) + { + var backgroundJobManager = serviceProvider.GetRequiredService(); + var jobId = await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-1" }); + await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-2" }); + Thread.Sleep(1000); + BackgroundJob.Delete(jobId); + } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs index 1ececcd621..eebe5fa279 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Program.cs @@ -1,23 +1,41 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs; +using Volo.Abp.Threading; namespace Volo.Abp.BackgroundJobs.DemoApp.Quartz; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.UseAutofac(); })) { - application.Initialize(); + await application.InitializeAsync(); + + await CancelableBackgroundJobAsync(application.ServiceProvider); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } + + private async static Task CancelableBackgroundJobAsync(IServiceProvider serviceProvider) + { + var backgroundJobManager = serviceProvider.GetRequiredService(); + var jobId = await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs {Value = "test-1"}); + await backgroundJobManager.EnqueueAsync(new LongRunningJobArgs { Value = "test-2" }); + Thread.Sleep(1000); + var scheduler = serviceProvider.GetRequiredService(); + await scheduler.Interrupt(new JobKey(jobId.Split('.')[1],jobId.Split('.')[0])); + } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs index 5d04169c15..a07a0498f9 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.RabbitMq/Program.cs @@ -1,23 +1,24 @@ using System; +using System.Threading.Tasks; namespace Volo.Abp.BackgroundJobs.DemoApp.RabbitMq; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.UseAutofac(); })) { - application.Initialize(); + await application.InitializeAsync(); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs new file mode 100644 index 0000000000..9a57331fff --- /dev/null +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJob.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs +{ + public class LongRunningJob : BackgroundJob, ITransientDependency + { + private readonly ICancellationTokenProvider _cancellationTokenProvider; + + public LongRunningJob(ICancellationTokenProvider cancellationTokenProvider) + { + _cancellationTokenProvider = cancellationTokenProvider; + } + + public override void Execute(LongRunningJobArgs args) + { + lock (Console.Out) + { + var oldColor = Console.ForegroundColor; + try + { + Console.WriteLine($"Long running {args.Value} start: {DateTime.Now}"); + + for (var i = 1; i <= 10; i++) + { + _cancellationTokenProvider.Token.ThrowIfCancellationRequested(); + + Thread.Sleep(1000); + Console.WriteLine($"{args.Value} step-{i} done: {DateTime.Now}"); + } + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"Long running {args.Value} completed: {DateTime.Now}"); + } + catch (OperationCanceledException) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Long running {args.Value} cancelled!!!"); + } + finally + { + Console.ForegroundColor = oldColor; + } + } + } + } +} \ No newline at end of file diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs new file mode 100644 index 0000000000..fabba0fa57 --- /dev/null +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/LongRunningJobArgs.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs +{ + [BackgroundJobName("LongJob")] + public class LongRunningJobArgs + { + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs index e065e409e5..5e5c00a97d 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleGreenJob.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs index a610b6e75a..dbeae26552 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp.Shared/Jobs/WriteToConsoleYellowJob.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs index a909fb476e..976705b07d 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/DemoAppModule.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Autofac; +using System.Threading.Tasks; +using Volo.Abp.Autofac; using Volo.Abp.BackgroundJobs.DemoApp.Shared; using Volo.Abp.BackgroundJobs.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -27,19 +28,21 @@ public class DemoAppModule : AbpModule Configure(options => { - //Configure for fast running - options.JobPollPeriod = 1000; + //Configure for fast running + options.JobPollPeriod = 1000; options.DefaultFirstWaitDuration = 1; options.DefaultWaitFactor = 1; }); } - public override void OnApplicationInitialization(ApplicationInitializationContext context) + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { //TODO: Configure console logging //context // .ServiceProvider // .GetRequiredService() // .AddConsole(LogLevel.Debug); + + return Task.CompletedTask; } } diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs index f895e7adbb..f8fa05863d 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Program.cs @@ -1,23 +1,23 @@ using System; - +using System.Threading.Tasks; namespace Volo.Abp.BackgroundJobs.DemoApp; class Program { - static void Main(string[] args) + async static Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.UseAutofac(); })) { - application.Initialize(); + await application.InitializeAsync(); Console.WriteLine("Started: " + typeof(Program).Namespace); Console.WriteLine("Press ENTER to stop the application..!"); Console.ReadLine(); - application.Shutdown(); + await application.ShutdownAsync(); } } } diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor index b3ecb41862..1f469a809a 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor @@ -13,7 +13,7 @@ { } - else if (url != null) + else if (MenuItem.Url != null) { public bool IsRecaptchaEnabled { get; set; } + + /// + /// Indicates the allowed external URLs by entity types, which can be included in a comment. + /// + public Dictionary> AllowedExternalUrls { get; set; } = new(); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index d4a32c194f..2f7d8ce13d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -214,6 +214,9 @@ "Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.", "DeleteBlogPostMessage": "The blog will be deleted. Are you sure?", "CaptchaCode": "Captcha code", - "CommentTextRequired": "Comment is required" + "CommentTextRequired": "Comment is required", + "CaptchaCodeErrorMessage" : "The answer you entered for the CAPTCHA was not correct. Please try again", + "CaptchaCodeMissingMessage": "The captcha code is missing!", + "UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL." } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json index 438818cdfb..48f961cd71 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json @@ -35,17 +35,17 @@ "CoverImage": "Kansikuva", "CreateBlogPostPage": "Uusi blogiviesti", "CreationTime": "Luomisaika", - "Delete": "Poistaa", + "Delete": "Poista", "Detail": "Yksityiskohta", "Details": "Yksityiskohdat", "DisplayName": "Näyttönimi", "DoYouPreferAdditionalEmails": "Haluatko mieluummin lisää sähköposteja?", - "Edit": "Muokata", + "Edit": "Muokkaa", "EndDate": "Päättymispäivä", "EntityId": "Entiteetin tunnus", "EntityType": "Entiteetin tyyppi", "ExportCSV": "Vie CSV", - "Features": "ominaisuudet", + "Features": "Ominaisuudet", "GenericDeletionConfirmationMessage": "Haluatko varmasti poistaa kohteen {0}?", "IsActive": "Aktiivinen", "LastModification": "Viimeisin muokkaus", @@ -77,58 +77,64 @@ "Pages": "Sivut", "PageSlugInformation": "Etanaa käytetään URL-osoitteessa. URL-osoitteesi on '/{{slug}}'.", "Permission:BlogManagement": "Blogin hallinta", - "Permission:BlogManagement.Create": "Luoda", - "Permission:BlogManagement.Delete": "Poistaa", - "Permission:BlogManagement.Features": "ominaisuudet", - "Permission:BlogManagement.Update": "Päivittää", + "Permission:BlogManagement.Create": "Luonti", + "Permission:BlogManagement.Delete": "Poisto", + "Permission:BlogManagement.Features": "Ominaisuudet", + "Permission:BlogManagement.Update": "Päivitys", "Permission:BlogPostManagement": "Blogiviestien hallinta", - "Permission:BlogPostManagement.Create": "Luoda", - "Permission:BlogPostManagement.Delete": "Poistaa", - "Permission:BlogPostManagement.Update": "Päivittää", + "Permission:BlogPostManagement.Create": "Luonti", + "Permission:BlogPostManagement.Delete": "Poisto", + "Permission:BlogPostManagement.Update": "Päivitys", + "Permission:BlogPostManagement.Publish": "Julkaisu", "Permission:CmsKit": "CmsKit", "Permission:Comments": "Kommenttien hallinta", - "Permission:Comments.Delete": "Poistaa", + "Permission:Comments.Delete": "Poisto", "Permission:Contents": "Sisällön hallinta", "Permission:Contents.Create": "Luo sisältöä", - "Permission:Contents.Delete": "Poista sisältö", - "Permission:Contents.Update": "Päivitä sisältö", + "Permission:Contents.Delete": "Poista sisältöä", + "Permission:Contents.Update": "Päivitä sisältöä", "Permission:MediaDescriptorManagement": "Median hallinta", - "Permission:MediaDescriptorManagement:Create": "Luoda", - "Permission:MediaDescriptorManagement:Delete": "Poistaa", + "Permission:MediaDescriptorManagement:Create": "Luonti", + "Permission:MediaDescriptorManagement:Delete": "Poisto", "Permission:MenuItemManagement": "Valikkokohteiden hallinta", - "Permission:MenuItemManagement.Create": "Luoda", - "Permission:MenuItemManagement.Delete": "Poistaa", - "Permission:MenuItemManagement.Update": "Päivittää", + "Permission:MenuItemManagement.Create": "Luonti", + "Permission:MenuItemManagement.Delete": "Poisto", + "Permission:MenuItemManagement.Update": "Päivitys", "Permission:MenuManagement": "Valikon hallinta", - "Permission:MenuManagement.Create": "Luoda", - "Permission:MenuManagement.Delete": "Poistaa", - "Permission:MenuManagement.Update": "Päivittää", + "Permission:MenuManagement.Create": "Luonti", + "Permission:MenuManagement.Delete": "Poisto", + "Permission:MenuManagement.Update": "Päivitys", "Permission:Menus": "Valikon hallinta", - "Permission:Menus.Create": "Luoda", - "Permission:Menus.Delete": "Poistaa", - "Permission:Menus.Update": "Päivittää", + "Permission:Menus.Create": "Luonti", + "Permission:Menus.Delete": "Poisto", + "Permission:Menus.Update": "Päivitys", "Permission:PageManagement": "Sivun hallinta", - "Permission:PageManagement:Create": "Luoda", - "Permission:PageManagement:Delete": "Poistaa", - "Permission:PageManagement:Update": "Päivittää", + "Permission:PageManagement:Create": "Luonti", + "Permission:PageManagement:Delete": "Poisto", + "Permission:PageManagement:Update": "Päivitys", + "Permission:PageManagement:SetAsHomePage": "Aseta kotisivuksi", "Permission:TagManagement": "Tagien hallinta", - "Permission:TagManagement.Create": "Luoda", - "Permission:TagManagement.Delete": "Poistaa", - "Permission:TagManagement.Update": "Päivittää", + "Permission:TagManagement.Create": "Luonti", + "Permission:TagManagement.Delete": "Poisto", + "Permission:TagManagement.Update": "Päivitys", + "Permission:GlobalResources": "Globaalit resurssit", + "Permission:CmsKitPublic": "CmsKit Julkinen", + "Permission:Comments.DeleteAll": "Poista kaikki", "PickYourReaction": "Valitse reaktio", "Rating": "Luokitus", "RatingUndoMessage": "Arviosi kumotaan.", "Reactions": "Reaktiot", - "Read": "Lukea", + "Read": "Lue", "RepliesToThisComment": "Vastaukset tähän kommenttiin", "Reply": "Vastaa", - "ReplyTo": "Vastata", + "ReplyTo": "Vastaa", "SamplePageMessage": "Esimerkkisivu Pro-moduulille", "SaveChanges": "Tallenna muutokset", "Script": "Skripti", "SelectAll": "Valitse kaikki", - "Send": "Lähettää", + "Send": "Lähetä", "SendMessage": "Lähetä viesti", + "SelectedAuthor": "Tekijä", "ShortDescription": "Lyhyt kuvaus", "Slug": "Etana", "Source": "Lähde", @@ -147,17 +153,69 @@ "ThankYou": "Kiitos", "Title": "Otsikko", "Undo": "Kumoa", - "Update": "Päivittää", + "Update": "Päivitä", "UpdatePreferenceSuccessMessage": "Asetuksesi on tallennettu.", "UpdateYourEmailPreferences": "Päivitä sähköpostiasetuksesi", "UnMakeMainMenu": "Poista päävalikko", "UploadFailedMessage": "Lataus epäonnistui.", "UserId": "Käyttäjätunnus", - "Username": "Käyttäjätunnus", + "Username": "Käyttäjänimi", "YourComment": "Kommenttisi", "YourEmailAddress": "Sähköpostiosoitteesi", "YourFullName": "Koko nimesi", "YourMessage": "Viestisi", - "YourReply": "Sinun vastauksesi" + "YourReply": "Sinun vastauksesi", + "MarkdownSupported": "Markdown tuettu.", + "GlobalResources": "Globaalit resurssit", + "SavedSuccessfully": "Tallennettu onnistuneesti", + "CmsKit.BlogPost.Status.0": "Luonnos", + "CmsKit.BlogPost.Status.1": "Julkaistu", + "CmsKit.BlogPost.Status.2": "Odottaa tarkastusta", + "BlogPostPublishConfirmationMessage": "Haluatko varmasti julkaista blogitekstin \"{0}\"?", + "SuccessfullyPublished": "Onnistuneesti julkaistu!", + "Draft": "Luonnos", + "Publish": "Julkaise", + "BlogPostDraftConfirmationMessage": "Oletko varma, että asetat blogitekstin \"{0}\" luonnokseksi?", + "BlogPostSendToReviewConfirmationMessage": "Oletko varma, että lähetät blogitekstin \"{0}\" järjestelmänvalvojan tarkistettavaksi julkaistavaksi?", + "SaveAsDraft": "Tallenna luonnoksena", + "SendToReview": "Lähetä arvosteluun", + "SendToReviewToPublish": "Lähetä arvosteluun julkaistavaksi", + "BlogPostSendToReviewSuccessMessage": "Blogiviesti \"{0}\" on lähetetty järjestelmänvalvojan tarkistettavaksi julkaistavaksi.", + "HasBlogPostWaitingForReviewMessage": "Sinulla on blogikirjoitus, joka odottaa tarkistusta. Napsauta listataksesi.", + "SelectAStatus": "Valitse tila", + "Status": "Tila", + "CmsKit.BlogPost.ScrollIndex": "Pikanavigointipalkki blogikirjoituksissa", + "Add": "Lisää", + "AddWidget": "Lisää widget", + "PleaseConfigureWidgets": "Määritä widgetit", + "SelectAnAuthor": "Valitse tekijä", + "InThisDocument": "Tässä asiakirjassa", + "GoToTop": "Mene alkuun", + "SetAsHomePage": "Muuta kotisivun tilaa", + "CompletedSettingAsHomePage": "Aseta kotisivuksi", + "IsHomePage": "On Kotisivu", + "RemovedSettingAsHomePage": "Kotisivun asetus poistettu", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "Blogipostaus", + "Feature:BlogEnableDescription": "CMS Kitin blogikirjoitusjärjestelmä, jonka avulla voit luoda blogeja ja viestejä dynaamisesti sovelluksessa.", + "Feature:CommentEnable": "Kommentointi", + "Feature:CommentEnableDescription": "CMS Kitin kommenttijärjestelmä mahdollistaa kokonaisuuksien, kuten BlogPost, kommentoimisen.", + "Feature:GlobalResourceEnable": "Globaali resursointi", + "Feature:GlobalResourceEnableDescription": "CMS Kitin globaali resurssiominaisuus, jonka avulla voit hallita globaaleja tyylejä ja komentosarjoja.", + "Feature:MenuEnable": "Valikko", + "Feature:MenuEnableDescription": "CMS Kitin dynaaminen valikkojärjestelmä, joka mahdollistaa sovellusvalikoiden lisäämisen/poistamisen dynaamisesti.", + "Feature:PageEnable": "Sivutus", + "Feature:PageEnableDescription": "CMS Kitin sivujärjestelmä, joka mahdollistaa staattisten sivujen luomisen tietyllä URL-osoitteella.", + "Feature:RatingEnable": "Luokitus", + "Feature:RatingEnableDescription": "CMS Kitin luokitusjärjestelmä, jonka avulla käyttäjät voivat arvioida kohteita, kuten BlogPost.", + "Feature:ReactionEnable": "Reaktio", + "Feature:ReactionEnableDescription": "CMS Kitin reaktiojärjestelmä, jonka avulla käyttäjät voivat lähettää reaktioita entiteeteille, kuten BlogPost, Comments jne.", + "Feature:TagEnable": "Merkintä", + "Feature:TagEnableDescription": "CMS Kitin tunnistejärjestelmä, joka mahdollistaa entiteettien, kuten BlogPost, merkitsemisen.", + "DeleteBlogPostMessage": "Blogi poistetaan. Oletko varma?", + "CaptchaCode": "Captcha-koodi", + "CommentTextRequired": "Kommentti vaaditaan", + "CaptchaCodeErrorMessage": "CAPTCHA:lle antamasi vastaus ei ollut oikea. Yritä uudelleen", + "CaptchaCodeMissingMessage": "Captcha-koodi puuttuu!" } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json index b8d5353b82..a827923981 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json @@ -112,11 +112,14 @@ "Permission:PageManagement:Create": "创建", "Permission:PageManagement:Delete": "删除", "Permission:PageManagement:Update": "更新", + "Permission:PageManagement:SetAsHomePage": "设为首页", "Permission:TagManagement": "标签管理", "Permission:TagManagement.Create": "创建", "Permission:TagManagement.Delete": "删除", "Permission:TagManagement.Update": "更新", "Permission:GlobalResources": "全局资源", + "Permission:CmsKitPublic": "CmsKit公共", + "Permission:Comments.DeleteAll": "删除全部", "PickYourReaction": "选择你的回应", "Rating": "评分", "RatingUndoMessage": "您的评分将被撤消", @@ -187,6 +190,32 @@ "PleaseConfigureWidgets": "请配置组件", "SelectAnAuthor": "选择一个作者", "InThisDocument": "在此文档", - "GoToTop": "跳至顶部" + "GoToTop": "跳至顶部", + "SetAsHomePage": "更改首页状态", + "CompletedSettingAsHomePage": "设为首页", + "IsHomePage": "是否为首页", + "RemovedSettingAsHomePage": "删除首页设置", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "博客文章", + "Feature:BlogEnableDescription": "CMS Kit的博客文章系统,允许在应用程序中动态创建博客和文章。", + "Feature:CommentEnable": "评论", + "Feature:CommentEnableDescription": "CMS Kit的评论系统允许对博客文章等实体进行评论。", + "Feature:GlobalResourceEnable": "全局资源", + "Feature:GlobalResourceEnableDescription": "CMS Kit的全局资源功能,允许管理全局样式和脚本。", + "Feature:MenuEnable": "菜单", + "Feature:MenuEnableDescription": "CMS Kit的动态菜单系统,允许动态添加/删除应用程序菜单。", + "Feature:PageEnable": "分页", + "Feature:PageEnableDescription": "CMS Kit的页面系统,允许使用特定URL创建静态页面。", + "Feature:RatingEnable": "评分", + "Feature:RatingEnableDescription": "CMS Kit的评分系统允许用户对博客文章等实体进行评分。", + "Feature:ReactionEnable": "反应", + "Feature:ReactionEnableDescription": "CMS Kit的反应系统允许用户对博客文章、评论等实体发送反应。", + "Feature:TagEnable": "标签", + "Feature:TagEnableDescription": "CMS Kit的标签系统允许对博客文章等实体进行标记。", + "DeleteBlogPostMessage": "是否确认删除博客?", + "CaptchaCode": "验证码", + "CommentTextRequired": "请输入评论", + "CaptchaCodeErrorMessage": "验证码错误,请重试", + "CaptchaCodeMissingMessage": "请输入验证码!" } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/CreateCommentWithParameteresInput.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/CreateCommentWithParametersInput.cs similarity index 92% rename from modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/CreateCommentWithParameteresInput.cs rename to modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/CreateCommentWithParametersInput.cs index 7e156ef375..bfdbd0a95d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/CreateCommentWithParameteresInput.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Comments/CreateCommentWithParametersInput.cs @@ -6,7 +6,7 @@ using Volo.CmsKit.Comments; namespace Volo.CmsKit.Public.Comments; [Serializable] -public class CreateCommentWithParameteresInput +public class CreateCommentWithParametersInput { [Required] [DynamicStringLength(typeof(CommentConsts), nameof(CommentConsts.MaxTextLength))] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs index 05857e5db9..4a7bd8be8c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Security; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Options; +using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Authorization; using Volo.Abp.Data; @@ -23,24 +25,27 @@ namespace Volo.CmsKit.Public.Comments; [RequiresGlobalFeature(typeof(CommentsFeature))] public class CommentPublicAppService : CmsKitPublicAppServiceBase, ICommentPublicAppService { + protected string RegexMarkdownUrlPattern = @"\[[^\]]*\]\((?.*?)\)(?![^\x60]*\x60)"; + protected ICommentRepository CommentRepository { get; } protected ICmsUserLookupService CmsUserLookupService { get; } public IDistributedEventBus DistributedEventBus { get; } protected CommentManager CommentManager { get; } - protected IAuthorizationService AuthorizationService { get; } + + protected CmsKitCommentOptions CmsCommentOptions { get; } public CommentPublicAppService( ICommentRepository commentRepository, ICmsUserLookupService cmsUserLookupService, IDistributedEventBus distributedEventBus, CommentManager commentManager, - IAuthorizationService authorizationService) + IOptionsSnapshot cmsCommentOptions) { CommentRepository = commentRepository; CmsUserLookupService = cmsUserLookupService; DistributedEventBus = distributedEventBus; CommentManager = commentManager; - AuthorizationService = authorizationService; + CmsCommentOptions = cmsCommentOptions.Value; } public virtual async Task> GetListAsync(string entityType, string entityId) @@ -56,6 +61,8 @@ public class CommentPublicAppService : CmsKitPublicAppServiceBase, ICommentPubli [Authorize] public virtual async Task CreateAsync(string entityType, string entityId, CreateCommentInput input) { + CheckExternalUrls(entityType, input.Text); + var user = await CmsUserLookupService.GetByIdAsync(CurrentUser.GetId()); if (input.RepliedCommentId.HasValue) @@ -87,11 +94,12 @@ public class CommentPublicAppService : CmsKitPublicAppServiceBase, ICommentPubli public virtual async Task UpdateAsync(Guid id, UpdateCommentInput input) { var comment = await CommentRepository.GetAsync(id); - if (comment.CreatorId != CurrentUser.GetId()) { throw new AbpAuthorizationException(); } + + CheckExternalUrls(comment.EntityType, input.Text); comment.SetText(input.Text); comment.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp); @@ -148,4 +156,46 @@ public class CommentPublicAppService : CmsKitPublicAppServiceBase, ICommentPubli { return ObjectMapper.Map(comments.Single(c => c.Comment.Id == commentId).Author); } + + private void CheckExternalUrls(string entityType, string text) + { + if (!CmsCommentOptions.AllowedExternalUrls.TryGetValue(entityType, out var allowedExternalUrls)) + { + return; + } + + var matches = Regex.Matches(text, RegexMarkdownUrlPattern, + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + foreach (Match match in matches) + { + if (!match.Success || match.Groups.Count < 2) + { + continue; + } + + var url = NormalizeUrl(match.Groups[1].Value); + if (!IsExternalUrl(url)) + { + continue; + } + + if (!allowedExternalUrls.Any(allowedExternalUrl => + url.Contains(NormalizeUrl(allowedExternalUrl), StringComparison.OrdinalIgnoreCase))) + { + throw new UserFriendlyException(L["UnAllowedExternalUrlMessage"]); + } + } + } + + private static bool IsExternalUrl(string url) + { + return url.StartsWith("https", StringComparison.InvariantCultureIgnoreCase) || + url.StartsWith("http", StringComparison.InvariantCultureIgnoreCase); + } + + private static string NormalizeUrl(string url) + { + return url.Replace("www.", "").RemovePostFix("/"); + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebAutoMapperProfile.cs index 3c44f6fa1c..744d5afbad 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebAutoMapperProfile.cs @@ -8,6 +8,6 @@ public class CmsKitPublicWebAutoMapperProfile : Profile { public CmsKitPublicWebAutoMapperProfile() { - CreateMap(); + CreateMap(); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs index bb2487587b..e10a606826 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs @@ -29,14 +29,14 @@ public class CmsKitPublicCommentsController : AbpController } [HttpPost] - public async Task ValidateAsync([FromBody] CreateCommentWithParameteresInput input) + public async Task ValidateAsync([FromBody] CreateCommentWithParametersInput input) { if (CmsKitCommentOptions.IsRecaptchaEnabled && input.CaptchaToken.HasValue) { SimpleMathsCaptchaGenerator.Validate(input.CaptchaToken.Value, input.CaptchaAnswer); } - var dto = ObjectMapper.Map (input); + var dto = ObjectMapper.Map (input); await CommentPublicAppService.CreateAsync(input.EntityType, input.EntityId, dto); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs index 304cfec687..b1ea42397f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs @@ -121,7 +121,7 @@ public class CommentingViewComponent : AbpViewComponent public string EntityType { get; set; } public string EntityId { get; set; } - + public IEnumerable ReferralLinks { get; set; } public string LoginUrl { get; set; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaException.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaException.cs deleted file mode 100644 index 7914e85b02..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Runtime.Serialization; -using Volo.Abp; - -namespace Volo.CmsKit.Public.Web.Security.Captcha; - -public class CaptchaException : UserFriendlyException -{ - public CaptchaException(string message) : base(message) - { - } - - public CaptchaException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) - { - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs index ef5a30a055..220e24f892 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs @@ -9,6 +9,9 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using Volo.Abp; +using Volo.CmsKit.Localization; +using Microsoft.Extensions.Localization; using Volo.Abp.DependencyInjection; using Color = SixLabors.ImageSharp.Color; using PointF = SixLabors.ImageSharp.PointF; @@ -17,6 +20,12 @@ namespace Volo.CmsKit.Public.Web.Security.Captcha; public class SimpleMathsCaptchaGenerator : ISingletonDependency { + private readonly IStringLocalizer _localizer; + + public SimpleMathsCaptchaGenerator(IStringLocalizer localizer) + { + _localizer = localizer; + } private static Dictionary Session { get; set; } = new Dictionary(); public CaptchaOutput Generate() @@ -74,7 +83,7 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency var request = Session[requestId]; if (request.Output.Result != value) { - throw new CaptchaException("The captcha code doesn't match text on the picture! Please try again."); + throw new UserFriendlyException(_localizer["CaptchaCodeErrorMessage"]); } } @@ -86,7 +95,7 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency } else { - throw new CaptchaException("The captcha code is missing!"); + throw new UserFriendlyException(_localizer["CaptchaCodeMissingMessage"]); } } diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/CmsKitApplicationTestModule.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/CmsKitApplicationTestModule.cs index e20c222a58..e0dba22140 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/CmsKitApplicationTestModule.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/CmsKitApplicationTestModule.cs @@ -1,4 +1,6 @@ -using Volo.Abp.Modularity; +using System.Collections.Generic; +using Volo.Abp.Modularity; +using Volo.CmsKit.Comments; namespace Volo.CmsKit; @@ -8,5 +10,20 @@ namespace Volo.CmsKit; )] public class CmsKitApplicationTestModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.AllowedExternalUrls = new Dictionary> + { + { + "EntityName1", + new List + { + "https://abp.io/" + } + } + }; + }); + } } diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs index d0e698937d..ddd913a93f 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Comments/CommentPublicAppService_Tests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using Shouldly; +using Volo.Abp; using Volo.Abp.Users; using Volo.CmsKit.Public.Comments; using Xunit; @@ -62,6 +63,23 @@ public class CommentPublicAppService_Tests : CmsKitApplicationTestBase }); } + [Fact] + public async Task CreateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed() + { + _currentUser.Id.Returns(_cmsKitTestData.User2Id); + + await Should.ThrowAsync(async () => + await _commentAppService.CreateAsync( + _cmsKitTestData.EntityType1, + _cmsKitTestData.EntityId1, + new CreateCommentInput + { + RepliedCommentId = null, + Text = "[ABP Community](https://community.abp.io/)", //not allowed URL + } + )); + } + [Fact] public async Task UpdateAsync() { @@ -80,6 +98,21 @@ public class CommentPublicAppService_Tests : CmsKitApplicationTestBase comment.Text.ShouldBe("I'm Updated"); }); } + + [Fact] + public async Task UpdateAsync_ShouldThrowUserFriendlyException_If_Url_UnAllowed() + { + _currentUser.Id.Returns(_cmsKitTestData.User1Id); + + await Should.ThrowAsync(async () => + await _commentAppService.UpdateAsync( + _cmsKitTestData.CommentWithChildId, + new UpdateCommentInput + { + Text = "[ABP Community - Update](https://community.abp.io/)", //not allowed URL + } + )); + } [Fact] public async Task DeleteAsync() diff --git a/modules/docs/app/VoloDocs.Web/package.json b/modules/docs/app/VoloDocs.Web/package.json index a02d8d3076..fa8ddd76f4 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": "~7.1.1", - "@abp/docs": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.0-rc.1", + "@abp/docs": "^7.2.0-rc.1" } } diff --git a/modules/docs/app/VoloDocs.Web/yarn.lock b/modules/docs/app/VoloDocs.Web/yarn.lock index 0d1aa6abe8..76a750eea9 100644 --- a/modules/docs/app/VoloDocs.Web/yarn.lock +++ b/modules/docs/app/VoloDocs.Web/yarn.lock @@ -2,47 +2,47 @@ # yarn lockfile v1 -"@abp/anchor-js@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/anchor-js/-/anchor-js-7.1.1.tgz#05a75de61834a37adee91715aba0774062c053ef" - integrity sha512-+VEt2EVYoo9OzlAoiMt3somAEFo6ILIozcnA4L5NcawgZCh51G2ogzqYAKicK8PeeVQSnVLrYCoQubDU7sAEAw== +"@abp/anchor-js@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/anchor-js/-/anchor-js-7.2.0-rc.1.tgz#9aa5a2c17be64073adfc8e144239eb742197455a" + integrity sha512-WQWX+Bbq2k7C97LRidRYwWmQABrOUdKEhYsQreF6A6DTKmktFqNDzwNiNOG5IhrVtjYekON42OMpOTJkUVJPyg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" anchor-js "^4.3.1" -"@abp/aspnetcore.mvc.ui.theme.basic@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-7.1.1.tgz#9368779919662a804a8119ac6cf9b731fa2a9728" - integrity sha512-xMUBHJv9pLWp3wx3Oc6+F4G8biZ+BgCskYzAgV2lLWFjQAUxe8klbP0dsVr0EZemyMctX6zlHLURRIl+Os8Z2Q== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~7.1.1" - -"@abp/aspnetcore.mvc.ui.theme.shared@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-7.1.1.tgz#48cf683b8a147bc5955de5e812a0dfa3b7184f29" - integrity sha512-caHzC5zOr2vXY2QDRKuFQ4qIWOS/DbsJUO+UhfKSHvP/bAv7Cu10K3gHwrbfuNCChDJ9iLK0+oJYXUtYBXRA3g== - dependencies: - "@abp/aspnetcore.mvc.ui" "~7.1.1" - "@abp/bootstrap" "~7.1.1" - "@abp/bootstrap-datepicker" "~7.1.1" - "@abp/bootstrap-daterangepicker" "~7.1.1" - "@abp/datatables.net-bs5" "~7.1.1" - "@abp/font-awesome" "~7.1.1" - "@abp/jquery-form" "~7.1.1" - "@abp/jquery-validation-unobtrusive" "~7.1.1" - "@abp/lodash" "~7.1.1" - "@abp/luxon" "~7.1.1" - "@abp/malihu-custom-scrollbar-plugin" "~7.1.1" - "@abp/moment" "~7.1.1" - "@abp/select2" "~7.1.1" - "@abp/sweetalert2" "~7.1.1" - "@abp/timeago" "~7.1.1" - "@abp/toastr" "~7.1.1" - -"@abp/aspnetcore.mvc.ui@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-7.1.1.tgz#f862b77573b5c34d9b938160669400edbf06154d" - integrity sha512-+xafeXzwnFa4Evak9Wq+jrpimWITio4Yv9WeSbKInNakIPO+wJNBClBneca1XQ+LFy4bMRuqgWYJueUct+E3tA== +"@abp/aspnetcore.mvc.ui.theme.basic@^7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-7.2.0-rc.1.tgz#3d0229c0b30aec8fa64f12becd60a1dce1a5e555" + integrity sha512-ZmKeFcNnicsvNoUWRstfioB0yGRvKlhrUtywI366Ve4eV6uucxTtrZdteGYAhmd41pNHZkQ/SloQLgpqR8Sszg== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~7.2.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-7.2.0-rc.1.tgz#502329f921b809e4ab390d4aca0c67646aa34b9d" + integrity sha512-LhOURgIwBSBg626fnJ8xKnpMfF63Pc8e+JWBQpvWNffLy8LjDeY/GCVTUDGJO2TKvMoYymeCCfzSG4f2EBqtJg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~7.2.0-rc.1" + "@abp/bootstrap" "~7.2.0-rc.1" + "@abp/bootstrap-datepicker" "~7.2.0-rc.1" + "@abp/bootstrap-daterangepicker" "~7.2.0-rc.1" + "@abp/datatables.net-bs5" "~7.2.0-rc.1" + "@abp/font-awesome" "~7.2.0-rc.1" + "@abp/jquery-form" "~7.2.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~7.2.0-rc.1" + "@abp/lodash" "~7.2.0-rc.1" + "@abp/luxon" "~7.2.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~7.2.0-rc.1" + "@abp/moment" "~7.2.0-rc.1" + "@abp/select2" "~7.2.0-rc.1" + "@abp/sweetalert2" "~7.2.0-rc.1" + "@abp/timeago" "~7.2.0-rc.1" + "@abp/toastr" "~7.2.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-7.2.0-rc.1.tgz#97d228aa9e7d817dacda5fdd170a95f5a5fdba7b" + integrity sha512-qmxBqN5LGtgmQnjbrW0hY3gguFvHwdbYfj2b4wnzhlMryo0Z9U1cPtjeVsDN4++ml2oivhybWmY4AzTlNYo9Hw== dependencies: ansi-colors "^4.1.1" extend-object "^1.0.0" @@ -51,194 +51,194 @@ merge-stream "^2.0.0" micromatch "^4.0.2" -"@abp/bootstrap-datepicker@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-7.1.1.tgz#45c9b9086b3a64ce4ba6193320afdf2e81d12136" - integrity sha512-/T2FlMlPV19J70t8yueyxj9k72+4t3b2aVDrNHCf7uPuSqClwVKEylzGr8RFc7VXHZZwwaUrbLhxYkhkCKLuLA== +"@abp/bootstrap-datepicker@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-7.2.0-rc.1.tgz#a625bc18ef6148fd856657b987561c1269780ce9" + integrity sha512-bmAGNhHsKFs/oL/LqpEDCeX4fOzvXXrcjFQcEG4pB1lHPQ0T9bm758f4dwEoT5qZQRBLwShQ7cKbWfCdrnXFTQ== dependencies: bootstrap-datepicker "^1.9.0" -"@abp/bootstrap-daterangepicker@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-7.1.1.tgz#19349099f6c007feef1ebe73c9c1059f8d271bc1" - integrity sha512-pCTiPRNW4gnzo0rWKbu2A52dRUeXRI3MqJW7h46yNk4n1ZrnsmwH6/b/ebp89YlbNXWaatDrEpk3NbqxSDDAdQ== +"@abp/bootstrap-daterangepicker@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-7.2.0-rc.1.tgz#5bfc4272efe98e3ce50da1a00f45c3050a19b0a1" + integrity sha512-dbI3nYhDRyvANGjNiZESs3Isfo0ai3xV1IaVzUwxRy90HDS2JupocXEXOMOnXs0+r05xYyl0/uXwVdtUQKFJ+w== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-7.1.1.tgz#1481b984a7f31f92f262d6957340fcaa87eb8ece" - integrity sha512-qFNLuBExQeVDOlFKP/STa3r+8CHhPUfsOFnPaknkS2QLewmtAZw3BJFEgvpJQkSvQdaBXW+EjutaJiFGdDrkEQ== +"@abp/bootstrap@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-7.2.0-rc.1.tgz#b87e8734492980377487bd775e7e5a75af64ac5b" + integrity sha512-4tOOusawRhVUttSQrSnhMeoZnuGbK3kV0QhitLgfqckvexo9mRtzDFSdpq/0W7/9gO7B3zdajToASMNcOdmSnQ== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" bootstrap "^5.1.3" -"@abp/clipboard@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-7.1.1.tgz#06985266e399a03f819585ec9b9ae17ffcbfef0b" - integrity sha512-IxlQJgNlhp6hMVAkPqRgzmB0a5bKdrZ0whVlaxNKR42geetutV+5KPo/koCmliksHLAFTfiAedQXOXsJ90p2AQ== +"@abp/clipboard@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-7.2.0-rc.1.tgz#d559d426b146ef519441021eafa74ea29e7393d9" + integrity sha512-t5Ik/9g+K4vQzvyk8C5duLvX6v0j5zFKs2QEWX3WXhwK+j1aOP8wSA8S5AKb0VHoGCTiqxzpdgcePv/sXh3t1w== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" clipboard "^2.0.8" -"@abp/core@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-7.1.1.tgz#de4d666d26fba4ab5f7b3e6fff38f2f5f034d121" - integrity sha512-d/vHAAU60v6gdH3+VpchXDD1l5yXNmKsb3i92gvG9M0orjgVy3dJmb6zBVw50nnZxNSfq3Z0S1TC/QdA2C1rQg== +"@abp/core@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-7.2.0-rc.1.tgz#edc1f7188d15fc6e62385576d34ea2e0c2f6afbd" + integrity sha512-KkLelSvFpOFxmzCQ+1cs3e6hd69IstqRH+5j5lnTASZtVMro86NB2RoqsAdmSDDG8SoHA2TzZpki56jo8ji6Yg== dependencies: - "@abp/utils" "~7.1.1" + "@abp/utils" "~7.2.0-rc.1" -"@abp/datatables.net-bs5@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-7.1.1.tgz#b7058a0cad4119cc7391493a7d148250efc41b72" - integrity sha512-uPqHzfE9dH5nEuocvIduQYcjEa4MwBXMjtnY5tHM+PK2yB8DsDOrXVopOX0YPTgFk49pLvOVbgxsftuyPb3xKQ== +"@abp/datatables.net-bs5@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-7.2.0-rc.1.tgz#4e204d44642f072320bc1ef83025b8dc579bfcfa" + integrity sha512-qVK/kTe9sf/1NZM2K3ixpwf/bBm1q2eogqygqBO7WeiA0UCXWu92WZ0cIKUeYCumKKsMbb/D3lX3FGIgqFqhkw== dependencies: - "@abp/datatables.net" "~7.1.1" + "@abp/datatables.net" "~7.2.0-rc.1" datatables.net-bs5 "^1.11.4" -"@abp/datatables.net@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-7.1.1.tgz#a84975c8ab0d7406e524d2eae41f7a04bc00f13c" - integrity sha512-eKIxvap/bKc1G7Dev+t9V8HvHWQYza0Y4RdYmC0bPOyRthlTW9AH8jyKK5HtJlpNpj9rjB2jy3/I9D1uzD67QQ== +"@abp/datatables.net@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-7.2.0-rc.1.tgz#e3aa60d69ffb27c96da9469543ce0f0c48f3e312" + integrity sha512-LnIwvU2m9JEtKdILQkQLobVSCik4VcIuYDuUq60TqgRtC2TBYbsX5Ngtp5LoUkJ+1O7PNF/aKkx92H55X27ZsA== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" datatables.net "^1.11.4" -"@abp/docs@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/docs/-/docs-7.1.1.tgz#1b36128d2034c616d55d48b0f3088f2207a3c1ba" - integrity sha512-43kie3W1nAdsgi624+CQ/cpsizgsSkw0ev2HH0OMoWWszuEar6SdDX8jdLqdUrraNycXFAtbybYmpHgmX0TLqg== +"@abp/docs@^7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/docs/-/docs-7.2.0-rc.1.tgz#513740d884741b44906c8849d4ea3143c0812d80" + integrity sha512-yjPNrrb/qQ1o7X0yGjmet4lR57wedhTiLrL2w/YuVXtsOuY2pvasvaoljc0rBnl2NJAy1XPOgtdxCZu2QVOvUg== dependencies: - "@abp/anchor-js" "~7.1.1" - "@abp/clipboard" "~7.1.1" - "@abp/malihu-custom-scrollbar-plugin" "~7.1.1" - "@abp/popper.js" "~7.1.1" - "@abp/prismjs" "~7.1.1" + "@abp/anchor-js" "~7.2.0-rc.1" + "@abp/clipboard" "~7.2.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~7.2.0-rc.1" + "@abp/popper.js" "~7.2.0-rc.1" + "@abp/prismjs" "~7.2.0-rc.1" -"@abp/font-awesome@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-7.1.1.tgz#da4a0be295b0acf9b62d8299d1c567ae192a320f" - integrity sha512-AVjbSFXj5IzzQwqwP/fgsuRG1NzV6/KGn5owsfn6HeKSOBjqW4h4EGyunMNoAOW4fsdFxvE4zjBpsG1/E9tuQg== +"@abp/font-awesome@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-7.2.0-rc.1.tgz#80d7915ff756b8f569de95322f607a8fa47ace00" + integrity sha512-829G90oNOxZyHRIPkZUtxBTkwLMhkourDQOZTvLV0c/IQzMdSEuU4VW5BZ4QdrVJrWJ5pPn/uFhbM7R7viskJg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" "@fortawesome/fontawesome-free" "^5.15.4" -"@abp/jquery-form@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-7.1.1.tgz#03c17ccb19820e0a56be58275e2ebba7e7ebaa5f" - integrity sha512-UurenNEYZRN192B70R3DR1NsFUae45h/2huAQD07OM0fyJyM6ji5N7q/Q2Aao0jqBLwRNPrEinUcP8BmJxe2Tw== +"@abp/jquery-form@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-7.2.0-rc.1.tgz#8c0dddb6907aaa40187ee93eab045c485a1d49eb" + integrity sha512-FK0GMHoB0u0VnizEwN+Gbc6yNg/G5VjSv0/u/9J3dHk4KVR5mo68xwbfPCIqvS0SOeOBgxYOfaxjfFrArCVFbg== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-7.1.1.tgz#255146ccc553bb9f9197ccf87fa71d930698cf65" - integrity sha512-oUYvNmiGxeyJeGoG3EWAzy2Ld9EKgyK6U28gKaAMrXFlYbiEMnX5+8v1Tdb3sQuOJ68bdiyYjO3Ke9NLsTZHFg== +"@abp/jquery-validation-unobtrusive@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-7.2.0-rc.1.tgz#2d7e559397192ded4409153d606120b96ef6958a" + integrity sha512-q+83bKCNOyqjOutRJ6lChg89lzvSUD04MkPj6teMOVWwqzbQ0B/lnkovfCtJRw7cAO8UBhzd3Q029JjhtG4WPw== dependencies: - "@abp/jquery-validation" "~7.1.1" + "@abp/jquery-validation" "~7.2.0-rc.1" jquery-validation-unobtrusive "^3.2.12" -"@abp/jquery-validation@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-7.1.1.tgz#b3af6606daaa6303c28f6a04aeaa2d6612c5248b" - integrity sha512-ZkDWUbHqF9NkczPdvEZH4gkb6NeXRI5JsROXzmx3K+QIOGUhs//4gOzSYYak0kn0Mljeg8fjJQNa55914d8Xow== +"@abp/jquery-validation@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-7.2.0-rc.1.tgz#1768ae95e2870ccf25d541b6fc65d7dfd8f6c567" + integrity sha512-IRNyw4ak/ntliaGWpqQLn3ZGOlg3DdgMLtINLdSF6STX2nEcts2jnv3bxI2iFUjcYF+x6pCjUrUCpegdgtTNrw== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" jquery-validation "^1.19.3" -"@abp/jquery@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-7.1.1.tgz#43adacf3d345576ff7ca42a5a470eb61fb827e23" - integrity sha512-3Epxyyoz1BJge7lbimkg0Ha4DmNlZN5vYFgVKa8SOCoKfoZ7+8gmbXlUEAUe4wnsjP5tQ4/AjoqgzjPL9KQcCg== +"@abp/jquery@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-7.2.0-rc.1.tgz#6020b62df568dae3d2659447314587793ef320ec" + integrity sha512-lt668fxX83pC/f+uA7edo5XwaPkmpZ2sQYqdBh9IQGD9hmkFIZdp7t6ABbcSsOiCFuLok2RXODAvJeDqV+x0TA== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" jquery "~3.6.0" -"@abp/lodash@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-7.1.1.tgz#7371484331867775adcb5f4a92d63d4cbed25f19" - integrity sha512-hwNcYcRNZZV5OgH+W775OkpJ5JmrDi+LiVFDAmelWgAXSgqxic8bDla+UUL/pjnkKxwgI4BAlOIctYN/2QM3iA== +"@abp/lodash@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-7.2.0-rc.1.tgz#e9c50df914b54f9d53f5ada9c80fb04906388889" + integrity sha512-Acl+ipVflcZPt4BMRsVl4yt2zxU+//u/N9Wr7wawpz0vLpMOTAi86YKHJHqjh1W7Ixeujn6gfjcwZLMwd95d1Q== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-7.1.1.tgz#b0cf4a72ffe66f77d403b896ea5d1ea007ebc9b7" - integrity sha512-2RDIdHrPUDvOoowQlMInfQ0rDZA8IOf2fVs7C2bcZmhjGoK7+vsUJsw/q9awpgeKrHwqJ0o1zsFGfFFKlYMnew== +"@abp/luxon@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-7.2.0-rc.1.tgz#ce254b096f2a96c19f0576046d0962e1e415d40c" + integrity sha512-33SfVt9VUbriGLbRyOsEIkRBiwOhXH4XAf1jE3Z8cwjOw5X+ZmKZUyZGJsvGtJfwMqZ54FT9lDuovp8L9U1OoA== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" luxon "^2.3.0" -"@abp/malihu-custom-scrollbar-plugin@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-7.1.1.tgz#8a25f3dd78c1f0c395ac255976567d2919d3ec38" - integrity sha512-kfW+B+kFr0Qao17rDginL0ICPwGA3t387hx5LhPIxP2p7aluaA3qyiEbM50Izz+t4mL4JdaBN8DU0kLziqVERw== +"@abp/malihu-custom-scrollbar-plugin@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-7.2.0-rc.1.tgz#785afe744620eb2b1648e8099b1f6f61a8f619cf" + integrity sha512-Qcoyy1wLClej8eCGnJ+W9TJ47R4I/eZpu2m0tmSWgdnw8Zqahti9xK09LOUG7piHoOC/qyv8Qwb+UdTSqCtzkw== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-7.1.1.tgz#5cf7f815cc4dbe55c9c363d146592683f8a90d62" - integrity sha512-tgg4rTmAGZE+B8OBpeq1ADXJW07EdkCkQUSrLykWMaQr1PZfs9xi0tgsi4CpdITLOK48b9BueRmUdZOgmFXKiQ== +"@abp/moment@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-7.2.0-rc.1.tgz#96697eabd63e67f24c774baa68b37b75d5d774be" + integrity sha512-s+7tgMxBGW/4uQwKEAfdLdgU7gX1t2XD/e0BxfSgex8diaxUQ9DoWrq4qK6EBk1keWqq1fKuMZ4fqbnRFRG+ag== dependencies: moment "^2.9.0" -"@abp/popper.js@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/popper.js/-/popper.js-7.1.1.tgz#bbdded3334342aef51483461b72aa8edd12664dc" - integrity sha512-hY+/D0vajNXbSv49YdiXcr1iVTeVOUusB+dpzBgETwRgr0iwe+xF8RDnevLaa99vpjfiLgQnBFhBB5ZqwVit2Q== +"@abp/popper.js@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/popper.js/-/popper.js-7.2.0-rc.1.tgz#c91f05cae6c8b0e452592a9dcbf64168d54ea802" + integrity sha512-qpqdOli11my/mGgYUbjShBpPwp2KH0sjpM7IhBSjkZWFpjG03Z/f1X5rbUch7l3/tWcL4i1lpJZtxqQUns4b0g== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" "@popperjs/core" "^2.11.2" -"@abp/prismjs@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-7.1.1.tgz#bfcee96e5a1e2f98fb29006f16aeeb227a4e773d" - integrity sha512-7o7FRzgGNPR9GxQ6CPskWL2N87LykoylKnkCm0Cz0n+x0JSrAEMv2yEiJJT2L1S+51ldCQhBmF2blOjxgUT98A== +"@abp/prismjs@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-7.2.0-rc.1.tgz#c775a9a04e9edb55cac06bf355c2a5f013837874" + integrity sha512-TaMfj18i5UXGVHBOP/JTHIVnEg/CdrfpIRwGjyG51CjWOK28xYfeRRYU41q+7UXTv3AjgwWT+B1ksyst6DA7Fw== dependencies: - "@abp/clipboard" "~7.1.1" - "@abp/core" "~7.1.1" + "@abp/clipboard" "~7.2.0-rc.1" + "@abp/core" "~7.2.0-rc.1" prismjs "^1.26.0" -"@abp/select2@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-7.1.1.tgz#1afa414ce68c1f35c3e7ab1beee00f924604de51" - integrity sha512-+5MMLQuXlj07VIXhVKEAmeqsfuGXHWwtpDY2LMsT15lNJbrvq0wF9KZJ0eMF8u29Nyk8IuBJf1YRUzx815PiVg== +"@abp/select2@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-7.2.0-rc.1.tgz#7c076ad31efe5087f361ea01f66cf00bc409c8b1" + integrity sha512-Hmmfl11hgHb7TSss7ptj48zqgez75wTHHfUhAyZsU/qu3/w2s7qTOAIoJczuARKBJ3eXKku9U1otzC7gR7LqKQ== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-7.1.1.tgz#9ba7578ab53af056f26ef34ae0f2fddc28722c12" - integrity sha512-8hjmEqmcRoMN3Cmk7k0lNdtsm8JytrjPzvHahjqKHIcK1Zi0RbjWJpafbvDu5IFlFrRNYHXlqpUw8e3dtCEp3A== +"@abp/sweetalert2@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-7.2.0-rc.1.tgz#c6cc72b5eb8a4909c42be27566077c4b1ce2e377" + integrity sha512-VSeaSxCuzEziQPjLQ2IXhuyC2PYOI8dp7Bi5uEtFG3fnHz042rcRZSgh6teks6eRRUNxuv17YnV/LAEvm2UQtg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" sweetalert2 "^11.3.6" -"@abp/timeago@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-7.1.1.tgz#c7be25a320aa311e2e9c7a8186b51766db4523ac" - integrity sha512-FsIjAiP2dqRHwrrKx/5tWgLMZ2LboNLhrHeRb1FFol/0163uVEQGEJkxLOE5xY530mdaFFfAOc0x6aniSLE4ZQ== +"@abp/timeago@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-7.2.0-rc.1.tgz#1f0f0ba199501c760cf53e493fd63bbe8a6329f2" + integrity sha512-QfbnOOBye76m+x+uOPcZG40zDOIyIgWssoUyBQDch6Z3A9HcDhw6qQBlsoeuX2+N/be1KCIfUHvjHE92Zdhktg== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" timeago "^1.6.7" -"@abp/toastr@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-7.1.1.tgz#5ef7da983a226f226d8b9b85f2fa9ff7eeed41aa" - integrity sha512-8x8FQt8BSmgI1b6JXK7N+JJJ0ksBcFSMQol0AbzTOFOBO2T77eXIuiVh8961ynaeIECjGWcazXUMuG09Drq6Ig== +"@abp/toastr@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-7.2.0-rc.1.tgz#758a74cd8d699c9c8fb1cc23b7e39762b6929861" + integrity sha512-IREF8C/CYb2PJrSWqYWoqvrzDrgBDrQSkGJvMVNo4DRj2V66UzHUfMFQBoQA40m0tY354SEhowhPRbj9BhQGtA== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" toastr "^2.1.4" -"@abp/utils@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-7.1.1.tgz#e11bc878573dd8118e42b3c1582c44d8b5c71d83" - integrity sha512-G4S0ndDUe8W525O8KUBucLcrESoSFjeqLjRZ+W7N7K9D/oLisYU9Siwxb2csTdjXz6JeQ7AtQl7ak1WpAMiJ/g== +"@abp/utils@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-7.2.0-rc.1.tgz#25726da9d39e887a490eff44b2ce9a28826ec4dd" + integrity sha512-g/G+En4Te3b9x/7bSf8WDwUjBusiLf4oVcUVk65/wbC0BezMsxnrzRr1ZMZQyYYGJYJ3DdnUftOLziUx9o7U6A== dependencies: just-compare "^1.3.0" 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 ada739b4d7..2af74dd224 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "رمز اللغة", "DisplayName:Version": "إصدار", "Documents": "وثائق", - "RemoveFromCache": "حذف من الذاكرة", + "RemoveFromCache": "إزالة من ذاكرة التخزين المؤقت وإعادة الفهرس", "Reindex": "إعادة الفهرسة", "ReindexCompleted": "تمت إعادة الفهرسة", - "RemovedFromCache": "تم الحذف من ذاكرة التخزين", - "RemoveFromCacheConfirmation": "هل أنت متأكد من حذف هذا العنصر من ذاكرة التخزين؟", - "ReIndexDocumentConfirmation": "هل أنت متأكد من إعادة فهرسة هذا العنصر؟", + "RemovedFromCache": "تمت إزالته من ذاكرة التخزين المؤقت وإعادة فهرسته", + "RemoveFromCacheConfirmation": "هل تريد بالتأكيد إعادة فهرسة \"{0} \"؟", + "ReIndexDocumentConfirmation": "هل تريد بالتأكيد إعادة فهرسة \"{0}\"؟", "DeleteFromDatabase": "حذف من قاعدة البيانات", "Deleted": "محذوف", "Search": "بحث", @@ -55,6 +55,7 @@ "LanguageCode": "رمز اللغة", "FileName": "اسم الملف", "LastCachedTime": "وقت ذاكرة التخزين", - "Project": "مشروع " + "Project": "مشروع ", + "RemoveCacheAndReIndexConfirmation": "ستتم إزالة المستند \"{0}\" من ذاكرة التخزين المؤقت وإعادة فهرسته. هل تؤكد؟" } } 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 c593147804..19fa5c257c 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Kód jazyka", "DisplayName:Version": "Verze", "Documents": "Dokumenty", - "RemoveFromCache": "Odebrat z mezipaměti", + "RemoveFromCache": "Odstranit z mezipaměti a znovu indexovat", "Reindex": "Reindex", "ReindexCompleted": "Reindex dokončen", - "RemovedFromCache": "Odebráno z mezipaměti", + "RemovedFromCache": "Odstraněno z mezipaměti a znovu zaindexováno", "RemoveFromCacheConfirmation": "Opravdu chcete tuto položku odebrat z mezipaměti?", - "ReIndexDocumentConfirmation": "Opravdu chcete tuto položku reindexovat?", + "ReIndexDocumentConfirmation": "Jste si jisti, že chcete znovu indexovat \"{0}\"?", "DeleteFromDatabase": "Odstranit z databáze", "Deleted": "Vymazáno", "Search": "Vyhledávání", @@ -55,6 +55,7 @@ "LanguageCode": "Kód jazyka", "FileName": "Název souboru", "LastCachedTime": "Čas uložení v mezipaměti", - "Project": "Projekt" + "Project": "Projekt", + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bude odstraněn z mezipaměti a znovu zaindexován. Potvrzujete to?" } } 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 4d92840132..ce7c8cafb0 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Sprachcode", "DisplayName:Version": "Version", "Documents": "Dokumente", - "RemoveFromCache": "Aus dem Cache entfernen", + "RemoveFromCache": "Aus dem Cache entfernen und neu indizieren", "Reindex": "Neuindizierung", "ReindexCompleted": "Neuindizierung abgeschlossen", - "RemovedFromCache": "Aus dem Cache entfernt", + "RemovedFromCache": "Aus dem Cache entfernt und neu indiziert", "RemoveFromCacheConfirmation": "Möchten Sie dieses Element wirklich aus dem Cache entfernen?", - "ReIndexDocumentConfirmation": "Möchten Sie diesen Beitrag wirklich neu indizieren?", + "ReIndexDocumentConfirmation": "Sind Sie sicher, dass Sie \"{0}\" neu indizieren wollen?", "DeleteFromDatabase": "Aus Datenbank löschen", "Deleted": "Gelöscht", "Search": "Suchen", @@ -55,6 +55,7 @@ "LanguageCode": "Sprachcode", "FileName": "Dateiname", "LastCachedTime": "Cache-Zeit", - "Project": "Projekt" + "Project": "Projekt", + "RemoveCacheAndReIndexConfirmation": "Das Dokument \"{0}\" wird aus dem Cache entfernt und neu indiziert. Können Sie das bestätigen?" } } \ 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 bacdfd56de..c2a3f69a53 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Κωδικός γλώσσας", "DisplayName:Version": "Εκδοχή", "Documents": "Εγγραφα", - "RemoveFromCache": "Αφαίρεση από την προσωρινή μνήμη", + "RemoveFromCache": "Αφαίρεση από τη μνήμη cache και εκ νέου ευρετηρίαση", "Reindex": "Επανακαταγραφή", "ReindexCompleted": "Ολοκληρώθηκε η επανακαταγραφή", - "RemovedFromCache": "Καταργήθηκε από την προσωρινή μνήμη", + "RemovedFromCache": "πομακρύνεται από τη μνήμη cache και αναπροσαρμόζεται", "RemoveFromCacheConfirmation": "Είστε βέβαιοι ότι θέλετε να αφαιρέσετε αυτό το στοιχείο από την προσωρινή μνήμη;", - "ReIndexDocumentConfirmation": "Είστε βέβαιοι ότι θέλετε να αναπροσαρμόσετε αυτό το στοιχείο;", + "ReIndexDocumentConfirmation": "Είστε σίγουροι ότι θέλετε να ξαναδείξετε το \"{0}\";", "DeleteFromDatabase": "Διαγραφή από τη βάση δεδομένων", "Deleted": "Διαγραφή", "Search": "Αναζήτηση", @@ -55,6 +55,7 @@ "LanguageCode": "Κωδικός γλώσσας", "FileName": "Όνομα αρχείου", "LastCachedTime": "Χρόνος προσωρινής αποθήκευσης", - "Project": "Εργο" + "Project": "Εργο", + "RemoveCacheAndReIndexConfirmation": "Το έγγραφο \"{0}\" θα αφαιρεθεί από την προσωρινή μνήμη και θα αναπροσαρμοστεί εκ νέου. Επιβεβαιώνετε;" } } \ 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 86142ceb44..5302cdcffb 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Language code", "DisplayName:Version": "Version", "Documents": "Documents", - "RemoveFromCache": "Remove from cache", + "RemoveFromCache": "Remove from cache and re-index", "Reindex": "Reindex", "ReindexCompleted": "Reindex completed", - "RemovedFromCache": "Removed from cache", + "RemovedFromCache": "Removed from cache and re-indexed", "RemoveFromCacheConfirmation": "Are you sure you want to remove this item from cache?", - "ReIndexDocumentConfirmation": "Are you sure you want to reindex this item?", + "ReIndexDocumentConfirmation": "Are you sure you want to re-index \"{0}\"?", "DeleteFromDatabase": "Delete from database", "Deleted": "Deleted", "Search": "Search", @@ -56,6 +56,7 @@ "FileName": "File name", "LastCachedTime": "Cache time", "Project": "Project", - "AdvancedFilters": "Advanced Filters" + "AdvancedFilters": "Advanced Filters", + "RemoveCacheAndReIndexConfirmation": "The document \"{0}\" will be removed from the cache and re-indexed. Do you confirm?" } } \ 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 9858f9d94a..800f3efc13 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Código de idioma", "DisplayName:Version": "Versión", "Documents": "Documentos", - "RemoveFromCache": "Borrado de caché", + "RemoveFromCache": "Eliminar de la caché y volver a indexar", "Reindex": "Reindexado", "ReindexCompleted": "Reindexado completado", - "RemovedFromCache": "Borrar la caché", + "RemovedFromCache": "Eliminado de la caché y reIndexado", "RemoveFromCacheConfirmation": "¿Estás seguro que quieres borrar este elemento de la caché?", - "ReIndexDocumentConfirmation": "¿Estás seguro que quieres reindexar este elemento?", + "ReIndexDocumentConfirmation": "¿Estás seguro de que quieres reindexar \"{0}\"?", "DeleteFromDatabase": "Eliminado de la base de datos", "Deleted": "Eliminado", "Search": "Buscar", @@ -55,6 +55,7 @@ "LanguageCode": "Código de idioma", "FileName": "Nombre de fichero", "LastCachedTime": "Última actualización de caché", - "Project": "Proyecto" + "Project": "Proyecto", + "RemoveCacheAndReIndexConfirmation": "El documento \"{0}\" será eliminado de la caché y reindexado. ¿Lo confirma?" } } \ 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 58befd658c..e3e826c1b7 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 @@ -3,21 +3,21 @@ "texts": { "Permission:DocumentManagement": "Asiakirjojen hallinta", "Permission:Projects": "Projektit", - "Permission:Edit": "Muokata", - "Permission:Delete": "Poistaa", - "Permission:Create": "Luoda", + "Permission:Edit": "Muokkaus", + "Permission:Delete": "Poisto", + "Permission:Create": "Luonti", "Permission:Documents": "Asiakirjat", "Menu:Documents": "Asiakirjat", "Menu:DocumentManagement": "Asiakirjat", "Menu:ProjectManagement": "Projektit", "CreateANewProject": "Luo uusi projekti", - "Edit": "Muokata", - "Create": "Luoda", - "Pull": "Vedä", + "Edit": "Muokkaa", + "Create": "Luo", + "Pull": "Vedä (Pull)", "Projects": "Projektit", "Name": "Nimi", "ShortName": "Lyhyt nimi", - "DocumentStoreType": "DocumentStoreType", + "DocumentStoreType": "Asiakirjavaraston tyyppi", "Format": "Muoto", "ShortNameInfoText": "Käytetään yksilölliseen URL-osoitteeseen.", "DisplayName:Name": "Nimi", @@ -33,16 +33,16 @@ "DisplayName:GitHubUserAgent": "GitHub-käyttäjäagentti", "DisplayName:GithubVersionProviderSource": "GitHub-version tarjoajan lähde", "DisplayName:VersionBranchPrefix": "Versiohaaran etuliite", - "DisplayName:All": "Vedä kaikki", + "DisplayName:All": "Vedä (Pull) Kaikki", "DisplayName:LanguageCode": "Kielikoodi", "DisplayName:Version": "Versio", "Documents": "Asiakirjat", - "RemoveFromCache": "Poista välimuistista", - "Reindex": "Reindex", - "ReindexCompleted": "Reindex valmis", - "RemovedFromCache": "Poistettu välimuistista", + "RemoveFromCache": "Poista välimuistista ja indeksoi uudelleen", + "Reindex": "Uudelleen indeksoi", + "ReindexCompleted": "Uudelleen indeksointi valmis", + "RemovedFromCache": "Poistettu välimuistista ja indeksoitu uudelleen.", "RemoveFromCacheConfirmation": "Haluatko varmasti poistaa tämän kohteen välimuistista?", - "ReIndexDocumentConfirmation": "Haluatko varmasti indeksoida tämän kohteen uudelleen?", + "ReIndexDocumentConfirmation": "Oletko varma, että haluat indeksoida \"{0}\" uudelleen?", "DeleteFromDatabase": "Poista tietokannasta", "Deleted": "Poistettu", "Search": "Hae", @@ -55,6 +55,8 @@ "LanguageCode": "Kielikoodi", "FileName": "Tiedoston nimi", "LastCachedTime": "Välimuistin aika", - "Project": "Projekti" + "Project": "Projekti", + "AdvancedFilters": "Edistyneet suodattimet", + "RemoveCacheAndReIndexConfirmation": "Dokumentti \"{0}\" poistetaan välimuistista ja indeksoidaan uudelleen. Vahvistatko?" } } \ 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 7a6d6a89cf..158e544742 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Code de langue", "DisplayName:Version": "Version", "Documents": "Documents", - "RemoveFromCache": "Retirer du cache", + "RemoveFromCache": "Remove from cache and ReIndex", "Reindex": "Réindexer", "ReindexCompleted": "Réindexation terminée", - "RemovedFromCache": "Supprimé du cache", + "RemovedFromCache": "Retiré du cache et ré-indexé", "RemoveFromCacheConfirmation": "Voulez-vous vraiment supprimer cet élément du cache?", - "ReIndexDocumentConfirmation": "Voulez-vous vraiment réindexer cet élément?", + "ReIndexDocumentConfirmation": "Êtes-vous sûr de vouloir réindexer \"{0}\" ?", "DeleteFromDatabase": "Supprimer de la base de données", "Deleted": "Supprimé", "Search": "Rechercher", @@ -55,6 +55,7 @@ "LanguageCode": "Code de langue", "FileName": "Nom de fichier", "LastCachedTime": "Temps de cache", - "Project": "Projet" + "Project": "Projet", + "RemoveCacheAndReIndexConfirmation": "Le document \"{0}\" sera supprimé du cache et réindexé. Confirmez-vous ?" } } \ 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 a7d357e83e..d45d10992d 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "भाषा कोड", "DisplayName:Version": "संस्करण", "Documents": "दस्तावेज़", - "RemoveFromCache": "कैश से निकालें", + "RemoveFromCache": "कैश और रीइंडेक्स से निकालें", "Reindex": "अनुक्रमणः", "ReindexCompleted": "रेनडेक्स पूरा किया", - "RemovedFromCache": "कैश से निकाला गया", + "RemovedFromCache": "संचय से निकाला गया और पुनः अनुक्रमित किया गया", "RemoveFromCacheConfirmation": "क्या आप वाकई इस आइटम को कैश से निकालना चाहते हैं?", - "ReIndexDocumentConfirmation": "क्या आप वाकई इस आइटम को फिर से दिखाना चाहते हैं?", + "ReIndexDocumentConfirmation": "क्या आप वाकई \"{0}\" को फिर से अनुक्रमित करना चाहते हैं?", "DeleteFromDatabase": "डेटाबेस से हटाएं", "Deleted": "हटाए गए", "Search": "खोज", @@ -55,6 +55,7 @@ "LanguageCode": "भाषा कोड", "FileName": "फ़ाइल का नाम", "LastCachedTime": "कैश समय", - "Project": "परियोजना" + "Project": "परियोजना", + "RemoveCacheAndReIndexConfirmation": "दस्u200Dतावेज़ \"{0}\" को संचय से हटा दिया जाएगा और पुन: अनुक्रमित किया जाएगा। क्या आप पुष्टि करते हैं?" } } \ 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 2469d21c4b..cf0a31368f 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Jezični kod", "DisplayName:Version": "Verzija", "Documents": "Dokumenti", - "RemoveFromCache": "Ukloni iz predmemorije", + "RemoveFromCache": "Ukloni iz predmemorije i ponovno indeksiraj", "Reindex": "Ponovno indeksiranje", "ReindexCompleted": "Ponovno indeksiranje dovršeno", - "RemovedFromCache": "Uklonjeno iz predmemorije", + "RemovedFromCache": "Uklonjeno iz predmemorije i ponovno indeksirano", "RemoveFromCacheConfirmation": "Jeste li sigurni da želite ukloniti ovu stavku iz predmemorije?", - "ReIndexDocumentConfirmation": "Jeste li sigurni da želite ponovno indeksirati ovu stavku?", + "ReIndexDocumentConfirmation": "Jeste li sigurni da želite ponovno indeksirati \"{0}\"?", "DeleteFromDatabase": "Izbriši iz baze podataka", "Deleted": "Izbrisano", "Search": "Pretraga", @@ -56,6 +56,7 @@ "FileName": "Naziv datoteke", "LastCachedTime": "Vrijeme predmemorije", "Project": "Projekt", - "AdvancedFilters": "Napredni filtri" + "AdvancedFilters": "Napredni filtri", + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" bit će uklonjen iz predmemorije i ponovno indeksiran. Potvrđujete li?" } } 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 fce9150db3..587f67e72c 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 @@ -38,12 +38,12 @@ "DisplayName:Version": "Verzió", "DisplayName:Role": "Szerepkör", "Documents": "Dokumentumok", - "RemoveFromCache": "Távolítsa el a gyorsítótárból", + "RemoveFromCache": "Eltávolítás a gyorsítótárból és újraindexelés", "Reindex": "Újraindexálás", "ReindexCompleted": "Újraindexálás teljes.", - "RemovedFromCache": "Távolítsa el a gyorsítótárból", + "RemovedFromCache": "Eltávolítva a gyorsítótárból és újraindexelve", "RemoveFromCacheConfirmation": "Biztosan eltávolítja ezt az elemet a gyorsítótárból?", - "ReIndexDocumentConfirmation": "Biztosan újraindexeli ezt az elemet?", + "ReIndexDocumentConfirmation": "Biztos, hogy újra akarja indexelni a \"{0}\"-t?", "DeleteFromDatabase": "Törlés az adatbázisból", "Deleted": "Törölt", "Search": "Keresés", @@ -57,6 +57,7 @@ "FileName": "Filenév", "LastCachedTime": "Cache idő", "Project": "Projekt", - "AdvancedFilters": "Speciális szűrők" + "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?" } } \ 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 c7d13791d0..ada8ff0e0c 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Túngumála kóði", "DisplayName:Version": "Útgáfa", "Documents": "Skjöl", - "RemoveFromCache": "Fjarlægja úr skyndiminni", + "RemoveFromCache": "Fjarlægðu úr skyndiminni og ReIndex", "Reindex": "Endurindexa", "ReindexCompleted": "Endurindexum lokið", - "RemovedFromCache": "Fjarlægja úr skyndiminni", + "RemovedFromCache": "Fjarlægt úr skyndiminni og endurtryggt", "RemoveFromCacheConfirmation": "Ertu viss um að þú viljir fjarlægja þetta atriði úr skyndiminni?", - "ReIndexDocumentConfirmation": "Ertu viss um að þú viljir endurindexa þennan hlut?", + "ReIndexDocumentConfirmation": "Ertu viss um að þú viljir endurskrá \"{0}\"?", "DeleteFromDatabase": "Eyða úr gagnagrunni", "Deleted": "Eyða", "Search": "Leita", @@ -55,6 +55,7 @@ "LanguageCode": "Túngumála kóði", "FileName": "Skráar nafn", "LastCachedTime": "Tími geymt í skyndiminni", - "Project": "Verkefni" + "Project": "Verkefni", + "RemoveCacheAndReIndexConfirmation": "Skjalið \"{0}\" verður fjarlægt úr skyndiminni og endurtryggt. Staðfestir þú?" } } \ 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 b6c95e5b58..28c66074e3 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Codice della lingua", "DisplayName:Version": "Versione", "Documents": "Documenti", - "RemoveFromCache": "Rimuovi dalla cache", + "RemoveFromCache": "Rimuovere dalla cache e reindicizzare", "Reindex": "Reindicizza", "ReindexCompleted": "Reindicizzazione completata", - "RemovedFromCache": "Rimosso dalla cache", + "RemovedFromCache": "Rimosso dalla cache e reindicizzato", "RemoveFromCacheConfirmation": "Sei sicuro di voler rimuovere questo elemento dalla cache?", - "ReIndexDocumentConfirmation": "Sei sicuro di voler reindicizzare questo articolo?", + "ReIndexDocumentConfirmation": "Siete sicuri di voler reindicizzare \"{0}\"?", "DeleteFromDatabase": "Elimina dal database", "Deleted": "Eliminato", "Search": "Ricerca", @@ -55,6 +55,7 @@ "LanguageCode": "Codice della lingua", "FileName": "Nome del file", "LastCachedTime": "Tempo di cache", - "Project": "Progetto" + "Project": "Progetto", + "RemoveCacheAndReIndexConfirmation": "Il documento \"{0}\" verrà rimosso dalla cache e reindicizzato. Confermate?" } } \ 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 e8cd5d730a..734000cc01 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Taalcode", "DisplayName:Version": "Versie", "Documents": "Documenten", - "RemoveFromCache": "Verwijderen uit cache", + "RemoveFromCache": "Verwijderen uit cache en opnieuw indexeren", "Reindex": "Opnieuw indexeren", "ReindexCompleted": "Opnieuw indexeren voltooid", - "RemovedFromCache": "Verwijderen uit cache", + "RemovedFromCache": "Verwijderd uit cache en opnieuw geïndexeerd", "RemoveFromCacheConfirmation": "Weet u zeker dat u dit item uit de cache wilt verwijderen?", - "ReIndexDocumentConfirmation": "Weet u zeker dat u dit item opnieuw wilt indexeren?", + "ReIndexDocumentConfirmation": "Weet u zeker dat u \"{0}\" opnieuw wilt indexeren?", "DeleteFromDatabase": "Verwijder uit database", "Deleted": "Verwijderd", "Search": "Zoeken", @@ -55,6 +55,7 @@ "LanguageCode": "Taalcode", "FileName": "Bestandsnaam", "LastCachedTime": "Cache tijd", - "Project": "Project" + "Project": "Project", + "RemoveCacheAndReIndexConfirmation": "Het document \"{0}\" wordt uit de cache verwijderd en opnieuw geïndexeerd. Bevestigt u?" } } \ 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 5f1025a9a6..06ee3410e3 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Kod języka", "DisplayName:Version": "Wersja", "Documents": "Dokumenty", - "RemoveFromCache": "Usuń z pamięci podręcznej", + "RemoveFromCache": "Usunięcie z pamięci podręcznej i ponowne indeksowanie", "Reindex": "Ponowna indeksacja", "ReindexCompleted": "Ponowna indeksacja zakończona", - "RemovedFromCache": "Usunięto z pamięci podręcznej", + "RemovedFromCache": "Usunięte z pamięci podręcznej i ponownie zindeksowane", "RemoveFromCacheConfirmation": "Czy na pewno chcesz usunąć ten element z pamięci podręcznej?", - "ReIndexDocumentConfirmation": "Czy na pewno chcesz ponownie zindeksować ten element?", + "ReIndexDocumentConfirmation": "Czy na pewno chcesz przeindeksować \"{0}\"?", "DeleteFromDatabase": "Usuń z bazy danych", "Deleted": "Usunięto", "Search": "Szukaj", @@ -55,6 +55,7 @@ "LanguageCode": "Kod języka", "FileName": "Nazwa pliku", "LastCachedTime": "Czas w pamięci podręcznej", - "Project": "Projekt" + "Project": "Projekt", + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" zostanie usunięty z pamięci podręcznej i ponownie zaindeksowany. Czy potwierdzasz?" } } \ 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 d926dfada9..b34ab4b9ef 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Código de idioma", "DisplayName:Version": "Versão", "Documents": "Documentos", - "RemoveFromCache": "Remover do cache", + "RemoveFromCache": "Remover do cache e do ReIndex", "Reindex": "Reindexar", "ReindexCompleted": "Reindexação concluída", - "RemovedFromCache": "Removido do cache", + "RemovedFromCache": "Removido do cache e reIndexado", "RemoveFromCacheConfirmation": "Tem certeza de que deseja remover este item do cache?", - "ReIndexDocumentConfirmation": "Tem certeza que deseja reindexar este item?", + "ReIndexDocumentConfirmation": "Você tem certeza de que quer re-indexar \"{0}\"?", "DeleteFromDatabase": "Excluir do banco de dados", "Deleted": "Excluído", "Search": "Procurar", @@ -56,6 +56,7 @@ "FileName": "Nome do arquivo", "LastCachedTime": "Tempo de cache", "Project": "Projeto", - "AdvancedFilters": "Filtros Avançados" + "AdvancedFilters": "Filtros Avançados", + "RemoveCacheAndReIndexConfirmation": "O documento \"{0}\" será removido do cache e indexado novamente. Você confirma?" } } \ 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 b236915665..be374b79c9 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Codul limbii", "DisplayName:Version": "Versiune", "Documents": "Documente", - "RemoveFromCache": "Şterge din cache", + "RemoveFromCache": "Eliminarea din memoria cache și reintroducerea indexării", "Reindex": "Reindexează", "ReindexCompleted": "Reindexare completă", - "RemovedFromCache": "Şters din cache", + "RemovedFromCache": "Eliminat din memoria cache și reintrodus în index", "RemoveFromCacheConfirmation": "Sunteţi sigur(ă) că vreţi să ştergeţi acest obiect din cache?", - "ReIndexDocumentConfirmation": "Sunteţi sigur(ă) că vreţi să reindexaţi acest obiect?", + "ReIndexDocumentConfirmation": "Sunteți sigur că doriți să re-indexați \"{0}\"?", "DeleteFromDatabase": "Şterge din baza de date", "Deleted": "Şters", "Search": "Caută", @@ -55,6 +55,7 @@ "LanguageCode": "Codul limbii", "FileName": "Nume fişier", "LastCachedTime": "Durată cache", - "Project": "Proiect" + "Project": "Proiect", + "RemoveCacheAndReIndexConfirmation": "Documentul \"{0}\" va fi eliminat din memoria cache și va fi reindexat. Confirmați?" } } \ 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 16102717c2..9a93cc36c8 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Код языка", "DisplayName:Version": "Версия", "Documents": "Документы", - "RemoveFromCache": "Удалить из кеша", + "RemoveFromCache": "Удаление из кэша и повторное индексирование", "Reindex": "Переиндексировать", "ReindexCompleted": "Переиндекс завершен", - "RemovedFromCache": "Удалено из кеша", + "RemovedFromCache": "Удалены из кэша и переиндексированы", "RemoveFromCacheConfirmation": "Вы уверены, что хотите удалить этот элемент из кеша?", - "ReIndexDocumentConfirmation": "Вы уверены, что хотите переиндексировать этот элемент?", + "ReIndexDocumentConfirmation": "Вы уверены, что хотите переиндексировать \"{0}\"?", "DeleteFromDatabase": "Удалить из базы данных", "Deleted": "Удалено", "Search": "Поиск", @@ -55,6 +55,7 @@ "LanguageCode": "Код языка", "FileName": "Имя файла", "LastCachedTime": "Время кеширования", - "Project": "Проект" + "Project": "Проект", + "RemoveCacheAndReIndexConfirmation": "Документ \"{0}\" будет удален из кэша и переиндексирован. Вы подтверждаете?" } } \ 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 8041e796f0..a29d85987e 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Kód jazyka", "DisplayName:Version": "Verzia", "Documents": "Dokumenty", - "RemoveFromCache": "Odstrániť z vyrovnávacej pamäte", + "RemoveFromCache": "Odstránenie z vyrovnávacej pamäte a opätovné indexovanie", "Reindex": "Reindexovať", "ReindexCompleted": "Reindexácia dokončená", - "RemovedFromCache": "Odstránené z vyrovnávacej pamäte", + "RemovedFromCache": "Odstránené z vyrovnávacej pamäte a znovu zaindexované", "RemoveFromCacheConfirmation": "Ste si istý, že chcete túto položku odstrániť z vyrovnávacej pamäte?", - "ReIndexDocumentConfirmation": "Ste si istý, že chcete túto položku reindexovať?", + "ReIndexDocumentConfirmation": "Ste si istí, že chcete znovu indexovať \"{0}\"?", "DeleteFromDatabase": "Zmazať z databázy", "Deleted": "Zmazané", "Search": "Hľadať", @@ -55,6 +55,7 @@ "LanguageCode": "Kód jazyka", "FileName": "Názov súboru", "LastCachedTime": "Čas vyrovnávacej pamäte", - "Project": "Projekt" + "Project": "Projekt", + "RemoveCacheAndReIndexConfirmation": "Dokument \"{0}\" sa odstráni z vyrovnávacej pamäte a znovu sa zaindexuje. Potvrdzujete?" } } \ 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 dade32b970..ab600c1db5 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Dil kodu", "DisplayName:Version": "versiyon", "Documents": "Dokümanlar", - "RemoveFromCache": "Önbellekten kaldır", + "RemoveFromCache": "Önbellekten kaldır ve yeniden indeksle", "Reindex": "Yeniden İndeksle", "ReindexCompleted": "Yeniden indeksleme tamamlandı", - "RemovedFromCache": "Önbellekten kaldırıldı", + "RemovedFromCache": "Önbellekten kaldırıldı ve yeniden indekslendi", "RemoveFromCacheConfirmation": "Bu maddeyi önbellekten kaldırmak istediğiniz emin misiniz?", - "ReIndexDocumentConfirmation": "Bu maddeyi yeniden indekslemek istediğinize emin misiniz?", + "ReIndexDocumentConfirmation": "\"{0}\" öğesini yeniden indekslemek istediğinizden emin misiniz?", "DeleteFromDatabase": "Veritabanından sil", "Deleted": "Silindi", "Search": "Arama", @@ -56,6 +56,7 @@ "FileName": "Dosya adı", "LastCachedTime": "Önbellek süresi", "Project": "Proje", - "AdvancedFilters": "Gelişmiş Filtre" + "AdvancedFilters": "Gelişmiş Filtre", + "RemoveCacheAndReIndexConfirmation": "\"{0}\" belgesi önbellekten kaldırılacak ve yeniden indekslenecektir. Onaylıyor musunuz?" } } \ 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 c44d2feb8f..df729a70e9 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "Mật ngữ", "DisplayName:Version": "Phiên bản", "Documents": "Các tài liệu", - "RemoveFromCache": "Xóa khỏi bộ nhớ cache", + "RemoveFromCache": "Xóa khỏi bộ đệm và lập chỉ mục lại", "Reindex": "Reindex", "ReindexCompleted": "Reindex đã hoàn thành", - "RemovedFromCache": "Đã xóa khỏi bộ nhớ cache", + "RemovedFromCache": "Đã xóa khỏi bộ đệm và lập chỉ mục lại", "RemoveFromCacheConfirmation": "Bạn có chắc chắn muốn xóa mục này khỏi bộ nhớ cache không?", - "ReIndexDocumentConfirmation": "Bạn có chắc chắn muốn lập chỉ mục lại mục này không?", + "ReIndexDocumentConfirmation": "Bạn có chắc chắn muốn lập chỉ mục lại \"{0}\" không?", "DeleteFromDatabase": "Xóa khỏi cơ sở dữ liệu", "Deleted": "Đã xóa", "Search": "Tìm kiếm", 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 f81333d38e..da611a35c7 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "语言代码", "DisplayName:Version": "版本", "Documents": "文档", - "RemoveFromCache": "从缓存中删除", + "RemoveFromCache": "从缓存中清除并重新索引", "Reindex": "重新索引", "ReindexCompleted": "重新索引完成", - "RemovedFromCache": "已从缓存中删除", + "RemovedFromCache": "从缓存中删除并重新索引", "RemoveFromCacheConfirmation": "你确定要从缓存中删除该项吗?", - "ReIndexDocumentConfirmation": "你确定要为该项重新索引吗", + "ReIndexDocumentConfirmation": "您确定要重新索引“{0}”吗?", "DeleteFromDatabase": "从数据库中删除", "Deleted": "删除", "Search": "搜索", @@ -55,6 +55,7 @@ "LanguageCode": "语言代码", "FileName": "文件名称", "LastCachedTime": "缓存项", - "Project": "项目" + "Project": "项目", + "RemoveCacheAndReIndexConfirmation": "文档“{0}”将从缓存中删除并重新编制索引。 你确认吗?" } } \ 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 54d86eca33..d79055d067 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 @@ -37,12 +37,12 @@ "DisplayName:LanguageCode": "語言代碼", "DisplayName:Version": "版本", "Documents": "文件", - "RemoveFromCache": "從緩存中移除", + "RemoveFromCache": "從緩存中刪除並重新索引", "Reindex": "重新索引", "ReindexCompleted": "重新索引完成", - "RemovedFromCache": "從緩存中刪除", + "RemovedFromCache": "從緩存中刪除並重新編入索引", "RemoveFromCacheConfirmation": "您確定要從緩存中刪除此項嗎?", - "ReIndexDocumentConfirmation": "您確定要重新索引此項目嗎?", + "ReIndexDocumentConfirmation": "您確定要重新索引“{0}”嗎?", "DeleteFromDatabase": "從數據庫中刪除", "Deleted": "已刪除", "Search": "搜索", @@ -55,6 +55,7 @@ "LanguageCode": "語言代碼", "FileName": "文檔名稱", "LastCachedTime": "緩存時間", - "Project": "项目" + "Project": "项目", + "RemoveCacheAndReIndexConfirmation": "文檔“{0}”將從緩存中刪除並重新編制索引。 你確認嗎?" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js index 18390a251a..e70086b133 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js @@ -173,6 +173,10 @@ $(function () { visible: abp.auth.isGranted( 'Docs.Admin.Documents' ), + confirmMessage: function (data) { + return l('RemoveCacheAndReIndexConfirmation', + data.record.name); + }, action: function (data) { service .removeFromCache(data.record.id) @@ -188,7 +192,8 @@ $(function () { 'Docs.Admin.Documents' ), confirmMessage: function (data) { - return l('ReIndexDocumentConfirmation'); + return l('ReIndexDocumentConfirmation', + data.record.name); }, action: function (data) { service 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 217448d767..26bc77e6d1 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 @@ -36,6 +36,7 @@ "Volo.Docs.Domain:010002": "ShortName {ShortName} already exists.", "Preview": "preview", "Search": "Search", - "SearchResults": "Search Results" + "SearchResults": "Search Results", + "SearchInTheAllDocuments": "Search in the all documents" } } 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 bf2eb2b34d..814bede574 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 @@ -6,19 +6,19 @@ "Contributors": "Avustajat", "ShareOn": "Jaa", "Version": "Versio", - "Edit": "Muokata", + "Edit": "Muokkaa", "LastEditTime": "Viimeisin muokkaus", - "Delete": "Poistaa", + "Delete": "Poista", "ClearCache": "Tyhjennä välimuisti", "ClearCacheConfirmationMessage": "Haluatko varmasti tyhjentää kaikki välimuistit projektille \"{0}\"", - "ReIndexAllProjects": "ReIndex kaikki projektit", - "ReIndexProject": "ReIndex-projekti", - "ReIndexProjectConfirmationMessage": "Haluatko varmasti luoda uudelleenindeksin projektille \"{0}\"", - "SuccessfullyReIndexProject": "Reindex onnistuneesti projektille \"{0}\"", + "ReIndexAllProjects": "Indeksoi uudelleen kaikki projektit", + "ReIndexProject": "Indeksoi uudelleen projekti", + "ReIndexProjectConfirmationMessage": "Haluatko varmasti indeksoida uudelleen projektin \"{0}\"", + "SuccessfullyReIndexProject": "Projekti \"{0}\" uudelleen indeksoitu onnistuneesti", "ReIndexAllProjectConfirmationMessage": "Haluatko varmasti indeksoida kaikki projektit uudelleen?", - "SuccessfullyReIndexAllProject": "Reindex onnistuneesti kaikille projekteille", + "SuccessfullyReIndexAllProject": "Kaikki projektit uudelleen indeksoitu onnistuneesti", "InThisDocument": "Tässä asiakirjassa", - "GoToTop": "Mennä huipulle", + "GoToTop": "Siirry alkuun", "Projects": "Projekti (t)", "NoProjectWarning": "Ei vielä projekteja!", "DocumentNotFound": "Hups, pyydettyä asiakirjaa ei löytynyt!", @@ -36,6 +36,7 @@ "Volo.Docs.Domain:010002": "Lyhytnimi {ShortName} on jo olemassa.", "Preview": "esikatselu", "Search": "Hae", - "SearchResults": "Hakutulokset" + "SearchResults": "Hakutulokset", + "SearchInTheAllDocuments": "Hae kaikista asiakirjoista" } } \ 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 9c32e143f1..8ddbe55ae7 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 @@ -36,6 +36,7 @@ "Volo.Docs.Domain:010002": "简称 {ShortName} 已经存在.", "Preview": "预览", "Search": "搜索", - "SearchResults": "搜索结果" + "SearchResults": "搜索结果", + "SearchInTheAllDocuments": "搜索所有文档" } -} +} \ No newline at end of file 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 dde30ddb95..eab5ad59e8 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 @@ -160,18 +160,25 @@
- +
+ + @if (Model.Navigation == null || !Model.Navigation.HasChildItems) {
@@ -201,7 +208,7 @@ @@ -240,16 +247,22 @@
} -
-
- @if (Model.Document.Contributors != null && Model.Document.Contributors.Count > 0) - { + @{ + var showContributors = Model.Document.Contributors != null && Model.Document.Contributors.Count > 0; + var showEditLink = !string.IsNullOrEmpty(Model.Document.EditLink); + } + @if (showContributors || showEditLink) + { +
+
- - @L["Contributors"].Value - - - @if (!string.IsNullOrEmpty(Model.Document.EditLink)) + @if (showContributors) + { + + @L["Contributors"].Value + + } + @if (showEditLink) { @@ -258,27 +271,27 @@ }
-
- @foreach (var contributor in Model.Document.Contributors.OrderByDescending(c => c.CommitCount).ToList()) - { - - Avatar - - } -
- } - + @if (showContributors) + { +
+ @foreach (var contributor in Model.Document.Contributors.OrderByDescending(c => c.CommitCount).ToList()) + { + + Avatar + + } +
+ } +
- - -
+ }
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 9bb18c8677..9a16f925f1 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 @@ -3,25 +3,10 @@ var initNavigationFilter = function (navigationContainerId) { var $navigation = $('#' + navigationContainerId); - var getShownDocumentLinks = function () { - return $navigation - .find('.mCSB_container > li a:visible') - .not('.tree-toggle'); - }; - - var gotoFilteredDocumentIfThereIsOnlyOne = function () { - var $links = getShownDocumentLinks(); - if ($links.length === 1) { - var url = $links.first().attr('href'); - if (url === 'javascript:;') { - return; - } - - window.location = url; - } - }; + var $searchAllDocument = $('#search-all-document'); var filterDocumentItems = function (filterText) { + $navigation .find('.mCSB_container .opened') .removeClass('opened'); @@ -34,6 +19,7 @@ $navigation .find('.mCSB_container .selected-tree > ul') .show(); + $searchAllDocument.hide(); return; } @@ -69,24 +55,34 @@ hasParent = $parent.length > 0; } }); + + $searchAllDocument.show(); }; + $searchAllDocument.click(function () { + fullSearch($('#filter').val()); + }); + $('#filter').on('input', (e) => { filterDocumentItems(e.target.value); }) $('#filter').keyup(function (e) { if (e.key === 'Enter') { - gotoFilteredDocumentIfThereIsOnlyOne(); + fullSearch($('#filter').val()); } }); + + function fullSearch(filterText){ + window.open($('#fullsearch').data('fullsearch-url') + "?keyword=" + encodeURIComponent(filterText)); + } $('#fullsearch').keyup(function (e) { if (e.key === 'Enter') { - window.open($(this).data('fullsearch-url') + "?keyword=" + encodeURIComponent(this.value)); + fullSearch(e.target.value); } }); - }; + }; var initAnchorTags = function (container) { anchors.options = { 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 417fff6410..5d8178c46c 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 @@ -146,14 +146,14 @@ body.scrolledMore .alert-criteria p.alert-p { overflow: hidden; } .docs-page .docs-sidebar .docs-tree-list .docs-version .version-select .input-group-text { - padding: 0 0; + padding: 0 0 !important; font-size: 0.75rem; width: 15px; height: 24px; line-height: 1; border-radius: 0px; border: 0; - background: transparent; + background: transparent !important; top: 1px; } .docs-page .docs-sidebar .docs-tree-list .docs-version .version-select .input-group-text i { @@ -202,6 +202,21 @@ body.scrolledMore .alert-criteria p.alert-p { .docs-page .docs-sidebar .docs-tree-list .docs-version select option { background-color: #000; } +.docs-page .docs-sidebar .docs-tree-list .search-all-document-container { + border-bottom: 1px solid rgba(170, 170, 170, 0.2); + padding-bottom: 5px; +} +.docs-page .docs-sidebar .docs-tree-list .search-all-document-container button { + color: #aaa; + font-size: 14px; + width: 100%; + text-align: start; +} +.docs-page .docs-sidebar .docs-tree-list .search-all-document-container button i { + transform: rotate(90deg); + margin-right: 9px; + font-size: 13px; +} .docs-page .docs-sidebar .docs-tree-list > ul { display: block; height: calc(100vh - 310px); @@ -371,7 +386,7 @@ body.scrolledMore .alert-criteria p.alert-p { height: 100%; } .docs-page .docs-content .docs-link-btns .search-area .input-group-text { - background: transparent; + background: transparent !important; border: 0; color: rgba(41, 45, 51, 0.5); font-size: 1em; @@ -464,7 +479,7 @@ body.scrolledMore .alert-criteria p.alert-p { margin-bottom: 1rem; margin-left: 0; padding: 1em 1.5em; - background-color: #e3edf2; + background-color: rgb(227, 237, 242); font-size: 1em; border-radius: 12px; color: #385766; @@ -531,7 +546,7 @@ body.scrolledMore .alert-criteria p.alert-p { background-color: #f4f6fa; border-color: #f4f6fa; border-radius: 12px; - background: rgba(190, 223, 238, 0.82); + background: hsla(199, 59%, 84%, 0.82); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); z-index: 3; @@ -597,7 +612,7 @@ body.scrolledMore .alert-criteria p.alert-p { margin-left: -30px; } .docs-page .docs-page-index #scroll-index { - max-height: 90vh; + max-height: 38vh; } .docs-page .docs-page-index .scroll-top-btn { display: none; @@ -649,7 +664,7 @@ body.scrolledMore .alert-criteria p.alert-p { display: none; } body .close-mmenu, -body .close-dmenu { + body .close-dmenu { position: absolute; top: -78px; left: 25px; @@ -702,7 +717,7 @@ body .close-dmenu { display: none; } .docs-page .docs-sidebar .docs-top .navbar.navbar-logo .navbar-collapse { - background: #38003d; + background: rgb(56, 0, 61); position: fixed; top: 86px; left: 0; diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css.map b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css.map index 8f6f8445e5..de45ccb3da 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css.map +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["vs.scss"],"names":[],"mappings":"AAGA;EACI;EACA;;AAEA;EACI;EACA;;AAIJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;;AAIA;EACI;;AAGJ;AAAA;AAAA;AAAA;EAII;;AAIR;AAAA;EAEI;;AAGJ;EACI;;AAEA;EACI;;AAEJ;EACI;;AAIR;AAAA;EAEI;EACA;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;;AAMhB;EACI;;AAEA;EACI;EACA;EACA,KA9FK;EA+FL,QA/FK;EAgGL;EACA;EACA;EACA;EACA;EACA;EACA;;AAIQ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAMhB;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;;AAEJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAII;;AAIR;EACI;EACA;;AAEJ;EACI;EACA;;AAEA;EACI;;AAIR;EACI;;AAEA;EAII;;AAIR;EACI;EACA;EACA;;AAIR;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGI;EACI;;AAIR;EACI;;AAIR;EACI;;AAGI;EACI;;AAGJ;EACI;;AAGI;EACI;;AAQhB;EACI;EACA;;AAIA;EACI;EACA;;AAMA;EACI;;AAUhC;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AACA;EACI;EACA;EACA;EACA;EACA;;AAMA;EACI;EACA;EACA;EACA;EACA;;AACA;EACI;;AAEJ;EACI;EACA;;AAMhB;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAEJ;EACI;;AAGJ;EACI;EACA;;AAKZ;EACI;EACA;;AAEA;EACI;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIR;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAMA;EACI;;AAQhB;EACI;;AAGJ;EACI;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;AAAA;AAAA;AAAA;EAII;EACA;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;EAMI;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGI;EACI;;AAIR;EACI;;AAGJ;AAAA;EAEI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;AAKZ;EACI;EACA;EACA;EACA;;AACA;EACI;EACA;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AACA;EACI;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;;AAKZ;EACI;EACA;;AAEA;EACI;EACA;EACA,KA9qBC;EA+qBD;EACA;EACA;;AAGI;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAMA;EACI;;AAMA;EACI;;AAQxB;EACI;;AAIR;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA,eA1vBC;EA2vBD;;AAEA;EACI;EACA;EACA;;AACA;EACI;;AAGR;EACI;EACA,SAxwBH;;AA0wBD;EACI;EACA;EACA;;AAGJ;EACI;;;AAMhB;EACI;IACI;;EAEA;IACI;;EAGJ;IACI;;EAGJ;AAAA;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;;EAQR;IACI;;EAEA;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGI;IACI;IACA;IACA;IACA;;EAEA;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAIR;IACI;;EAGJ;IACI;IACA;;EAGJ;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;IACA;IACA;;EAEA;IACI;;EAKZ;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAIR;IACI;IACA;IACA;;EAIR;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAKZ;IACI;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAGJ;IACI;;EAIA;IACI;;EAEJ;IACI;;EAGJ;IACI;IACA;IACA;IACA;;EAGJ;IACI;IACA;IACA;IACA;;EAKZ;IACI;IACA;IACA;;EAEA;IACI;IACA;;EAIR;IACI;;EAEA;IACI;;;AAMhB;EAIgB;IACI;;EAEJ;IACI;;EAMI;IACI;IACA;;;AAS5B;EAEQ;IACI;IACA;;EAEJ;IAII;;EAHA;IACI;;;AAOhB;EAEQ;IACI;IACA;IACA;IACA;;EAEA;IACI;IACA;IACA","file":"vs.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["vs.scss"],"names":[],"mappings":"AAGA;EACI;EACA;;AAEA;EACI;EACA;;AAIJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;;AAIA;EACI;;AAGJ;AAAA;AAAA;AAAA;EAII;;AAIR;AAAA;EAEI;;AAGJ;EACI;;AAEA;EACI;;AAEJ;EACI;;AAIR;AAAA;EAEI;EACA;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;;AAMhB;EACI;;AAEA;EACI;EACA;EACA,KA9FK;EA+FL,QA/FK;EAgGL;EACA;EACA;EACA;EACA;EACA;EACA;;AAIQ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAMhB;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;;AAEJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAII;;AAIR;EACI;EACA;;AAEJ;EACI;EACA;;AAEA;EACI;;AAIR;EACI;;AAEA;EAII;;AAIR;EACI;EACA;EACA;;AAIR;EACI;;AAIR;EAEI;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAKZ;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGI;EACI;;AAIR;EACI;;AAIR;EACI;;AAGI;EACI;;AAGJ;EACI;;AAGI;EACI;;AAQhB;EACI;EACA;;AAIA;EACI;EACA;;AAMA;EACI;;AAUhC;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AACA;EACI;EACA;EACA;EACA;EACA;;AAMA;EACI;EACA;EACA;EACA;EACA;;AACA;EACI;;AAEJ;EACI;EACA;;AAMhB;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAEJ;EACI;;AAGJ;EACI;EACA;;AAKZ;EACI;EACA;;AAEA;EACI;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIR;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAMA;EACI;;AAQhB;EACI;;AAGJ;EACI;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;AAAA;AAAA;AAAA;EAII;EACA;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;EAMI;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGI;EACI;;AAIR;EACI;;AAGJ;AAAA;EAEI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;AAKZ;EACI;EACA;EACA;EACA;;AACA;EACI;EACA;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AACA;EACI;;AAKZ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAMR;EACI;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;;AAKZ;EACI;EACA;;AAEA;EACI;EACA;EACA,KAnsBC;EAosBD;EACA;EACA;;AAGI;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAMA;EACI;;AAMA;EACI;;AAQxB;EACI;;AAIR;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA,eA/wBC;EAgxBD;;AAEA;EACI;EACA;EACA;;AACA;EACI;;AAGR;EACI;EACA,SA7xBH;;AA+xBD;EACI;EACA;EACA;;AAGJ;EACI;;;AAMhB;EACI;IACI;;EAEA;IACI;;EAGJ;IACI;;EAGJ;AAAA;IAEI;IACA;IACA;IACA;IACA;IACA;IACA;;EAQR;IACI;;EAEA;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGI;IACI;IACA;IACA;IACA;;EAEA;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAIR;IACI;;EAGJ;IACI;IACA;;EAGJ;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;IACA;IACA;;EAEA;IACI;;EAKZ;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAIR;IACI;IACA;IACA;;EAIR;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAKZ;IACI;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAGJ;IACI;;EAIA;IACI;;EAEJ;IACI;;EAGJ;IACI;IACA;IACA;IACA;;EAGJ;IACI;IACA;IACA;IACA;;EAKZ;IACI;IACA;IACA;;EAEA;IACI;IACA;;EAIR;IACI;;EAEA;IACI;;;AAMhB;EAIgB;IACI;;EAEJ;IACI;;EAMI;IACI;IACA;;;AAS5B;EAEQ;IACI;IACA;;EAEJ;IAII;;EAHA;IACI;;;AAOhB;EAEQ;IACI;IACA;IACA;IACA;;EAEA;IACI;IACA;IACA","file":"vs.css"} \ No newline at end of file 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 6730794824..85ea8092b9 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 @@ -177,14 +177,14 @@ body { } .input-group-text { - padding: 0 0; + padding: 0 0 !important; font-size: 0.75rem; width: 15px; height: 24px; line-height: 1; border-radius: 0px; border: 0; - background: transparent; + background: transparent !important; top: 1px; i { @@ -247,6 +247,25 @@ body { } } + .search-all-document-container{ + + border-bottom: 1px solid rgb(170 170 170 / 20%); + padding-bottom: 5px; + + button{ + color: #aaa; + font-size: 14px; + width: 100%; + text-align: start; + + i{ + transform: rotate(90deg); + margin-right: 9px; + font-size: 13px; + } + } + } + > ul { display: block; height: calc(100vh - 310px); @@ -464,7 +483,7 @@ body { } .input-group-text { - background: transparent; + background: transparent !important; border: 0; color: rgb(41 45 51 / 50%); font-size: 1em; @@ -659,6 +678,8 @@ body { p.alert-p { font-size: 0.96em; } + + } .anchorjs-link { @@ -741,7 +762,7 @@ body { } #scroll-index { - max-height: 90vh; + max-height: 38vh; } .scroll-top-btn { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/fi.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/fi.json index edd6704f13..215b3289e6 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/fi.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/fi.json @@ -1,12 +1,17 @@ { "culture": "fi", "texts": { - "Features": "ominaisuudet", - "NoFeatureFoundMessage": "Ei ole mitään käytettävissä olevaa ominaisuutta.", + "Features": "Ominaisuudet", + "NoFeatureFoundMessage": "Käytettävissä olevia ominaisuuksia ei löydy.", "ManageHostFeatures": "Hallinnoi isäntäominaisuuksia", + "ManageHostFeaturesText": "Voit hallita isäntäpuolen ominaisuuksia napsauttamalla seuraavaa painiketta.", "Permission:FeatureManagement": "Ominaisuuden hallinta", "Permission:FeatureManagement.ManageHostFeatures": "Hallinnoi isäntäominaisuuksia", "Volo.Abp.FeatureManagement:InvalidFeatureValue": "Ominaisuuden {0} arvo ei kelpaa!", - "Menu:FeatureManagement": "Ominaisuuden hallinta" + "Menu:FeatureManagement": "Ominaisuuden hallinta", + "ResetToDefault": "Palauta oletusarvo", + "ResetedToDefault": "Palautettu oletusarvoon", + "AreYouSure": "Oletko varma?", + "AreYouSureToResetToDefault": "Oletko varma, että haluat palauttaa oletusarvon?" } } \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json index 30d01781d5..dc63ddf34a 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json @@ -4,12 +4,14 @@ "Features": "功能", "NoFeatureFoundMessage": "没有可用的功能.", "ManageHostFeatures": "管理Host功能", + "ManageHostFeaturesText": "您可以通过单击以下按钮来管理宿主功能。", "Permission:FeatureManagement": "功能管理", "Permission:FeatureManagement.ManageHostFeatures": "管理Host功能", "Volo.Abp.FeatureManagement:InvalidFeatureValue": "{0}功能的值无效!", "Menu:FeatureManagement": "功能管理", "ResetToDefault": "重置为默认值", "ResetedToDefault": "已重置为默认值", + "AreYouSure": "是否确认?", "AreYouSureToResetToDefault": "你确定要重置为默认值吗?" } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs index 61e6eee2a5..7495361ef0 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs @@ -8,6 +8,7 @@ public class IdentityRoleCreateOrUpdateDtoBase : ExtensibleObject { [Required] [DynamicStringLength(typeof(IdentityRoleConsts), nameof(IdentityRoleConsts.MaxNameLength))] + [Display(Name = "RoleName")] public string Name { get; set; } public bool IsDefault { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs index bbba6e63ec..61387f6536 100644 --- a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpSignInManager.cs @@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Volo.Abp.Identity.Settings; +using Volo.Abp.Settings; +using Volo.Abp.Timing; namespace Volo.Abp.Identity.AspNetCore; @@ -12,6 +15,10 @@ public class AbpSignInManager : SignInManager { protected AbpIdentityOptions AbpOptions { get; } + protected ISettingProvider SettingProvider { get; } + + private readonly IdentityUserManager _identityUserManager; + public AbpSignInManager( IdentityUserManager userManager, IHttpContextAccessor contextAccessor, @@ -20,8 +27,8 @@ public class AbpSignInManager : SignInManager ILogger> logger, IAuthenticationSchemeProvider schemes, IUserConfirmation confirmation, - IOptions options - ) : base( + IOptions options, + ISettingProvider settingProvider) : base( userManager, contextAccessor, claimsFactory, @@ -30,7 +37,9 @@ public class AbpSignInManager : SignInManager schemes, confirmation) { + SettingProvider = settingProvider; AbpOptions = options.Value; + _identityUserManager = userManager; } public override async Task PasswordSignInAsync( @@ -85,6 +94,17 @@ public class AbpSignInManager : SignInManager return SignInResult.NotAllowed; } + if (user.ShouldChangePasswordOnNextLogin) + { + Logger.LogWarning($"The user should change password! (username: \"{user.UserName}\", id:\"{user.Id}\")"); + return SignInResult.NotAllowed; + } + + if (await _identityUserManager.ShouldPeriodicallyChangePasswordAsync(user)) + { + return SignInResult.NotAllowed; + } + return await base.PreSignInCheck(user); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityErrorCodes.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityErrorCodes.cs index ff808d9fbb..4e681c3ea1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityErrorCodes.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityErrorCodes.cs @@ -10,4 +10,5 @@ public static class IdentityErrorCodes public const string StaticRoleDeletion = "Volo.Abp.Identity:010006"; public const string UsersCanNotChangeTwoFactor = "Volo.Abp.Identity:010007"; public const string CanNotChangeTwoFactor = "Volo.Abp.Identity:010008"; + public const string YouCannotDelegateYourself = "Volo.Abp.Identity:010009"; } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json index 2d19b28989..490bd611df 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "لا يمكن حذف الأدوار الثابتة.", "Volo.Abp.Identity:010007": "لا يمكنك تغيير إعداد العاملين.", "Volo.Abp.Identity:010008": "لا يجوز تغيير إعداد عاملين.", + "Volo.Abp.Identity:010009": "لا يمكنك تفويض نفسك.", "Identity.OrganizationUnit.MaxUserMembershipCount": "العدد الأقصى المسموح به لعضوية الوحدة التنظيمية للمستخدم", "ThisUserIsNotActiveMessage": "هذا المستخدم غير نشط.", "Permission:IdentityManagement": "إدارة الهوية", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "الأحرف صغيرة المطلوبة", "DisplayName:Abp.Identity.Password.RequireUppercase": "الأحرف الكبيرة المطلوبة", "DisplayName:Abp.Identity.Password.RequireDigit": "الرقم المطلوب", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "إجبار المستخدمين على تغيير كلمة المرور بشكل دوري", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "تغيير كلمة المرور بشكل دوري", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "ممكّن للمستخدمين الجدد", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "مدة التأمين (بالثواني)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "محاولات الوصول الفاشلة", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "إذا كانت كلمات المرور يجب أن تحتوي على حرف ASCII صغير.", "Description:Abp.Identity.Password.RequireUppercase": "إذا كان يجب أن تحتوي كلمات المرور على أحرف ASCII ذات الأحرف الكبيرة.", "Description:Abp.Identity.Password.RequireDigit": "إذا كانت كلمات المرور يجب أن تحتوي على رقم.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "إذا كان يجب أن يتغير كلمة المرور بشكل دوري.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "عدد الأيام التي يجب أن تتراوح بين تغيير كلمة المرور.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "ما إذا كان يمكن قفل مستخدم جديد.", "Description:Abp.Identity.Lockout.LockoutDuration": "المدة التي يتم فيها حظر المستخدم عند حدوث قفل.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "عدد محاولات الوصول الفاشلة المسموح بها قبل قفل المستخدم ، بافتراض تمكين التأمين.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "ما إذا كان يمكن تحديث اسم المستخدم بواسطة المستخدم.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "ما إذا كان يمكن تحديث البريد الإلكتروني من قبل المستخدم." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json index 45a50180ba..7f2ddde421 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statické role nemohou být smazány.", "Volo.Abp.Identity:010007": "Nastavení dvou faktorů nemůžete změnit.", "Volo.Abp.Identity:010008": "Není povoleno měnit nastavení dvou faktorů.", + "Volo.Abp.Identity:010009": "Nemůžete delegovat své vlastní oprávnění.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximální povolený počet členů organizační jednotky pro uživatele", "ThisUserIsNotActiveMessage": "Tento uživatel není aktivní.", "Permission:IdentityManagement": "Správa identit", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Požadováno malé písmeno", "DisplayName:Abp.Identity.Password.RequireUppercase": "Požadováno velké písmeno", "DisplayName:Abp.Identity.Password.RequireDigit": "Požadováno číslo", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Vynutit uživatelům pravidelnou změnu hesla", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Délka platnosti hesla (dny)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Povoleno pro nové uživatele", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Délka blokování (sekundy)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maximální počet neúspěšných pokusů o přístup", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Pokud hesla musí obsahovat ASCII znak malých písmen.", "Description:Abp.Identity.Password.RequireUppercase": "Pokud hesla musí obsahovat ASCII znak velkých písmen.", "Description:Abp.Identity.Password.RequireDigit": "Pokud hesla musí obsahovat číslici.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Zda musí uživatelé pravidelně měnit heslo.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays:": "Počet dní, po které je heslo platné. Pokud je nastaveno na 0, heslo nikdy nevyprší.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Zda může být uzamčen nový uživatel.", "Description:Abp.Identity.Lockout.LockoutDuration": "Doba, po kterou je uživatel zablokován, když dojde k zablokování.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Počet neúspěšných pokusů o přístup než je uživatel uzamčen, za předpokladu, že je uzamčení povoleno.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Zda může uživatel změnit uživatelské jméno.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Zda může uživatel změnit email." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json index 5bc9beb4dc..69f2e9e9b2 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statische Rollen können nicht gelöscht werden.", "Volo.Abp.Identity:010007": "Sie können Ihre Zwei-Faktor-Einstellung nicht ändern.", "Volo.Abp.Identity:010008": "Die Zwei-Faktor-Einstellung dürfen nicht geändert werden.", + "Volo.Abp.Identity:010009": "Sie können sich nicht selbst delegieren.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximal zulässige Anzahl an Mitgliedschaften in Organisationseinheiten für einen Benutzer", "ThisUserIsNotActiveMessage": "Dieser Benutzer ist nicht aktiv.", "Permission:IdentityManagement": "Identitätsverwaltung", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Erforderlicher Kleinbuchstabe", "DisplayName:Abp.Identity.Password.RequireUppercase": "Erforderlicher Großbuchstabe", "DisplayName:Abp.Identity.Password.RequireDigit": "Erforderliche Ziffer", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Benutzer müssen das Passwort regelmäßig ändern", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Passwortänderungszeitraum (Tage)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Für neue Benutzer aktiviert", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Sperrdauer (Sekunden)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max. Fehlgeschlagene Zugriffsversuche", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Wenn Kennwörter einen ASCII-Kleinbuchstaben enthalten müssen.", "Description:Abp.Identity.Password.RequireUppercase": "Wenn Kennwörter einen ASCII-Großbuchstaben enthalten müssen.", "Description:Abp.Identity.Password.RequireDigit": "Wenn Passwörter eine Ziffer enthalten müssen.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Gibt an, ob Benutzer das Passwort regelmäßig ändern müssen.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Die Anzahl der Tage, nach denen ein Benutzer das Passwort ändern muss.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Gibt an, ob ein neuer Benutzer gesperrt werden kann.", "Description:Abp.Identity.Lockout.LockoutDuration": "Die Dauer, für die ein Benutzer gesperrt ist, wenn eine Sperre auftritt.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Die Anzahl der fehlgeschlagenen Zugriffsversuche, die zulässig sind, bevor ein Benutzer gesperrt wird, sofern die Sperre aktiviert ist.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Gibt an, ob der Benutzername vom Benutzer aktualisiert werden kann.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Gibt an, ob die E-Mail-Adresse vom Benutzer aktualisiert werden kann." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json index f00493c329..765d85ce09 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json @@ -70,6 +70,7 @@ "Volo.Abp.Identity:010006": "Οι στατικοί ρόλοι δεν μπορούν να διαγραφούν.", "Volo.Abp.Identity:010007": "Δεν μπορείτε να αλλάξετε τη ρύθμιση δύο παραγόντων.", "Volo.Abp.Identity:010008": "Δεν επιτρέπεται η αλλαγή της ρύθμισης δύο παραγόντων.", + "Volo.Abp.Identity:010009": "Δεν μπορείτε να αναθέσετε την εξουσιοδότησή σας σε εσάς ίδιο.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Μέγιστος επιτρεπόμενος αριθμός μελών μονάδας οργανισμού για έναν χρήστη", "ThisUserIsNotActiveMessage": "Αυτός ο χρήστης δεν είναι ενεργός.", "Permission:IdentityManagement": "Διαχείριση ταυτότητας", @@ -86,6 +87,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Απαιτούμενος πεζός χαρακτήρας", "DisplayName:Abp.Identity.Password.RequireUppercase": "Απαιτούμενος κεφαλαίος χαρακτήρας", "DisplayName:Abp.Identity.Password.RequireDigit": "Απαιτούμενο ψηφίο", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Επιβάλλεται η αλλαγή του κωδικού πρόσβασης", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Διάρκεια κωδικού πρόσβασης (ημέρες)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Ενεργοποιήθηκε για νέους χρήστες", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Διάρκεια κλειδώματος (δευτερόλεπτα)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Μέγιστες αποτυχημένες προσπάθειες πρόσβασης", @@ -100,6 +103,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Εάν οι κωδικοί πρόσβασης πρέπει να περιέχουν πεζό χαρακτήρα ASCII.", "Description:Abp.Identity.Password.RequireUppercase": "Εάν οι κωδικοί πρόσβασης πρέπει να περιέχουν κεφαλαίο χαρακτήρα ASCII.", "Description:Abp.Identity.Password.RequireDigit": "Εάν οι κωδικοί πρόσβασης πρέπει να περιέχουν ένα ψηφίο.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Εάν οι χρήστες πρέπει να αλλάζουν τον κωδικό πρόσβασης τους με συχνότητα που ορίζεται από το PasswordChangePeriodDays.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Η διάρκεια της περιόδου σε ημέρες μετά την οποία οι χρήστες πρέπει να αλλάζουν τον κωδικό πρόσβασης τους.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Εάν ένας νέος χρήστης μπορεί να κλειδωθεί.", "Description:Abp.Identity.Lockout.LockoutDuration": "Η διάρκεια για την οποία ένας χρήστης είναι κλειδωμένος όταν εμφανίζεται ένα κλείδωμα.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Ο αριθμός των αποτυχημένων προσπαθειών πρόσβασης που επιτρέπονται πριν από το κλείδωμα ενός χρήστη, με την προϋπόθεση ότι το κλείδωμα είναι ενεργοποιημένο.", @@ -109,4 +114,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Εάν το όνομα χρήστη μπορεί να ενημερωθεί από τον χρήστη.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Εάν το email μπορεί να ενημερωθεί από τον χρήστη." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json index 3efd41afd5..adebfa33e8 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json @@ -70,6 +70,7 @@ "Volo.Abp.Identity:010006": "Static roles cannot be deleted.", "Volo.Abp.Identity:010007": "You can't change your two factor setting.", "Volo.Abp.Identity:010008": "Changing the two factor setting is not allowed.", + "Volo.Abp.Identity:010009": "You cannot delegate yourself!", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximum allowed organisation unit membership count for a user", "Permission:IdentityManagement": "Identity management", "Permission:RoleManagement": "Role management", @@ -91,6 +92,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Required lower case character", "DisplayName:Abp.Identity.Password.RequireUppercase": "Required upper case character", "DisplayName:Abp.Identity.Password.RequireDigit": "Required digit", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Force users to periodically change password", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Password change period(days)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Enabled for new users", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Lockout duration(in seconds)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max failed access attempts", @@ -105,6 +108,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "If passwords must contain a lower case ASCII character.", "Description:Abp.Identity.Password.RequireUppercase": "If passwords must contain a upper case ASCII character.", "Description:Abp.Identity.Password.RequireDigit": "If passwords must contain a digit.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Whether users are required to periodically change their password.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "The number of days a user's password is valid for.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Whether a new user can be locked out.", "Description:Abp.Identity.Lockout.LockoutDuration": "The duration a user is locked out for when a lockout occurs.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "The number of failed access attempts allowed before a user is locked out, assuming lock out is enabled.", @@ -118,4 +123,4 @@ "DisplayName:Abp.Identity.UsersCanChange": "Allow users to change their Two Factor.", "Description:Abp.Identity.UsersCanChange": "Allow users to change their Two Factor." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json index 3a67018bb8..724ec04300 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Static roles can not be deleted.", "Volo.Abp.Identity:010007": "You can't change your two factor setting.", "Volo.Abp.Identity:010008": "It's not allowed to change two factor setting.", + "Volo.Abp.Identity:010009": "You can not delegate yourself.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximum allowed organization unit membership count for a user", "ThisUserIsNotActiveMessage": "This user is not active.", "Permission:IdentityManagement": "Identity management", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Required lower case character", "DisplayName:Abp.Identity.Password.RequireUppercase": "Required upper case character", "DisplayName:Abp.Identity.Password.RequireDigit": "Required digit", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Force users to periodically change password", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Password change period(days)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Enabled for new users", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Lockout duration(seconds)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max failed access attempts", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "If passwords must contain a lower case ASCII character.", "Description:Abp.Identity.Password.RequireUppercase": "If passwords must contain a upper case ASCII character.", "Description:Abp.Identity.Password.RequireDigit": "If passwords must contain a digit.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Whether users are forced to periodically change their password.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "The number of days a user's password is valid for.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Whether a new user can be locked out.", "Description:Abp.Identity.Lockout.LockoutDuration": "The duration a user is locked out for when a lockout occurs.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "The number of failed access attempts allowed before a user is locked out, assuming lock out is enabled.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Whether the username can be updated by the user.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Whether the email can be updated by the user." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json index 48cd0522d3..06c279ec73 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Los roles estáticos no pueden ser borrados.", "Volo.Abp.Identity:010007": "No puedes cambiar tu configuración de autentificación de dos pasos.", "Volo.Abp.Identity:010008": "No está permitido cambiar la configuración de autenticación de dos pasos.", + "Volo.Abp.Identity:010009": "No puedes delegar tu propia cuenta!", "Identity.OrganizationUnit.MaxUserMembershipCount": "Número máximo de unidades organizativas por usuario", "ThisUserIsNotActiveMessage": "Este usuario no está activo.", "Permission:IdentityManagement": "Gestión de identidades", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Carácter en minúsculas requerido", "DisplayName:Abp.Identity.Password.RequireUppercase": "Carácter en mayúsculas requerido", "DisplayName:Abp.Identity.Password.RequireDigit": "Dígito requerido", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Forzar a los usuarios a cambiar su contraseña periódicamente", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Período de cambio de contraseña (días)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Habilitado para nuevos usuarios", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Duración del bloqueo (segundos)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Número máximo de accesos fallidos", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Si las contraseñas deben contener un carácter en minúscula.", "Description:Abp.Identity.Password.RequireUppercase": "Si las contreseñas deben contener un carácter en mayúscula", "Description:Abp.Identity.Password.RequireDigit": "Si las contraseñas deben contener un dígito", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Si los usuarios deben cambiar su contraseña periódicamente.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "El número de días que un usuario debe esperar antes de cambiar su contraseña.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Si un nuevo usuario puede ser bloqueado.", "Description:Abp.Identity.Lockout.LockoutDuration": "La duración del bloqueo de un usuario cuando el bloqueo ocurre.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "El número de accessos fallidos permitidos antes de que un usuario sea bloqueado, el bloqueo de usuario debe estar habilitado.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Si el nombre de usuario puede ser actualizado por el usuario.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Si el e-mail puede ser actualizado por el usuario." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json index 0f94187749..7a89cebc87 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json @@ -70,6 +70,7 @@ "Volo.Abp.Identity:010006": "نقش/وظیفه ی استاتیک را نمی توان حذف کرد.", "Volo.Abp.Identity:010007": "شما نمی توانید تنظیمات دو مرحله ای خود را تغییر دهید.", "Volo.Abp.Identity:010008": "تغییر دادن تنظیمات دو مرحله ای مجاز نمی باشد.", + "Volo.Abp.Identity:010009": "شما نمی توانید خودتان را معرفی کنید.", "Identity.OrganizationUnit.MaxUserMembershipCount": "حداکثر تعداد مجاز عضویت در یک واحد سازمان برای یک کاربر", "ThisUserIsNotActiveMessage": "این کاربر غیرفعال میباشد.", "Permission:IdentityManagement": "مدیریت هویت", @@ -86,6 +87,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "حروف کوچک مورد نیاز است", "DisplayName:Abp.Identity.Password.RequireUppercase": "حروف بزرگ مورد نیاز است", "DisplayName:Abp.Identity.Password.RequireDigit": "رقم مورد نیاز است", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "اجبار کاربران به تغییر گذرواژه", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "مدت زمان تغییر گذرواژه (روز)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "برای کاربران جدید فعال گردیده است", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "مدت زمان قفل شدن (ثانیه)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "حداکثر تلاشهای ناموفق برای دسترسی", @@ -100,6 +103,8 @@ "Description:Abp.Identity.Password.RequireLowercase": " ها باید دارای حروف کوچک ASCII باشند.", "Description:Abp.Identity.Password.RequireUppercase": "گذرواژه ها باید دارای حروف بزرگ ASCII باشند.", "Description:Abp.Identity.Password.RequireDigit": "گذرواژه ها باید دارای عدد باشند.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "اجبار کاربران به تغییر گذرواژه بعد از یک مدت زمان مشخص.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "مدت زمانی که کاربر باید بعد از آن گذرواژه خود را تغییر دهد.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "آیا کاربر جدید را می توان قفل کرد.", "Description:Abp.Identity.Lockout.LockoutDuration": "مدت زمانی که کاربر هنگام قفل شدن، در حالت قفل باقی می ماند.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "تعداد تلاشهای دسترسی ناموفق قبل از قفل شدن کاربر، با فرض فعال بودن امکان قفل کردن.", @@ -109,4 +114,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "آیا کاربر می تواند نام کاربری را به روز کند یا خیر.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "آیا کاربر می تواند آدرس ایمیل خود را به روز کند با خیر." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json index f0be798b90..d74257414a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json @@ -71,13 +71,14 @@ "Volo.Abp.Identity:010006": "Staattisia rooleja ei voi poistaa.", "Volo.Abp.Identity:010007": "Et voi muuttaa kahden tekijän asetusta.", "Volo.Abp.Identity:010008": "Kahden tekijän asetusta ei saa muuttaa.", + "Volo.Abp.Identity:010009": "Et voi delegoida itseäsi.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Suurin sallittu organisaatioyksikön jäsenmäärä käyttäjälle", "ThisUserIsNotActiveMessage": "Tämä käyttäjä ei ole aktiivinen.", "Permission:IdentityManagement": "Identiteetin hallinta", "Permission:RoleManagement": "Roolien hallinta", - "Permission:Create": "Luoda", - "Permission:Edit": "Muokata", - "Permission:Delete": "Poistaa", + "Permission:Create": "Luonti", + "Permission:Edit": "Muokkaus", + "Permission:Delete": "Poisto", "Permission:ChangePermissions": "Muuta käyttöoikeuksia", "Permission:UserManagement": "Käyttäjien hallinta", "Permission:UserLookup": "Käyttäjähaku", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Vaadittu pieni kirjain", "DisplayName:Abp.Identity.Password.RequireUppercase": "Vaadittu iso kirjain", "DisplayName:Abp.Identity.Password.RequireDigit": "Vaadittu numero", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Pakota käyttäjät vaihtamaan salasanaa säännöllisesti", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Salasanan vaihtamisen aikaväli (päivää)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Käytössä uusille käyttäjille", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Lukituksen kesto (sekuntia)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max epäonnistui pääsyyrityksiä", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Jos salasanojen on sisällettävä pieni kirjain ASCII-merkki.", "Description:Abp.Identity.Password.RequireUppercase": "Jos salasanojen on sisällettävä isoja ASCII-merkkejä.", "Description:Abp.Identity.Password.RequireDigit": "Jos salasanojen on sisällettävä numero.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Pakottaa käyttäjät vaihtamaan salasanaa säännöllisesti.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Salasanan vaihtamisen aikaväli (päivää).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Voiko uusi käyttäjä lukita.", "Description:Abp.Identity.Lockout.LockoutDuration": "Kesto, jonka käyttäjä lukitaan, kun lukitus tapahtuu.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Ennen käyttäjän lukitsemista sallittujen epäonnistuneiden pääsyyritysten lukumäärä, olettaen, että lukitus on käytössä.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Voiko käyttäjä päivittää käyttäjänimen?", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Voiko käyttäjä päivittää sähköpostin." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json index 9a7d0294fb..80a5f90a10 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Les rôles statiques ne peuvent pas être supprimés.", "Volo.Abp.Identity:010007": "Vous ne pouvez pas modifier votre paramètre à deux facteurs.", "Volo.Abp.Identity:010008": "Il n’est pas permis de changer deux facteurs de réglage.", + "Volo.Abp.Identity:010009": "Vous ne pouvez pas vous déléguer vous-même.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Nombre maximal d’adhésions autorisées à l’unité d’organisation pour un utilisateur", "ThisUserIsNotActiveMessage": "Cet utilisateur n'est pas actif.", "Permission:IdentityManagement": "Gestion de l’identité", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Caractère de minuscule requis", "DisplayName:Abp.Identity.Password.RequireUppercase": "Caractère de majuscule requis", "DisplayName:Abp.Identity.Password.RequireDigit": "Chiffre requis", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Forcer les utilisateurs à changer leur mot de passe périodiquement", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Période de changement de mot de passe (jours)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Activé pour les nouveaux utilisateurs", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Durée(secondes) du lock-out", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max a échoué tentatives d’accès", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Si les mots de passe doivent contenir un caractère ASCII minuscule.", "Description:Abp.Identity.Password.RequireUppercase": "Si les mots de passe doivent contenir un caractère ASCII majuscule.", "Description:Abp.Identity.Password.RequireDigit": "Si les mots de passe doivent contenir un chiffre.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Si les utilisateurs doivent changer leur mot de passe périodiquement.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Période de changement de mot de passe (jours).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Si un nouvel utilisateur peut être verrouillé.", "Description:Abp.Identity.Lockout.LockoutDuration": "Durée pendant laquelle un utilisateur est verrouillé lorsqu’un lock-out se produit.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Nombre de tentatives d’accès échouées avant qu’un utilisateur ne soit verrouillé, en supposant que le verrouillage est activé.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Si le nom d’utilisateur peut être mis à jour par l’utilisateur.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Si l’e-mail peut être mis à jour par l’utilisateur." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json index 898e664b5b..e01e4c8e25 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "स्टेटिक भूमिकाओं को हटाया नहीं जा सकता।", "Volo.Abp.Identity:010007": "आप अपनी दो कारक सेटिंग नहीं बदल सकते।", "Volo.Abp.Identity:010008": "इसे दो कारक सेटिंग बदलने की अनुमति नहीं है।", + "Volo.Abp.Identity:010009": "आप अपने आप को अधिकृत नहीं कर सकते हैं!", "Identity.OrganizationUnit.MaxUserMembershipCount": "उपयोगकर्ता के लिए अधिकतम अनुमत संगठन इकाई सदस्यता गणना", "ThisUserIsNotActiveMessage": "यह उपयोगकर्ता सक्रिय नहीं है।", "Permission:IdentityManagement": "पहचान प्रबंधन", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "आवश्यक निचला मामला चरित्र", "DisplayName:Abp.Identity.Password.RequireUppercase": "आवश्यक ऊपरी मामला चरित्र", "DisplayName:Abp.Identity.Password.RequireDigit": "आवश्यक अंक", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "उपयोगकर्ताओं को अपने पासवर्ड को अक्षम करने के लिए बाधित करने की आवश्यकता है", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "पासवर्ड बदलने की अवधि (दिन)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "नए उपयोगकर्ताओं के लिए सक्षम है", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "तालाबंदी अवधि (सेकंड)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "अधिकतम पहुँच प्रयास विफल", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "यदि पासवर्ड में ASCII वर्ण कम होना चाहिए।", "Description:Abp.Identity.Password.RequireUppercase": "यदि पासवर्ड में ऊपरी मामला ASCII वर्ण होना चाहिए।", "Description:Abp.Identity.Password.RequireDigit": "यदि पासवर्ड में एक अंक होना चाहिए।", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "यदि उपयोगकर्ताओं को अपने पासवर्ड को अक्षम करने के लिए बाधित करने की आवश्यकता है।", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "उपयोगकर्ता के पासवर्ड को बदलने की अनुमति देने के लिए अवधि (दिन)।", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "क्या कोई नया उपयोगकर्ता लॉक किया जा सकता है।", "Description:Abp.Identity.Lockout.LockoutDuration": "जब लॉकआउट होता है, तो उपयोगकर्ता की अवधि लॉक हो जाती है।", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "उपयोगकर्ता द्वारा लॉक किए जाने से पहले अनुमति प्राप्त विफल प्रयासों की संख्या, यह मानकर कि लॉक आउट सक्षम है।", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "उपयोगकर्ता द्वारा उपयोगकर्ता नाम अपडेट किया जा सकता है या नहीं।", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "क्या उपयोगकर्ता द्वारा ईमेल को अपडेट किया जा सकता है।" } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json index 75b349405a..a31715fc16 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statičke uloge nije moguće izbrisati.", "Volo.Abp.Identity:010007": "Ne možete promijeniti postavku dva faktora.", "Volo.Abp.Identity:010008": "Nije dopušteno mijenjati postavke dvofaktorske autentifikacije.", + "Volo.Abp.Identity:010009": "Ne možete delegirati sami sebi.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maksimalni dopušteni broj članstva u organizacijskoj jedinici za korisnika", "ThisUserIsNotActiveMessage": "Ovaj korisnik nije aktivan.", "Permission:IdentityManagement": "Upravljanje identitetom", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Obavezno malo slovo", "DisplayName:Abp.Identity.Password.RequireUppercase": "Obavezno veliko slovo", "DisplayName:Abp.Identity.Password.RequireDigit": "Obavezna znamenka", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Prisilite korisnike da periodično mijenjaju lozinku", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Period promjene lozinke (dana)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Omogućeno za nove korisnike", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Trajanje zaključavanja (sekunde)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maksimalan broj neuspjelih pokušaja pristupa", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Ako lozinke moraju sadržavati mali ASCII znak.", "Description:Abp.Identity.Password.RequireUppercase": "Ako lozinke moraju sadržavati veliki ASCII znak.", "Description:Abp.Identity.Password.RequireDigit": "Ako lozinke moraju sadržavati znamenku.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Ako se korisnici moraju periodično mijenjati lozinku.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Period u danima nakon kojeg se korisnici moraju promijeniti lozinku.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Može li se novi korisnik zaključati.", "Description:Abp.Identity.Lockout.LockoutDuration": "Trajanje koliko je korisnik zaključan kada dođe do zaključavanja.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Broj dopuštenih neuspjelih pokušaja pristupa prije nego što se korisnik zaključa, pod pretpostavkom da je zaključavanje omogućeno.", diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json index fe3b0122c9..8c658c9e89 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "A statikus szerepeket nem lehet törölni.", "Volo.Abp.Identity:010007": "Nem változtathatja meg a kétlépcsős bejelentkezés beállítását.", "Volo.Abp.Identity:010008": "Kétlépcsős bejelentkezés beállítás megváltoztatása nem megengedett.", + "Volo.Abp.Identity:010009": "Nem adhatja át a saját jogosultságait.", "Identity.OrganizationUnit.MaxUserMembershipCount": "A maximálisan megengedett szervezeti egység tagsági szám egy felhasználó számára", "ThisUserIsNotActiveMessage": "Ez a felhasználó nem aktív.", "Permission:IdentityManagement": "Identitáskezelés", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Szükséges kisbetű", "DisplayName:Abp.Identity.Password.RequireUppercase": "Szükséges nagybetű", "DisplayName:Abp.Identity.Password.RequireDigit": "Szükséges számjegy", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "A felhasználók szükségesnek tartják a jelszavukat rendszeresen megváltoztatni", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Jelszóváltoztatási időszak napokban", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Engedélyezve az új felhasználók számára", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "A zárolás időtartama (másodpercben)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max sikertelen hozzáférési kísérlet", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Ha a jelszavaknak kisbetűs ASCII karaktert kell tartalmazniuk.", "Description:Abp.Identity.Password.RequireUppercase": "Ha a jelszavaknak nagybetűs ASCII karaktert kell tartalmazniuk.", "Description:Abp.Identity.Password.RequireDigit": "Ha a jelszavaknak tartalmazniuk kell egy számjegyet.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Ha a felhasználók szükségesnek tartják a jelszavukat rendszeresen megváltoztatni.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "A jelszóváltoztatási időszak napokban.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Egy új felhasználó zárolható-e.", "Description:Abp.Identity.Lockout.LockoutDuration": "Az az időtartam, amelyre a felhasználó zárolva van, amikor zárolás történik.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "A felhasználó zárolása előtt megengedett sikertelen hozzáférési kísérletek száma, feltéve, hogy a zárolás engedélyezve van.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Meg tudja e módosítani a felhasználónevet a felhasználó?.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Meg tudja-e módosítani az e-mail címét a felhasználó." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json index d80b315c91..c0bb4af19a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Ekki er hægt að eyða static hlutverkum.", "Volo.Abp.Identity:010007": "Þú getur ekki breytt tveggja þátta stillingu þinni.", "Volo.Abp.Identity:010008": "Það er ekki leyfilegt að breyta tvíþátta stillingu.", + "Volo.Abp.Identity:010009": "Þú getur ekki delegað þér sjálfum.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Hámarks leyfileg fjöldi aðildar að skipulagseiningu fyrir notanda", "ThisUserIsNotActiveMessage": "Þessi notandi er ekki virkur.", "Permission:IdentityManagement": "Auðkenninga umsjón", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Nauðsynlegt að hafa lágstaf", "DisplayName:Abp.Identity.Password.RequireUppercase": "Nauðsynlegt að hafa hágstaf", "DisplayName:Abp.Identity.Password.RequireDigit": "Nauðsynlegt að hafa tölustaf", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Þvinga notendur til að breyta lykilorði á ákveðnum tímabilum", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Tímabil á milli lykilorðabreytinga (dagar)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Virkt fyrir nýja notendur", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Lengd lokunar (sekúndur)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Hámarks misheppnaðra aðgangsstilrauna", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Ef lykilorð verða að innihalda lágstaf ASCII staf.", "Description:Abp.Identity.Password.RequireUppercase": "Ef lykilorð verða að innihalda hástafi ASCII staf.", "Description:Abp.Identity.Password.RequireDigit": "Ef lykilorð verða að innihalda tölustaf.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Hvort notendur verði að breyta lykilorði á ákveðnum tímabilum.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Tímabil á milli lykilorðabreytinga (dagar).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Hvort hægt sé að læsa nýjum notanda.", "Description:Abp.Identity.Lockout.LockoutDuration": "Tímalengd þess að notandi er læstur úti þegar lokun á sér stað.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Fjöldi misheppnaðra aðgangstilrauna sem leyfður er áður en notandi er læstur út, að því gefnu að útilokun sé virk.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Hvort notandi geti uppfært notanda nafnið sitt.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Hvort notandinn getur uppfært tölvupóstfangið sitt." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json index d486248b4d..513def4b52 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "I ruoli statici non possono essere eliminati.", "Volo.Abp.Identity:010007": "Non puoi modificare l'impostazione dei due fattori.", "Volo.Abp.Identity:010008": "Non è consentito modificare l'impostazione a due fattori.", + "Volo.Abp.Identity:010009": "Non puoi delegare te stesso.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Numero massimo consentito di membri dell'unità organizzativa per un utente", "ThisUserIsNotActiveMessage": "Questo utente non è attivo.", "Permission:IdentityManagement": "Gestione identità", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Carattere minuscolo richiesto", "DisplayName:Abp.Identity.Password.RequireUppercase": "Carattere maiuscolo obbligatorio", "DisplayName:Abp.Identity.Password.RequireDigit": "Cifra richiesta", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Forza gli utenti a cambiare la password periodicamente", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Periodo di cambio password (giorni)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Abilitato per i nuovi utenti", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Durata blocco (secondi)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Numero massimo di tentativi di accesso non riusciti", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Se la password deve contenere un carattere ASCII minuscolo.", "Description:Abp.Identity.Password.RequireUppercase": "Se la password deve contenere un carattere ASCII maiuscolo.", "Description:Abp.Identity.Password.RequireDigit": "Se la password devono contenere una cifra.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Se gli utenti devono cambiare la password periodicamente.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Il numero di giorni dopo i quali gli utenti devono cambiare la password.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Se un nuovo utente può essere bloccato.", "Description:Abp.Identity.Lockout.LockoutDuration": "La durata per cui un utente viene bloccato quando si verifica un blocco.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Il numero di tentativi di accesso non riusciti consentiti prima che un utente venga bloccato, a condizione che il blocco sia abilitato.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Se il nome utente può essere aggiornato dall'utente.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Se l'email può essere aggiornata dall'utente." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json index 476ccd6ed5..472935418b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statische rollen kunnen niet worden verwijderd.", "Volo.Abp.Identity:010007": "U kunt uw instelling voor tweefactor authenticatie niet wijzigen.", "Volo.Abp.Identity:010008": "Het is niet toegestaan om de instelling van tweefactor authenticatie te wijzigen.", + "Volo.Abp.Identity:010009": "U kunt uzelf niet delegeren.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximaal toegestande aantal lidmaatschappen van organisatie-eenheden voor een gebruiker", "ThisUserIsNotActiveMessage": "Deze gebruiker is niet actief.", "Permission:IdentityManagement": "Identiteitsbeheer", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Vereist kleine letter", "DisplayName:Abp.Identity.Password.RequireUppercase": "Vereist hoofdletter", "DisplayName:Abp.Identity.Password.RequireDigit": "Vereist cijfer", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Forceer gebruikers om periodiek hun wachtwoord te wijzigen", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Wachtwoord wijzigen periode (dagen)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Ingeschakeld voor nieuwe gebruikers", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Blokkeringsduur (seconden)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Max mislukte toegangspogingen", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Als wachtwoorden een ASCII-teken in kleine letters moeten bevatten.", "Description:Abp.Identity.Password.RequireUppercase": "Als wachtwoorden een ASCII-teken in hoofdletters moeten bevatten.", "Description:Abp.Identity.Password.RequireDigit": "Als wachtwoorden een cijfer moeten bevatten.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Of gebruikers verplicht zijn om hun wachtwoord periodiek te wijzigen.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Het aantal dagen dat een gebruiker zijn wachtwoord moet wijzigen nadat het is ingesteld.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Of een nieuwe gebruiker kan worden geblokkeerd.", "Description:Abp.Identity.Lockout.LockoutDuration": "De duur dat een gebruiker wordt geblokkeerd wanneer een blokkering optreedt.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Het aantal mislukte toegangspogingen dat is toegestaan voordat een gebruiker wordt geblokkeerd, ervan uitgaande dat blokkering is ingeschakeld.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Of de gebruikersnaam kan worden bijgewerkt door de gebruiker.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Of de e-mail door de gebruiker kan worden veranderd." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json index 8acea51398..377c792ddf 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statyczna rola nie może zostać usunięta.", "Volo.Abp.Identity:010007": "Nie możesz zmienić ustawienia dwóch czynników.", "Volo.Abp.Identity:010008": "Nie wolno zmieniać ustawienia dwuczynnikowego.", + "Volo.Abp.Identity:010009": "Nie możesz delegować swoich uprawnień.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maksymalna dozwolona liczba członków jednostki organizacyjnej dla użytkownika", "ThisUserIsNotActiveMessage": "Ten użytkownik nie jest aktywny.", "Permission:IdentityManagement": "Zarządzanie tożsamością", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Wymagana mała litera", "DisplayName:Abp.Identity.Password.RequireUppercase": "Wymagana wielka litera", "DisplayName:Abp.Identity.Password.RequireDigit": "Wymagana cyfra", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Wymuś użytkownikom okresowe zmiany hasła", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Okres zmiany hasła (dni)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Włączone dla nowych użytkowników", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Czas trwania blokady (sekundy)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maksymalna liczba nieudanych prób dostępu", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Jeśli hasła muszą zawierać małą literę ASCII.", "Description:Abp.Identity.Password.RequireUppercase": "Jeśli hasła muszą zawierać wielką literę ASCII.", "Description:Abp.Identity.Password.RequireDigit": "Jeśli hasła muszą zawierać cyfrę.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Czy użytkownicy muszą okresowo zmieniać hasło.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Okres zmiany hasła (dni).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Czy można zablokować nowego użytkownika.", "Description:Abp.Identity.Lockout.LockoutDuration": "Czas, na jaki użytkownik jest zablokowany, gdy nastąpi blokada.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Liczba nieudanych prób dostępu dopuszczonych przed zablokowaniem użytkownika, przy założeniu, że blokada jest włączona.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Czy nazwa użytkownika może być aktualizowana przez użytkownika.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Czy wiadomość e-mail może zostać zaktualizowana przez użytkownika." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json index 5b96b8e88d..c8807d2792 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Perfis estáticos não podem ser excluídos.", "Volo.Abp.Identity:010007": "Você não pode alterar sua configuração de dois fatores.", "Volo.Abp.Identity:010008": "Não é permitido alterar a configuração de dois fatores.", + "Volo.Abp.Identity:010009": "Você não pode delegar a si mesmo.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Contagem máxima permitida de membros da unidade organizacional para um usuário", "ThisUserIsNotActiveMessage": "Este usuário não está ativo.", "Permission:IdentityManagement": "Acessos", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Caractere minúsculo obrigatório", "DisplayName:Abp.Identity.Password.RequireUppercase": "Caractere maiúsculo obrigatório", "DisplayName:Abp.Identity.Password.RequireDigit": "Dígito requerido", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Forçar usuários a alterar a senha periodicamente", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Período de alteração de senha (dias)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Habilitado para novos usuários", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Duração do bloqueio (segundos)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Máximo de tentativas de acesso malsucedidas", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Se as senhas devem conter um caractere ASCII minúsculo.", "Description:Abp.Identity.Password.RequireUppercase": "Se as senhas devem conter um caractere ASCII maiúsculo.", "Description:Abp.Identity.Password.RequireDigit": "Se as senhas devem conter um dígito.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Se os usuários devem alterar sua senha periodicamente.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "O período de dias que um usuário deve esperar antes de alterar sua senha novamente.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Se um novo usuário pode ser bloqueado.", "Description:Abp.Identity.Lockout.LockoutDuration": "A duração que um usuário fica bloqueado quando ocorre um bloqueio.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "O número de tentativas de acesso malsucedidas permitidas antes que um usuário seja bloqueado, assumindo que o bloqueio esteja habilitado.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Se o nome de usuário pode ser atualizado pelo usuário.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Se o e-mail pode ser atualizado pelo usuário." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json index f9c49a7d42..d86eb4f1fa 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Rolurile statice nu pot fi şterse.", "Volo.Abp.Identity:010007": "Nu vă puteţi schimba setările de autentificare în doi paşi.", "Volo.Abp.Identity:010008": "Nu este permisă modificarea setărilor autentificării în doi paşi.", + "Volo.Abp.Identity:010009": "Nu vă puteţi delega singur.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Numărul maxim de unităţi organizaţionale permise pentru un utilizator", "ThisUserIsNotActiveMessage": "Acest utilizator nu este activ.", "Permission:IdentityManagement": "Administrare identităţii", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Numărul de caractere", "DisplayName:Abp.Identity.Password.RequireUppercase": "Numărul de caractere cu majusculă", "DisplayName:Abp.Identity.Password.RequireDigit": "Numărul de cifre", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Forţează utilizatorii să schimbe parola periodic", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Perioada de schimbare a parolei (zile)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Activat pentru noi utilizatori", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Durata blocării (secunde)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Numărul maxim de încercări de acces eşuate", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Dacă parolele trebuie să conţină un caracter ASCII.", "Description:Abp.Identity.Password.RequireUppercase": "Dacă parolele trebuie să conţină un caracter ASCII cu majusculă.", "Description:Abp.Identity.Password.RequireDigit": "Dacă parolele trebuie să conţină o cifră.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Dacă utilizatorii trebuie să schimbe parola periodic.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Perioada de schimbare a parolei (zile).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Dacă un utilizator nou poate fi blocat.", "Description:Abp.Identity.Lockout.LockoutDuration": "Durata blocării unui utilizator când intervine blocarea.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Numărul de accesări eşuate permise înainte de a bloca un utilizator, presupunând că blocarea este activată.", diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json index 23657b6e5a..73fd937af0 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Статические роли не могут быть удалены.", "Volo.Abp.Identity:010007": "Вы не можете изменить настройку двух факторов.", "Volo.Abp.Identity:010008": "Изменение двухфакторной настройки не допускается.", + "Volo.Abp.Identity:010009": "Вы не можете делегировать свои собственные права.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Максимально допустимое количество членов организационного подразделения для пользователя", "ThisUserIsNotActiveMessage": "Этот пользователь не активен.", "Permission:IdentityManagement": "Управление идентификацией", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Обязательный символ нижнего регистра", "DisplayName:Abp.Identity.Password.RequireUppercase": "Обязательный символ верхнего регистра", "DisplayName:Abp.Identity.Password.RequireDigit": "Требуемая цифра", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Требовать периодическое изменение пароля", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Периодичность изменения пароля (дни)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Включено для новых пользователей", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Длительность блокировки (секунды)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Максимальное количество неудачных попыток доступа", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Если пароли должны содержать строчные символы ASCII.", "Description:Abp.Identity.Password.RequireUppercase": "Если пароли должны содержать символ ASCII в верхнем регистре.", "Description:Abp.Identity.Password.RequireDigit": "Если пароли должны содержать цифру.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Если пользователи должны периодически изменять пароль.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Периодичность изменения пароля (дни).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Может ли новый пользователь быть заблокирован.", "Description:Abp.Identity.Lockout.LockoutDuration": "Длительность блокировки пользователя.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Число неудачных попыток доступа, после которых пользователь будет заблокирован.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Может ли пользователь обновить имя пользователя.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Может ли электронная почта быть обновлена пользователем." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json index f6792914c3..83eb3850ad 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statické roly nie je možné zmazať.", "Volo.Abp.Identity:010007": "Dvojfaktorové nastavenie nie je možné zmeniť.", "Volo.Abp.Identity:010008": "Dvojfaktorové nastavenie nie je povolené zmeniť.", + "Volo.Abp.Identity:010009": "Nemôžete delegovať svoje vlastné oprávnenia.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Maximálny povolený počet členov organizačnej jednotky pre používateľa", "ThisUserIsNotActiveMessage": "Tento používateľ nie je aktívny.", "Permission:IdentityManagement": "Správa identít", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Požadované malé písmeno", "DisplayName:Abp.Identity.Password.RequireUppercase": "Požadované veľké písmeno", "DisplayName:Abp.Identity.Password.RequireDigit": "Požadovaná číslica", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Vynútiť používateľom pravidelne meniť heslo", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Doba platnosti hesla (v dňoch)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Povolené pre nových používateľov", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Trvanie uzamknutia (v sekundách)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maximálny počet neúspešných pokusov o prístup", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Či heslá musia obsahovať malé ASCII písmená.", "Description:Abp.Identity.Password.RequireUppercase": "Či heslá musia obsahovať veľké ASCII písmená.", "Description:Abp.Identity.Password.RequireDigit": "Či heslá musia obsahovať číslicu.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Či sa používateľom musí pravidelne meniť heslo.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Doba platnosti hesla (v dňoch).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Či môže byť nový používateľ uzamknutý.", "Description:Abp.Identity.Lockout.LockoutDuration": "Doba, počas ktorej je používateľ uzamknutý, keď dôjde k uzamknutiu.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Počet neúspešných pokusov o prístup pred tým, ako bol používateľ uzamknutý za predpokladu, že je uzamknutie povolené.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Či môže používateľ aktualizovať používateľské meno.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Či môže používateľ aktualizovať email." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json index c775c3e234..caa60a2d71 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Statičnih vlog ni mogoče izbrisati.", "Volo.Abp.Identity:010007": "Nastavitve dveh faktorjev ne morete spremeniti.", "Volo.Abp.Identity:010008": "Ni dovoljeno spreminjati nastavitve dveh faktorjev.", + "Volo.Abp.Identity:010009": "Ne morete delegirati svojih pravic.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Največje dovoljeno število članov v organizacijski enoti za uporabnika", "ThisUserIsNotActiveMessage": "Ta uporabnik ni aktiven.", "Permission:IdentityManagement": "Upravljanje identitet", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Zahtevana mala črka", "DisplayName:Abp.Identity.Password.RequireUppercase": "Zahtevana velika črka", "DisplayName:Abp.Identity.Password.RequireDigit": "Zahtevana številka", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Vsakih X dni zahtevaj spremembo gesla", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Število dni, ki jih uporabnik lahko uporablja isto geslo", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Omogočeno za nove uporabnike", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Trajanje zaklepa(sekund)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Največje število neuspešnih poskusov dostopa", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Ali morajo gesla vsebovati mali ASCII znak.", "Description:Abp.Identity.Password.RequireUppercase": "Ali morajo gesla vsebovati veliki ASCII znak.", "Description:Abp.Identity.Password.RequireDigit": "Ali morajo gesla vsebovati številko.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Ali morajo uporabniki spremeniti geslo vsakih X dni.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Število dni, ki jih uporabnik lahko uporablja isto geslo.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Ali se nov uporabnik lahko zaklene.", "Description:Abp.Identity.Lockout.LockoutDuration": "Trajanje zaklepa uporabnika, ko pride do zaklepa.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Število neuspelih poskusov dostopa ki so dovoljeni, preden se uporabnik zaklene, ob predpostavki, da je zaklepanje omogočeno.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Ali lahko uporabnik posodobi uporabniško ime.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Ali lahko uporabnik posodobi e-poštni naslov." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json index 0c94889184..c8957dc3e7 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Bir Sabit rol silinemez.", "Volo.Abp.Identity:010007": "İki faktörlü ayarınızı değiştiremezsiniz.", "Volo.Abp.Identity:010008": "İki faktörlü ayarın değiştirilmesine izin verilmez.", + "Volo.Abp.Identity:010009": "Kendinizi yetkilendiremezsiniz.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Bir kullanıcı için izin verilen en fazla organizasyon birimi sayısı", "ThisUserIsNotActiveMessage": "Bu kullanıcı aktif değil.", "Permission:IdentityManagement": "Kimlik yönetimi", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Küçük harf gerekli", "DisplayName:Abp.Identity.Password.RequireUppercase": "Büyük harf gerekli", "DisplayName:Abp.Identity.Password.RequireDigit": "Rakam gerekli", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Kullanıcıların periyodik olarak şifrelerini değiştirmelerini zorla", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Şifre değiştirme periyodu (gün)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Yeni kullanıcılar için aktif", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Kilitli kalma süresi (saniye)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Maksimum başarısız giriş denemesi", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Parolaların küçük harfli bir ASCII karakteri içermesi gerekiyorsa.", "Description:Abp.Identity.Password.RequireUppercase": "Parolaların büyük harfli bir ASCII karakteri içermesi gerekiyorsa.", "Description:Abp.Identity.Password.RequireDigit": "Parolaların bir rakam içermesi gerekiyorsa.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Kullanıcıların periyodik olarak şifrelerini değiştirmelerini zorla.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Kullanıcıların şifrelerini değiştirmeleri gereken gün sayısı.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Yeni kullanıcılar kilitlenebilir.", "Description:Abp.Identity.Lockout.LockoutDuration": "Kilitlenme olduğunda, ne kadar kilitli kalacağı.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Kilitleme etkin olduğunda, kullanıcıya kilitlenmeden önce izin verilen başarısız giriş sayısı.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Kullanıcı adının, kullanıcının kendisi tarafından güncellenebilirliği.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "E-posta alanının, kullanıcının kendisi tarafından güncellenebilirliği" } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json index 1cb39cec2a..05dbe248a0 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "Vai trò này là cố định không được phép xóa.", "Volo.Abp.Identity:010007": "Bạn không thể thay đổi cài đặt hai yếu tố của mình.", "Volo.Abp.Identity:010008": "Không được phép thay đổi cài đặt hai yếu tố.", + "Volo.Abp.Identity:010009": "Bạn không thể ủy quyền cho chính mình.", "Identity.OrganizationUnit.MaxUserMembershipCount": "Số lượng thành viên đơn vị tổ chức tối đa được phép cho một người dùng", "ThisUserIsNotActiveMessage": "Người dùng này không hoạt động.", "Permission:IdentityManagement": "Quản lý danh tính", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "Ký tự viết thường bắt buộc", "DisplayName:Abp.Identity.Password.RequireUppercase": "Ký tự viết hoa bắt buộc", "DisplayName:Abp.Identity.Password.RequireDigit": "Chữ số bắt buộc", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Buộc người dùng thay đổi mật khẩu định kỳ", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "Thời gian thay đổi mật khẩu (ngày)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "Đã bật cho người dùng mới", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "Thời gian khóa (giây)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Số lần truy cập không thành công tối đa", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "Nếu mật khẩu phải chứa ký tự ASCII viết thường.", "Description:Abp.Identity.Password.RequireUppercase": "Nếu mật khẩu phải chứa ký tự ASCII viết hoa.", "Description:Abp.Identity.Password.RequireDigit": "Nếu mật khẩu phải chứa một chữ số.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "Nếu người dùng phải thay đổi mật khẩu của họ định kỳ.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "Số ngày mà người dùng phải thay đổi mật khẩu của họ.", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "Người dùng mới có thể bị khóa hay không.", "Description:Abp.Identity.Lockout.LockoutDuration": "Khoảng thời gian người dùng bị khóa khi xảy ra quá trình khóa.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "Số lần truy cập không thành công được phép trước khi người dùng bị khóa, giả sử tính năng khóa được bật.", @@ -110,4 +115,4 @@ "Description:Abp.Identity.User.IsUserNameUpdateEnabled": "Người dùng có thể cập nhật tên người dùng hay không.", "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Người dùng có thể cập nhật email hay không." } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json index c622c1a310..095f5cef2f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "无法删除静态角色.", "Volo.Abp.Identity:010007": "你不能修改你的双因素身份验证设置", "Volo.Abp.Identity:010008": "不允许修改双因素身份验证设置.", + "Volo.Abp.Identity:010009": "你不能委托给自己.", "Identity.OrganizationUnit.MaxUserMembershipCount": "组织单位最大允许的成员资格计数", "ThisUserIsNotActiveMessage": "该用户不可用.", "Permission:IdentityManagement": "身份标识管理", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "要求小写字母", "DisplayName:Abp.Identity.Password.RequireUppercase": "要求大写字母", "DisplayName:Abp.Identity.Password.RequireDigit": "要求数字", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "强制用户定期更改密码", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "密码更改周期(天)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "允许新用户", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "锁定时间(秒)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "最大失败访问尝试次数", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "密码是否必须包含小写字母.", "Description:Abp.Identity.Password.RequireUppercase": "密码是否必须包含大写字母.", "Description:Abp.Identity.Password.RequireDigit": "密码是否必须包含数字.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "是否强制用户定期更改密码.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "用户必须更改密码的周期(天).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "允许新用户被锁定.", "Description:Abp.Identity.Lockout.LockoutDuration": "当锁定发生时用户被的锁定的时间(秒).", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "如果启用锁定, 当用户被锁定前失败的访问尝试次数.", diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json index 99be7e03bf..936ad985f6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json @@ -71,6 +71,7 @@ "Volo.Abp.Identity:010006": "無法刪除靜態角色.", "Volo.Abp.Identity:010007": "你不能修改你的雙因素身份驗證設置", "Volo.Abp.Identity:010008": "不允許修改雙因素身份驗證設置.", + "Volo.Abp.Identity:010009": "你不能委派給自己", "Identity.OrganizationUnit.MaxUserMembershipCount": "允許一個使用者至多可隸屬在幾個組織單位", "ThisUserIsNotActiveMessage": "該用戶不可用.", "Permission:IdentityManagement": "身份識別管理", @@ -87,6 +88,8 @@ "DisplayName:Abp.Identity.Password.RequireLowercase": "需小寫字元", "DisplayName:Abp.Identity.Password.RequireUppercase": "需大寫字元", "DisplayName:Abp.Identity.Password.RequireDigit": "需要數字", + "DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "強制使用者定期更改密碼", + "DisplayName:Abp.Identity.Password.PasswordChangePeriodDays": "密碼更改週期(天)", "DisplayName:Abp.Identity.Lockout.AllowedForNewUsers": "允許新的使用者", "DisplayName:Abp.Identity.Lockout.LockoutDuration": "被鎖定期間(秒)", "DisplayName:Abp.Identity.Lockout.MaxFailedAccessAttempts": "最大登入次數嘗試", @@ -101,6 +104,8 @@ "Description:Abp.Identity.Password.RequireLowercase": "須包含小寫字母.", "Description:Abp.Identity.Password.RequireUppercase": "須包含大寫字母.", "Description:Abp.Identity.Password.RequireDigit": "密碼必須包含數字.", + "Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword": "強制使用者定期更改密碼.", + "Description:Abp.Identity.Password.PasswordChangePeriodDays": "密碼更改週期(天).", "Description:Abp.Identity.Lockout.AllowedForNewUsers": "使用者是否會被鎖定.", "Description:Abp.Identity.Lockout.LockoutDuration": "使用者被鎖定後的時間.", "Description:Abp.Identity.Lockout.MaxFailedAccessAttempts": "當啟用鎖定功能,設定最大嘗試輸入次數,超過後就被鎖定.", diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Settings/IdentitySettingNames.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Settings/IdentitySettingNames.cs index 70c2430751..9c2b44cb4b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Settings/IdentitySettingNames.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Settings/IdentitySettingNames.cs @@ -14,6 +14,8 @@ public static class IdentitySettingNames public const string RequireLowercase = PasswordPrefix + ".RequireLowercase"; public const string RequireUppercase = PasswordPrefix + ".RequireUppercase"; public const string RequireDigit = PasswordPrefix + ".RequireDigit"; + public const string ForceUsersToPeriodicallyChangePassword = PasswordPrefix + ".ForceUsersToPeriodicallyChangePassword"; + public const string PasswordChangePeriodDays = PasswordPrefix + ".PasswordChangePeriodDays"; } public static class Lockout diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs index 79b4afaa05..eb01525e15 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs @@ -52,6 +52,20 @@ public class AbpIdentitySettingDefinitionProvider : SettingDefinitionProvider L("Description:Abp.Identity.Password.RequireDigit"), true), + new SettingDefinition( + IdentitySettingNames.Password.ForceUsersToPeriodicallyChangePassword, + false.ToString(), + L("DisplayName:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword"), + L("Description:Abp.Identity.Password.ForceUsersToPeriodicallyChangePassword"), + true), + + new SettingDefinition( + IdentitySettingNames.Password.PasswordChangePeriodDays, + 0.ToString(), + L("DisplayName:Abp.Identity.Password.PasswordChangePeriodDays"), + L("Description:Abp.Identity.Password.PasswordChangePeriodDays"), + true), + new SettingDefinition( IdentitySettingNames.Lockout.AllowedForNewUsers, true.ToString(), diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserDelegationRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserDelegationRepository.cs new file mode 100644 index 0000000000..360b9c494c --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserDelegationRepository.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Identity; + +public interface IIdentityUserDelegationRepository: IBasicRepository +{ + Task> GetListAsync( + Guid? sourceUserId, + Guid? targetUserId, + CancellationToken cancellationToken = default); + + Task> GetActiveDelegationsAsync( + Guid targetUserId, + CancellationToken cancellationToken = default); + + Task FindActiveDelegationByIdAsync( + Guid id, + CancellationToken cancellationToken = default); +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs index d2a049dd84..d8b3543703 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs @@ -125,4 +125,10 @@ public interface IIdentityUserRepository : IBasicRepository bool includeDetails = true, CancellationToken cancellationToken = default ); + + Task> GetListByIdsAsync( + IEnumerable ids, + bool includeDetails = false, + CancellationToken cancellationToken = default + ); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs index c7aceb7bf9..ec5db2fe90 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs @@ -112,11 +112,21 @@ public class IdentityUser : FullAuditedAggregateRoot, IUser, IHasEntityVer ///
public virtual int AccessFailedCount { get; protected internal set; } + /// + /// Should change password on next login. + /// + public virtual bool ShouldChangePasswordOnNextLogin { get; protected internal set; } + /// /// A version value that is increased whenever the entity is changed. /// public virtual int EntityVersion { get; protected set; } + /// + /// Gets or sets the last password change time for the user. + /// + public virtual DateTimeOffset? LastPasswordChangeTime { get; protected set; } + //TODO: Can we make collections readonly collection, which will provide encapsulation. But... can work for all ORMs? /// @@ -368,6 +378,16 @@ public class IdentityUser : FullAuditedAggregateRoot, IUser, IHasEntityVer IsActive = isActive; } + public virtual void SetShouldChangePasswordOnNextLogin(bool shouldChangePasswordOnNextLogin) + { + ShouldChangePasswordOnNextLogin = shouldChangePasswordOnNextLogin; + } + + public virtual void SetLastPasswordChangeTime(DateTimeOffset? lastPasswordChangeTime) + { + LastPasswordChangeTime = lastPasswordChangeTime; + } + public override string ToString() { return $"{base.ToString()}, UserName = {UserName}"; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegation.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegation.cs new file mode 100644 index 0000000000..8cab00f882 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegation.cs @@ -0,0 +1,41 @@ +using System; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity; + +public class IdentityUserDelegation : BasicAggregateRoot, IMultiTenant +{ + public virtual Guid? TenantId { get; protected set; } + + public virtual Guid SourceUserId { get; protected set; } + + public virtual Guid TargetUserId { get; protected set; } + + public virtual DateTime StartTime { get; protected set; } + + public virtual DateTime EndTime { get; protected set; } + + /// + /// Initializes a new instance of . + /// + protected IdentityUserDelegation() + { + } + + public IdentityUserDelegation( + Guid id, + Guid sourceUserId, + Guid targetUserId, + DateTime startTime, + DateTime endTime, + Guid? tenantId = null) + : base(id) + { + TenantId = tenantId; + SourceUserId = sourceUserId; + TargetUserId = targetUserId; + StartTime = startTime; + EndTime = endTime; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegationManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegationManager.cs new file mode 100644 index 0000000000..8fd4c444f5 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserDelegationManager.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; + +namespace Volo.Abp.Identity; + +public class IdentityUserDelegationManager : DomainService +{ + protected IIdentityUserDelegationRepository IdentityUserDelegationRepository { get; } + + public IdentityUserDelegationManager(IIdentityUserDelegationRepository identityUserDelegationRepository) + { + IdentityUserDelegationRepository = identityUserDelegationRepository; + } + + public virtual async Task> GetListAsync(Guid? sourceUserId = null, Guid? targetUserId = null, CancellationToken cancellationToken = default) + { + return await IdentityUserDelegationRepository.GetListAsync(sourceUserId, targetUserId, cancellationToken: cancellationToken); + } + + public virtual async Task> GetActiveDelegationsAsync(Guid targetUseId, CancellationToken cancellationToken = default) + { + return await IdentityUserDelegationRepository.GetActiveDelegationsAsync(targetUseId, cancellationToken: cancellationToken); + } + + public virtual async Task FindActiveDelegationByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + return await IdentityUserDelegationRepository.FindActiveDelegationByIdAsync(id, cancellationToken: cancellationToken); + } + + public virtual async Task DelegateNewUserAsync(Guid sourceUserId, Guid targetUserId, DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default) + { + if (sourceUserId == targetUserId) + { + throw new BusinessException(IdentityErrorCodes.YouCannotDelegateYourself); + } + + await IdentityUserDelegationRepository.InsertAsync( + new IdentityUserDelegation( + GuidGenerator.Create(), + sourceUserId, + targetUserId, + startTime, + endTime + ), + cancellationToken: cancellationToken + ); + } + + public virtual async Task DeleteDelegationAsync(Guid id, Guid sourceUserId, CancellationToken cancellationToken = default) + { + var delegation = await IdentityUserDelegationRepository.FindAsync(id, cancellationToken: cancellationToken); + + if (delegation != null && delegation.SourceUserId == sourceUserId) + { + await IdentityUserDelegationRepository.DeleteAsync(delegation, cancellationToken: cancellationToken); + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs index d0520c9ef9..355378b8d0 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs @@ -13,6 +13,7 @@ using Volo.Abp.Domain.Services; using Volo.Abp.Identity.Settings; using Volo.Abp.Settings; using Volo.Abp.Threading; +using Volo.Abp.Timing; using Volo.Abp.Uow; namespace Volo.Abp.Identity; @@ -253,4 +254,25 @@ public class IdentityUserManager : UserManager, IDomainService return await UpdateUserAsync(user); } + + public virtual async Task ShouldPeriodicallyChangePasswordAsync(IdentityUser user) + { + Check.NotNull(user, nameof(user)); + + if (user.PasswordHash.IsNullOrWhiteSpace()) + { + return false; + } + + var forceUsersToPeriodicallyChangePassword = await SettingProvider.GetAsync(IdentitySettingNames.Password.ForceUsersToPeriodicallyChangePassword); + if (!forceUsersToPeriodicallyChangePassword) + { + return false; + } + + var lastPasswordChangeTime = user.LastPasswordChangeTime ?? DateTime.SpecifyKind(user.CreationTime, DateTimeKind.Utc); + var passwordChangePeriodDays = await SettingProvider.GetAsync(IdentitySettingNames.Password.PasswordChangePeriodDays); + + return passwordChangePeriodDays > 0 && lastPasswordChangeTime.AddDays(passwordChangePeriodDays) < DateTime.UtcNow; + } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs index c8c8fd45a9..d7d26e02e1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs @@ -12,6 +12,7 @@ using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Repositories; using Volo.Abp.Guids; +using Volo.Abp.Timing; namespace Volo.Abp.Identity; @@ -268,6 +269,8 @@ public class IdentityUserStore : user.PasswordHash = passwordHash; + user.SetLastPasswordChangeTime(DateTime.UtcNow); + return Task.CompletedTask; } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs index 000781d4ef..1beb15f0b1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnitManager.cs @@ -122,7 +122,7 @@ public class OrganizationUnitManager : DomainService public virtual async Task GetCodeOrDefaultAsync(Guid id) { - var ou = await OrganizationUnitRepository.GetAsync(id); + var ou = await OrganizationUnitRepository.FindAsync(id); return ou?.Code; } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs index 4bfa96d253..a58a73a996 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/AbpIdentityEntityFrameworkCoreModule.cs @@ -19,6 +19,7 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs index 6a0245fa4f..035904120c 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs @@ -20,6 +20,7 @@ public class EfCoreIdentityLinkUserRepository : EfCoreRepository FindAsync(IdentityLinkUserInfo sourceLinkUserInfo, IdentityLinkUserInfo targetLinkUserInfo, CancellationToken cancellationToken = default) { return await (await GetDbSetAsync()) + .AsNoTracking() .OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.SourceUserId == sourceLinkUserInfo.UserId && x.SourceTenantId == sourceLinkUserInfo.TenantId && x.TargetUserId == targetLinkUserInfo.UserId && x.TargetTenantId == targetLinkUserInfo.TenantId || @@ -31,7 +32,8 @@ public class EfCoreIdentityLinkUserRepository : EfCoreRepository> GetListAsync(IdentityLinkUserInfo linkUserInfo, List excludes = null, CancellationToken cancellationToken = default) { - IQueryable query = (await GetDbSetAsync()) + var query = (await GetDbSetAsync()) + .AsNoTracking() .Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId); @@ -51,7 +53,7 @@ public class EfCoreIdentityLinkUserRepository : EfCoreRepository + var linkUsers = await (await GetDbSetAsync()).AsNoTracking().Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserDelegationRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserDelegationRepository.cs new file mode 100644 index 0000000000..cd567ffa80 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserDelegationRepository.cs @@ -0,0 +1,52 @@ +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; +using Volo.Abp.Timing; + +namespace Volo.Abp.Identity.EntityFrameworkCore; + +public class EfCoreIdentityUserDelegationRepository : EfCoreRepository, IIdentityUserDelegationRepository +{ + protected IClock Clock { get; } + + public EfCoreIdentityUserDelegationRepository(IDbContextProvider dbContextProvider, IClock clock) + : base(dbContextProvider) + { + Clock = clock; + } + + public async Task> GetListAsync(Guid? sourceUserId, Guid? targetUserId, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .AsNoTracking() + .WhereIf(sourceUserId.HasValue, x => x.SourceUserId == sourceUserId) + .WhereIf(targetUserId.HasValue, x => x.TargetUserId == targetUserId) + .ToListAsync(cancellationToken: cancellationToken); + } + + public async Task> GetActiveDelegationsAsync(Guid targetUserId, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .AsNoTracking() + .Where(x => x.TargetUserId == targetUserId && + x.StartTime <= Clock.Now && + x.EndTime >= Clock.Now) + .ToListAsync(cancellationToken: cancellationToken); + } + + public async Task FindActiveDelegationByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .AsNoTracking() + .FirstOrDefaultAsync(x => + x.Id == id && + x.StartTime <= Clock.Now && + x.EndTime >= Clock.Now + , cancellationToken: GetCancellationToken(cancellationToken)); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index e2527555b2..60abbb3054 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -348,4 +348,12 @@ public class EfCoreIdentityUserRepository : EfCoreRepository> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .IncludeDetails(includeDetails) + .Where(x => ids.Contains(x.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs index e84b2811c5..2f409a61b2 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs @@ -18,4 +18,6 @@ public interface IIdentityDbContext : IEfCoreDbContext DbSet SecurityLogs { get; } DbSet LinkUsers { get; } + + DbSet UserDelegations { get; } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs index bc2b4dd4b0..79adece5e1 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs @@ -22,6 +22,8 @@ public class IdentityDbContext : AbpDbContext, IIdentityDbCon public DbSet LinkUsers { get; set; } + public DbSet UserDelegations { get; set; } + public IdentityDbContext(DbContextOptions options) : base(options) { diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index 472581fdbd..f85f72e84e 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -270,6 +270,15 @@ public static class IdentityDbContextModelBuilderExtensions }); } + builder.Entity(b => + { + b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "UserDelegations", AbpIdentityDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.ApplyObjectExtensionMappings(); + }); + builder.TryConfigureObjectExtensions(); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs index 1acc952024..90118a534e 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs @@ -19,6 +19,8 @@ public class AbpIdentityMongoDbContext : AbpMongoDbContext, IAbpIdentityMongoDbC public IMongoCollection LinkUsers => Collection(); + public IMongoCollection UserDelegations => Collection(); + protected override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder); diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs index 4816664d68..5ee7ffc47e 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs @@ -37,5 +37,10 @@ public static class AbpIdentityMongoDbContextExtensions { b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "LinkUsers"; }); + + builder.Entity(b => + { + b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "UserDelegations"; + }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs index 85fc619180..35c81b25bb 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs @@ -20,6 +20,7 @@ public class AbpIdentityMongoDbModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs index ad2ae429e1..39bcc23b50 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs @@ -18,4 +18,6 @@ public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext IMongoCollection SecurityLogs { get; } IMongoCollection LinkUsers { get; } + + IMongoCollection UserDelegations { get; } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserDelegationRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserDelegationRepository.cs new file mode 100644 index 0000000000..a782dd57c9 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserDelegationRepository.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; +using Volo.Abp.Timing; + +namespace Volo.Abp.Identity.MongoDB; + +public class MongoIdentityUserDelegationRepository : MongoDbRepository, IIdentityUserDelegationRepository +{ + protected IClock Clock { get; } + + public MongoIdentityUserDelegationRepository(IMongoDbContextProvider dbContextProvider, IClock clock) + : base(dbContextProvider) + { + Clock = clock; + } + + public async Task> GetListAsync(Guid? sourceUserId, Guid? targetUserId, + CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .WhereIf(sourceUserId.HasValue, x => x.SourceUserId == sourceUserId) + .WhereIf(targetUserId.HasValue, x => x.TargetUserId == targetUserId) + .As>() + .ToListAsync(cancellationToken: cancellationToken); + } + + public async Task> GetActiveDelegationsAsync(Guid targetUserId, CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .Where(x => x.TargetUserId == targetUserId) + .Where(x => x.StartTime <= Clock.Now && x.EndTime >= Clock.Now) + .As>() + .ToListAsync(cancellationToken: cancellationToken); + } + + public async Task FindActiveDelegationByIdAsync(Guid id, CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .FirstOrDefaultAsync(x => + x.Id == id && + x.StartTime <= Clock.Now && + x.EndTime >= Clock.Now + , cancellationToken: GetCancellationToken(cancellationToken)); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index ac2ab63809..ae805d9a03 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -316,4 +316,11 @@ public class MongoIdentityUserRepository : MongoDbRepository> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .Where(x => ids.Contains(x.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs index 8949d7dafd..34f933ced4 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs @@ -3,10 +3,12 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Identity.Localization; +using Volo.Abp.Identity.Settings; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement.Identity; +using Volo.Abp.Settings; using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem; using Volo.Abp.Uow; @@ -49,6 +51,11 @@ public class AbpIdentityDomainTestModule : AbpModule { options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; }); + + Configure(options => + { + options.ValueProviders.Add(); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserDelegationManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserDelegationManager_Tests.cs new file mode 100644 index 0000000000..c85f17230f --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserDelegationManager_Tests.cs @@ -0,0 +1,69 @@ +using System; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Identity; + +public class IdentityUserDelegationManager_Tests : AbpIdentityDomainTestBase +{ + protected IdentityUserDelegationManager IdentityUserDelegationManager { get; } + protected IdentityTestData TestData { get; } + + public IdentityUserDelegationManager_Tests() + { + IdentityUserDelegationManager = GetRequiredService(); + TestData = GetRequiredService(); + } + + [Fact] + public async Task GetListAsync() + { + (await IdentityUserDelegationManager.GetListAsync(Guid.NewGuid(), Guid.NewGuid())).Count.ShouldBe(0); + + (await IdentityUserDelegationManager.GetListAsync(TestData.UserJohnId, null)).Count.ShouldBe(2); + + (await IdentityUserDelegationManager.GetListAsync(null, TestData.UserDavidId)).Count.ShouldBe(3); + + (await IdentityUserDelegationManager.GetListAsync(TestData.UserNeoId, TestData.UserDavidId)).Count.ShouldBe(1); + } + + [Fact] + public async Task GetActiveDelegationsAsync() + { + var activeDelegations = await IdentityUserDelegationManager.GetActiveDelegationsAsync(TestData.UserDavidId); + activeDelegations.Count.ShouldBe(2); + activeDelegations[0].SourceUserId.ShouldBe(TestData.UserJohnId); + activeDelegations[0].TargetUserId.ShouldBe(TestData.UserDavidId); + activeDelegations[1].SourceUserId.ShouldBe(TestData.UserNeoId); + activeDelegations[1].TargetUserId.ShouldBe(TestData.UserDavidId); + } + + [Fact] + public async Task FindActiveDelegationByIdAsync() + { + var activeDelegations = await IdentityUserDelegationManager.GetActiveDelegationsAsync(TestData.UserDavidId); + var activeDelegation = await IdentityUserDelegationManager.FindActiveDelegationByIdAsync(activeDelegations[0].Id); + activeDelegation.ShouldNotBeNull(); + activeDelegation.SourceUserId.ShouldBe(TestData.UserJohnId); + activeDelegation.TargetUserId.ShouldBe(TestData.UserDavidId); + } + + [Fact] + public async Task DelegateNewUserAsync() + { + await Should.ThrowAsync(IdentityUserDelegationManager.DelegateNewUserAsync( + TestData.UserJohnId, + TestData.UserJohnId, + DateTime.Now.AddDays(-1), + DateTime.Now)); + + await IdentityUserDelegationManager.DelegateNewUserAsync( + TestData.UserJohnId, + TestData.UserBobId, + DateTime.Now.AddDays(-1), + DateTime.Now.AddDays(1)); + + (await IdentityUserDelegationManager.GetActiveDelegationsAsync(TestData.UserBobId)).Count.ShouldBe(1); + } +} \ No newline at end of file diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs index 29b51a9b54..517313abcd 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityUserManager_Tests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Shouldly; +using Volo.Abp.Identity.Settings; using Volo.Abp.Uow; using Xunit; @@ -214,6 +215,40 @@ public class IdentityUserManager_Tests : AbpIdentityDomainTestBase } } + [Fact] + public async Task ShouldPeriodicallyChangePasswordAsync_Return_False() + { + var user = CreateRandomUser(); + AddPeriodicallyChangePasswordSettings(); + + (await _identityUserManager.CreateAsync(user)).CheckErrors(); + (await _identityUserManager.ShouldPeriodicallyChangePasswordAsync(user)).ShouldBeFalse(); + + await _identityUserManager.AddPasswordAsync(user, IdentityDataSeedContributor.AdminPasswordDefaultValue); + (await _identityUserManager.ShouldPeriodicallyChangePasswordAsync(user)).ShouldBeFalse(); + + user.CreationTime = DateTime.Now; + user.SetLastPasswordChangeTime(null); + (await _identityUserManager.ShouldPeriodicallyChangePasswordAsync(user)).ShouldBeFalse(); + } + + [Fact] + public async Task ShouldPeriodicallyChangePasswordAsync_Return_True() + { + var user = CreateRandomUser(); + AddPeriodicallyChangePasswordSettings(); + + (await _identityUserManager.CreateAsync(user)).CheckErrors(); + await _identityUserManager.AddPasswordAsync(user, IdentityDataSeedContributor.AdminPasswordDefaultValue); + + user.SetLastPasswordChangeTime(DateTime.UtcNow.AddDays(-3)); + (await _identityUserManager.ShouldPeriodicallyChangePasswordAsync(user)).ShouldBeTrue(); + + user.CreationTime = DateTime.Now.AddDays(-3); + user.SetLastPasswordChangeTime(null); + (await _identityUserManager.ShouldPeriodicallyChangePasswordAsync(user)).ShouldBeTrue(); + } + private async Task CreateRandomDefaultRoleAsync() { await _identityRoleRepository.InsertAsync( @@ -235,4 +270,10 @@ public class IdentityUserManager_Tests : AbpIdentityDomainTestBase Guid.NewGuid().ToString() + "@abp.io" ); } + + private static void AddPeriodicallyChangePasswordSettings() + { + TestSettingValueProvider.AddSetting(IdentitySettingNames.Password.PasswordChangePeriodDays, 2.ToString()); + TestSettingValueProvider.AddSetting(IdentitySettingNames.Password.ForceUsersToPeriodicallyChangePassword, true.ToString()); + } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestSettingValueProvider.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestSettingValueProvider.cs new file mode 100644 index 0000000000..e70abe6e1f --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/TestSettingValueProvider.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Settings; + +namespace Volo.Abp.Identity; + +public class TestSettingValueProvider : ISettingValueProvider, ITransientDependency +{ + public const string ProviderName = "Test"; + + private readonly static Dictionary Values = new (); + + public string Name => ProviderName; + + public static void AddSetting(string name, string value) + { + Values[name] = value; + } + + public Task GetOrNullAsync(SettingDefinition setting) + { + return Task.FromResult(Values.GetOrDefault(setting.Name)); + } + + public Task> GetAllAsync(SettingDefinition[] settings) + { + return Task.FromResult(settings.Select(x => new SettingValue(x.Name, Values.GetOrDefault(x.Name))).ToList()); + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentityUserDelegationepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentityUserDelegationepository_Tests.cs new file mode 100644 index 0000000000..92648defe7 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentityUserDelegationepository_Tests.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.Identity.EntityFrameworkCore; + +public class IdentityUserDelegationepository_Tests : IdentityUserDelegationepository_Tests +{ + +} \ No newline at end of file diff --git a/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentityUserDelegationepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentityUserDelegationepository_Tests.cs new file mode 100644 index 0000000000..5fb94b614a --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentityUserDelegationepository_Tests.cs @@ -0,0 +1,9 @@ +using Xunit; + +namespace Volo.Abp.Identity.MongoDB; + +[Collection(MongoTestCollection.Name)] +public class IdentityUserDelegationepository_Tests: IdentityUserDelegationepository_Tests +{ + +} \ No newline at end of file diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs index 788f974b5e..dc2b28690a 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs @@ -22,6 +22,7 @@ public class AbpIdentityTestDataBuilder : ITransientDependency private readonly OrganizationUnitManager _organizationUnitManager; private readonly IIdentityLinkUserRepository _identityLinkUserRepository; private readonly IdentityLinkUserManager _identityLinkUserManager; + private readonly IIdentityUserDelegationRepository _identityUserDelegationRepository; private IdentityRole _adminRole; private IdentityRole _moderatorRole; @@ -42,7 +43,8 @@ public class AbpIdentityTestDataBuilder : ITransientDependency IdentityTestData testData, OrganizationUnitManager organizationUnitManager, IIdentityLinkUserRepository identityLinkUserRepository, - IdentityLinkUserManager identityLinkUserManager) + IdentityLinkUserManager identityLinkUserManager, + IIdentityUserDelegationRepository identityUserDelegationRepository) { _guidGenerator = guidGenerator; _userRepository = userRepository; @@ -55,6 +57,7 @@ public class AbpIdentityTestDataBuilder : ITransientDependency _organizationUnitManager = organizationUnitManager; _identityLinkUserRepository = identityLinkUserRepository; _identityLinkUserManager = identityLinkUserManager; + _identityUserDelegationRepository = identityUserDelegationRepository; _identitySecurityLogRepository = identitySecurityLogRepository; } @@ -66,6 +69,7 @@ public class AbpIdentityTestDataBuilder : ITransientDependency await AddLinkUsers(); await AddClaimTypes(); await AddSecurityLogs(); + await AddUserDelegations(); } private async Task AddRoles() @@ -197,4 +201,28 @@ public class AbpIdentityTestDataBuilder : ITransientDependency CreationTime = new DateTime(2020, 01, 02, 10, 0, 0) })); } + + private async Task AddUserDelegations() + { + await _identityUserDelegationRepository.InsertAsync( + new IdentityUserDelegation(_guidGenerator.Create(), + _testData.UserJohnId, + _testData.UserDavidId, + DateTime.Now.AddDays(-2), + DateTime.Now.AddDays(-1))); + + await _identityUserDelegationRepository.InsertAsync( + new IdentityUserDelegation(_guidGenerator.Create(), + _testData.UserJohnId, + _testData.UserDavidId, + DateTime.Now.AddDays(-1), + DateTime.Now.AddDays(1))); + + await _identityUserDelegationRepository.InsertAsync( + new IdentityUserDelegation(_guidGenerator.Create(), + _testData.UserNeoId, + _testData.UserDavidId, + DateTime.Now.AddDays(-1), + DateTime.Now.AddDays(1))); + } } diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserDelegationepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserDelegationepository_Tests.cs new file mode 100644 index 0000000000..50d5dd8a6f --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserDelegationepository_Tests.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.Abp.Identity; + +public abstract class IdentityUserDelegationepository_Tests : AbpIdentityTestBase + where TStartupModule : IAbpModule +{ + protected IIdentityUserRepository UserRepository { get; } + protected IIdentityUserDelegationRepository IdentityUserDelegationRepository { get; } + protected IdentityTestData TestData { get; } + + public IdentityUserDelegationepository_Tests() + { + UserRepository = GetRequiredService(); + IdentityUserDelegationRepository = GetRequiredService(); + TestData = GetRequiredService(); + } + + [Fact] + public async Task GetListAsync() + { + (await IdentityUserDelegationRepository.GetListAsync(Guid.NewGuid(), Guid.NewGuid())).Count.ShouldBe(0); + + (await IdentityUserDelegationRepository.GetListAsync(TestData.UserJohnId, null)).Count.ShouldBe(2); + + (await IdentityUserDelegationRepository.GetListAsync(null, TestData.UserDavidId)).Count.ShouldBe(3); + + (await IdentityUserDelegationRepository.GetListAsync(TestData.UserNeoId, TestData.UserDavidId)).Count.ShouldBe(1); + } + + [Fact] + public async Task GetActiveDelegationsAsync() + { + var activeDelegations = await IdentityUserDelegationRepository.GetActiveDelegationsAsync(TestData.UserDavidId); + activeDelegations.Count.ShouldBe(2); + activeDelegations[0].SourceUserId.ShouldBe(TestData.UserJohnId); + activeDelegations[0].TargetUserId.ShouldBe(TestData.UserDavidId); + activeDelegations[1].SourceUserId.ShouldBe(TestData.UserNeoId); + activeDelegations[1].TargetUserId.ShouldBe(TestData.UserDavidId); + } + + [Fact] + public async Task GetActiveDelegationOrNullAsync() + { + var activeDelegations = await IdentityUserDelegationRepository.GetActiveDelegationsAsync(TestData.UserDavidId); + var activeDelegation = await IdentityUserDelegationRepository.FindActiveDelegationByIdAsync(activeDelegations[0].Id); + activeDelegation.ShouldNotBeNull(); + activeDelegation.SourceUserId.ShouldBe(TestData.UserJohnId); + activeDelegation.TargetUserId.ShouldBe(TestData.UserDavidId); + } +} \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs index cf69fda91a..b2c7ebecb6 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs @@ -17,8 +17,11 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; +using Volo.Abp.Identity.Settings; using Volo.Abp.IdentityServer.Localization; using Volo.Abp.Security.Claims; +using Volo.Abp.Settings; +using Volo.Abp.Timing; using Volo.Abp.Uow; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -28,7 +31,7 @@ namespace Volo.Abp.IdentityServer.AspNetIdentity; public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { protected SignInManager SignInManager { get; } - protected UserManager UserManager { get; } + protected IdentityUserManager UserManager { get; } protected IdentitySecurityLogManager IdentitySecurityLogManager { get; } protected ILogger> Logger { get; } protected IStringLocalizer Localizer { get; } @@ -36,15 +39,18 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator protected AbpIdentityOptions AbpIdentityOptions { get; } protected IOptions IdentityOptions { get; } + protected ISettingProvider SettingProvider { get; } + public AbpResourceOwnerPasswordValidator( - UserManager userManager, + IdentityUserManager userManager, SignInManager signInManager, IdentitySecurityLogManager identitySecurityLogManager, ILogger> logger, IStringLocalizer localizer, IOptions abpIdentityOptions, IServiceScopeFactory serviceScopeFactory, - IOptions identityOptions) + IOptions identityOptions, + ISettingProvider settingProvider) { UserManager = userManager; SignInManager = signInManager; @@ -54,6 +60,7 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator ServiceScopeFactory = serviceScopeFactory; AbpIdentityOptions = abpIdentityOptions.Value; IdentityOptions = identityOptions; + SettingProvider = settingProvider; } /// @@ -122,6 +129,19 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator else if (result.IsNotAllowed) { Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", context.UserName); + + if (user.ShouldChangePasswordOnNextLogin) + { + await HandleShouldChangePasswordOnNextLoginAsync(context, user, context.Password); + return; + } + + if (await UserManager.ShouldPeriodicallyChangePasswordAsync(user)) + { + await HandlePeriodicallyChangePasswordAsync(context, user, context.Password); + return; + } + errorDescription = Localizer["LoginIsNotAllowed"]; } else @@ -193,6 +213,75 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator } } + protected virtual async Task HandleShouldChangePasswordOnNextLoginAsync(ResourceOwnerPasswordValidationContext context, IdentityUser user, string currentPassword) + { + await HandlerChangePasswordAsync(context, user, currentPassword, ChangePasswordType.ShouldChangePasswordOnNextLogin); + } + + protected virtual async Task HandlePeriodicallyChangePasswordAsync(ResourceOwnerPasswordValidationContext context, IdentityUser user, string currentPassword) + { + await HandlerChangePasswordAsync(context, user, currentPassword, ChangePasswordType.PeriodicallyChangePassword); + } + + protected virtual async Task HandlerChangePasswordAsync(ResourceOwnerPasswordValidationContext context, IdentityUser user, string currentPassword, ChangePasswordType changePasswordType) + { + var changePasswordToken = context.Request?.Raw?["ChangePasswordToken"]; + var newPassword = context.Request?.Raw?["NewPassword"]; + if (!changePasswordToken.IsNullOrWhiteSpace() && !currentPassword.IsNullOrWhiteSpace() && !newPassword.IsNullOrWhiteSpace()) + { + if (await UserManager.VerifyUserTokenAsync(user, TokenOptions.DefaultProvider, changePasswordType.ToString(), changePasswordToken)) + { + var changePasswordResult = await UserManager.ChangePasswordAsync(user, currentPassword, newPassword); + if (changePasswordResult.Succeeded) + { + await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext + { + Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer, + Action = IdentitySecurityLogActionConsts.ChangePassword, + UserName = context.UserName, + ClientId = await FindClientIdAsync(context) + }); + + if (changePasswordType == ChangePasswordType.ShouldChangePasswordOnNextLogin) + { + user.SetShouldChangePasswordOnNextLogin(false); + } + + await UserManager.UpdateAsync(user); + await SetSuccessResultAsync(context, user); + } + else + { + Logger.LogInformation("ChangePassword failed for username: {username}, reason: {changePasswordResult}", context.UserName, changePasswordResult); + context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, changePasswordResult.Errors.Select(x => x.Description).JoinAsString(", ")); + } + } + else + { + Logger.LogInformation("Authentication failed for username: {username}, reason: InvalidAuthenticatorCode", context.UserName); + context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, Localizer["InvalidAuthenticatorCode"]); + } + } + else + { + Logger.LogInformation($"Authentication failed for username: {{{context.UserName}}}, reason: {{{changePasswordType.ToString()}}}"); + context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, nameof(user.ShouldChangePasswordOnNextLogin), + new Dictionary() + { + {"userId", user.Id}, + {"changePasswordToken", await UserManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, changePasswordType.ToString())} + }); + + await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext + { + Identity = IdentityServerSecurityLogIdentityConsts.IdentityServer, + Action = IdentityServerSecurityLogActionConsts.LoginNotAllowed, + UserName = context.UserName, + ClientId = await FindClientIdAsync(context) + }); + } + } + protected virtual async Task SetSuccessResultAsync(ResourceOwnerPasswordValidationContext context, IdentityUser user) { var sub = await UserManager.GetUserIdAsync(user); @@ -266,4 +355,10 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator return Task.CompletedTask; } + + public enum ChangePasswordType + { + ShouldChangePasswordOnNextLogin, + PeriodicallyChangePassword + } } diff --git a/modules/openiddict/app/OpenIddict.Demo.Client.Mvc/Pages/Index.cshtml b/modules/openiddict/app/OpenIddict.Demo.Client.Mvc/Pages/Index.cshtml index d2f8710862..ca7e62a411 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Client.Mvc/Pages/Index.cshtml +++ b/modules/openiddict/app/OpenIddict.Demo.Client.Mvc/Pages/Index.cshtml @@ -9,7 +9,7 @@
Login - Loout + Logout @if (HttpContext.User.Identity != null && HttpContext.User.Identity.IsAuthenticated) { diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230106050616_Initial.Designer.cs b/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.Designer.cs similarity index 98% rename from modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230106050616_Initial.Designer.cs rename to modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.Designer.cs index 64ad616624..34487a75a8 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230106050616_Initial.Designer.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace OpenIddict.Demo.Server.Migrations { [DbContext(typeof(ServerDbContext))] - [Migration("20230106050616_Initial")] + [Migration("20230404033745_Initial")] partial class Initial { /// @@ -235,6 +235,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -421,6 +424,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasDefaultValue(false) .HasColumnName("EmailConfirmed"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -449,6 +455,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -497,6 +506,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -699,6 +711,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("nvarchar(128)") .HasColumnName("DisplayName"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1277,6 +1292,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230106050616_Initial.cs b/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.cs similarity index 98% rename from modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230106050616_Initial.cs rename to modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.cs index 611a9ad2ca..611109065a 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230106050616_Initial.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.cs @@ -106,6 +106,7 @@ namespace OpenIddict.Demo.Server.Migrations ParentId = table.Column(type: "uniqueidentifier", nullable: true), Code = table.Column(type: "nvarchar(95)", maxLength: 95, nullable: false), DisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -186,6 +187,7 @@ namespace OpenIddict.Demo.Server.Migrations IsDefault = table.Column(type: "bit", nullable: false), IsStatic = table.Column(type: "bit", nullable: false), IsPublic = table.Column(type: "bit", nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) }, @@ -240,6 +242,7 @@ namespace OpenIddict.Demo.Server.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -278,6 +281,9 @@ namespace OpenIddict.Demo.Server.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/ServerDbContextModelSnapshot.cs b/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/ServerDbContextModelSnapshot.cs index c0599ebe15..6dcdccdd99 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/ServerDbContextModelSnapshot.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/Migrations/ServerDbContextModelSnapshot.cs @@ -232,6 +232,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -418,6 +421,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasDefaultValue(false) .HasColumnName("EmailConfirmed"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -446,6 +452,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -494,6 +503,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -696,6 +708,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("nvarchar(128)") .HasColumnName("DisplayName"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1274,6 +1289,9 @@ namespace OpenIddict.Demo.Server.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/package.json b/modules/openiddict/app/OpenIddict.Demo.Server/package.json index d598fa29ec..59a5a01ede 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": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "~7.2.0-rc.1" } } diff --git a/modules/openiddict/app/angular/package.json b/modules/openiddict/app/angular/package.json index 7e337458ec..683fa3a410 100644 --- a/modules/openiddict/app/angular/package.json +++ b/modules/openiddict/app/angular/package.json @@ -12,14 +12,14 @@ }, "private": true, "dependencies": { - "@abp/ng.account": "~7.1.1", - "@abp/ng.components": "~7.1.1", - "@abp/ng.core": "~7.1.1", - "@abp/ng.oauth": "~7.1.1", - "@abp/ng.identity": "~7.1.1", - "@abp/ng.setting-management": "~7.1.1", - "@abp/ng.tenant-management": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.account": "~7.2.0-rc.1", + "@abp/ng.components": "~7.2.0-rc.1", + "@abp/ng.core": "~7.2.0-rc.1", + "@abp/ng.oauth": "~7.2.0-rc.1", + "@abp/ng.identity": "~7.2.0-rc.1", + "@abp/ng.setting-management": "~7.2.0-rc.1", + "@abp/ng.tenant-management": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "@abp/ng.theme.lepton-x": "~2.1.0", "@angular/animations": "^15.0.1", "@angular/common": "^15.0.1", @@ -36,7 +36,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@abp/ng.schematics": "~7.1.1", + "@abp/ng.schematics": "~7.2.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/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj index d3f9e0e9cb..ccd59d2932 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo.Abp.OpenIddict.AspNetCore.csproj @@ -20,8 +20,8 @@ - - - + + + diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs index 8a664da5c1..3ee5dbf126 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs @@ -5,6 +5,7 @@ using OpenIddict.Server; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.Modularity; +using Volo.Abp.OpenIddict.Scopes; using Volo.Abp.OpenIddict.WildcardDomains; using Volo.Abp.Security.Claims; @@ -133,6 +134,7 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule } builder.AddEventHandler(RemoveClaimsFromClientCredentialsGrantType.Descriptor); + builder.AddEventHandler(AttachScopes.Descriptor); services.ExecutePreConfiguredActions(builder); }); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs index 6406c935c7..dd9d46b2de 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs @@ -12,7 +12,9 @@ using OpenIddict.Abstractions; using OpenIddict.Server.AspNetCore; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; +using Volo.Abp.Identity.Settings; using Volo.Abp.MultiTenancy; +using Volo.Abp.Settings; using Volo.Abp.Uow; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -28,6 +30,8 @@ public partial class TokenController protected IOptions IdentityOptions => LazyServiceProvider.LazyGetRequiredService>(); protected IdentitySecurityLogManager IdentitySecurityLogManager => LazyServiceProvider.LazyGetRequiredService(); + protected ISettingProvider SettingProvider => LazyServiceProvider.LazyGetRequiredService(); + [UnitOfWork] protected virtual async Task HandlePasswordAsync(OpenIddictRequest request) { @@ -101,6 +105,17 @@ public partial class TokenController else if (result.IsNotAllowed) { Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", request.Username); + + if (user.ShouldChangePasswordOnNextLogin) + { + return await HandleShouldChangePasswordOnNextLoginAsync(request, user, request.Password); + } + + if (await UserManager.ShouldPeriodicallyChangePasswordAsync(user)) + { + return await HandlePeriodicallyChangePasswordAsync(request, user, request.Password); + } + errorDescription = "You are not allowed to login! Your account is inactive or needs to confirm your email/phone number."; } else @@ -197,8 +212,7 @@ public partial class TokenController items: new Dictionary { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = - nameof(SignInResult.RequiresTwoFactor), + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = nameof(SignInResult.RequiresTwoFactor) }, parameters: new Dictionary { @@ -210,6 +224,96 @@ public partial class TokenController } } + protected virtual async Task HandleShouldChangePasswordOnNextLoginAsync(OpenIddictRequest request, IdentityUser user, string currentPassword) + { + return await HandleChangePasswordAsync(request, user, currentPassword, ChangePasswordType.ShouldChangePasswordOnNextLogin); + } + + protected virtual async Task HandlePeriodicallyChangePasswordAsync(OpenIddictRequest request, IdentityUser user, string currentPassword) + { + return await HandleChangePasswordAsync(request, user, currentPassword, ChangePasswordType.PeriodicallyChangePassword); + } + + protected virtual async Task HandleChangePasswordAsync(OpenIddictRequest request, IdentityUser user, string currentPassword, ChangePasswordType changePasswordType) + { + var changePasswordToken = request.GetParameter("ChangePasswordToken")?.ToString(); + var newPassword = request.GetParameter("NewPassword")?.ToString(); + if (!changePasswordToken.IsNullOrWhiteSpace() && !currentPassword.IsNullOrWhiteSpace() && !newPassword.IsNullOrWhiteSpace()) + { + if (await UserManager.VerifyUserTokenAsync(user, TokenOptions.DefaultProvider, changePasswordType.ToString(), changePasswordToken)) + { + var changePasswordResult = await UserManager.ChangePasswordAsync(user, currentPassword, newPassword); + if (changePasswordResult.Succeeded) + { + await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext + { + Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict, + Action = IdentitySecurityLogActionConsts.ChangePassword, + UserName = request.Username, + ClientId = request.ClientId + }); + + if (changePasswordType == ChangePasswordType.ShouldChangePasswordOnNextLogin) + { + user.SetShouldChangePasswordOnNextLogin(false); + } + + await UserManager.UpdateAsync(user); + return await SetSuccessResultAsync(request, user); + } + else + { + Logger.LogInformation("ChangePassword failed for username: {username}, reason: {changePasswordResult}", request.Username, changePasswordResult.Errors.Select(x => x.Description).JoinAsString(", ")); + + var properties = new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = changePasswordResult.Errors.Select(x => x.Description).JoinAsString(", ") + }); + return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } + } + else + { + Logger.LogInformation("Authentication failed for username: {username}, reason: InvalidAuthenticatorCode", request.Username); + + var properties = new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Invalid authenticator code!" + }); + + return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } + } + else + { + Logger.LogInformation($"Authentication failed for username: {{{request.Username}}}, reason: {{{changePasswordType.ToString()}}}"); + + await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext + { + Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict, + Action = OpenIddictSecurityLogActionConsts.LoginNotAllowed, + UserName = request.Username, + ClientId = request.ClientId + }); + + var properties = new AuthenticationProperties( + items: new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = changePasswordType.ToString() + }, + parameters: new Dictionary + { + ["userId"] = user.Id.ToString("N"), + ["changePasswordToken"] = await UserManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, changePasswordType.ToString()) + }); + + return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } + } + protected virtual async Task SetSuccessResultAsync(OpenIddictRequest request, IdentityUser user) { // Create a new ClaimsPrincipal containing the claims that @@ -240,4 +344,10 @@ public partial class TokenController await UserManager.GetTwoFactorEnabledAsync(user) && (await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0; } + + public enum ChangePasswordType + { + ShouldChangePasswordOnNextLogin, + PeriodicallyChangePassword + } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Scopes/AttachScopes.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Scopes/AttachScopes.cs new file mode 100644 index 0000000000..75401ada2b --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Scopes/AttachScopes.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using OpenIddict.Server; + +namespace Volo.Abp.OpenIddict.Scopes; + +public class AttachScopes : IOpenIddictServerHandler +{ + public static OpenIddictServerHandlerDescriptor Descriptor { get; } + = OpenIddictServerHandlerDescriptor.CreateBuilder() + .UseSingletonHandler() + .SetOrder(OpenIddictServerHandlers.Discovery.AttachScopes.Descriptor.Order + 1) + .SetType(OpenIddictServerHandlerType.Custom) + .Build(); + + private readonly IOpenIddictScopeRepository _scopeRepository; + + public AttachScopes(IOpenIddictScopeRepository scopeRepository) + { + _scopeRepository = scopeRepository; + } + + public async ValueTask HandleAsync(OpenIddictServerEvents.HandleConfigurationRequestContext context) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + var scopes = await _scopeRepository.GetListAsync(); + context.Scopes.UnionWith(scopes.Select(x => x.Name)); + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateClientRedirectUri.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateClientRedirectUri.cs index d2871a57cc..739d34b39b 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateClientRedirectUri.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/WildcardDomains/AbpValidateClientRedirectUri.cs @@ -18,7 +18,7 @@ public class AbpValidateClientRedirectUri : AbpOpenIddictWildcardDomainBase wildcardDomainsOptions, IOpenIddictApplicationManager applicationManager) - : base(wildcardDomainsOptions, new OpenIddictServerHandlers.Authentication.ValidateClientRedirectUri()) + : base(wildcardDomainsOptions, new OpenIddictServerHandlers.Authentication.ValidateClientRedirectUri(applicationManager)) { Handler = new OpenIddictServerHandlers.Authentication.ValidateClientRedirectUri(applicationManager); } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj index d7cb8d2592..61eb0ad9ec 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo.Abp.OpenIddict.Domain.Shared.csproj @@ -14,7 +14,7 @@ - + diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/fi.json b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/fi.json new file mode 100644 index 0000000000..43dbfb17ac --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/fi.json @@ -0,0 +1,15 @@ +{ + "culture": "fi", + "texts": { + "TheOpenIDConnectRequestCannotBeRetrieved": "OpenID Connect -pyyntöä ei voi noutaa.", + "TheUserDetailsCannotBbeRetrieved": "Käyttäjätietoja ei voi hakea.", + "TheApplicationDetailsCannotBeFound": "Sovelluksen tietoja ei löydy.", + "DetailsConcerningTheCallingClientApplicationCannotBeFound": "Kutsuvan asiakassovelluksen tietoja ei löydy.", + "TheSpecifiedGrantTypeIsNotImplemented": "Määritettyä lupatyyppiä {0} ei ole otettu käyttöön.", + "Authorization": "Valtuutus", + "DoYouWantToGrantAccessToYourData": "Haluatko myöntää käyttäjälle {0} pääsyn tietoihisi?", + "ScopesRequested": "Laajuudet pyydetty", + "Accept": "Hyväksy", + "Deny": "Kiellä" + } +} \ No newline at end of file diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj index 456ea01da2..f0affe755d 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo.Abp.OpenIddict.Domain.csproj @@ -17,7 +17,7 @@ - + diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json index ed877cea31..bd52741202 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json @@ -5,6 +5,7 @@ "OnlyProviderPermissons": "Vain tämä palveluntarjoaja", "All": "Kaikki", "SelectAllInAllTabs": "Myönnä kaikki käyttöoikeudet", - "SelectAllInThisTab": "Valitse kaikki" + "SelectAllInThisTab": "Valitse kaikki", + "SaveWithoutAnyPermissionsWarningMessage": "Haluatko varmasti tallentaa ilman käyttöoikeuksia?" } } \ No newline at end of file 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 713652d5f5..2c3b7fb75b 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": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.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 0ad110e7ef..6b71f288a5 100644 --- a/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/yarn.lock +++ b/modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/yarn.lock @@ -2,39 +2,39 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-7.1.1.tgz#9368779919662a804a8119ac6cf9b731fa2a9728" - integrity sha512-xMUBHJv9pLWp3wx3Oc6+F4G8biZ+BgCskYzAgV2lLWFjQAUxe8klbP0dsVr0EZemyMctX6zlHLURRIl+Os8Z2Q== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~7.1.1" - -"@abp/aspnetcore.mvc.ui.theme.shared@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-7.1.1.tgz#48cf683b8a147bc5955de5e812a0dfa3b7184f29" - integrity sha512-caHzC5zOr2vXY2QDRKuFQ4qIWOS/DbsJUO+UhfKSHvP/bAv7Cu10K3gHwrbfuNCChDJ9iLK0+oJYXUtYBXRA3g== - dependencies: - "@abp/aspnetcore.mvc.ui" "~7.1.1" - "@abp/bootstrap" "~7.1.1" - "@abp/bootstrap-datepicker" "~7.1.1" - "@abp/bootstrap-daterangepicker" "~7.1.1" - "@abp/datatables.net-bs5" "~7.1.1" - "@abp/font-awesome" "~7.1.1" - "@abp/jquery-form" "~7.1.1" - "@abp/jquery-validation-unobtrusive" "~7.1.1" - "@abp/lodash" "~7.1.1" - "@abp/luxon" "~7.1.1" - "@abp/malihu-custom-scrollbar-plugin" "~7.1.1" - "@abp/moment" "~7.1.1" - "@abp/select2" "~7.1.1" - "@abp/sweetalert2" "~7.1.1" - "@abp/timeago" "~7.1.1" - "@abp/toastr" "~7.1.1" - -"@abp/aspnetcore.mvc.ui@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-7.1.1.tgz#f862b77573b5c34d9b938160669400edbf06154d" - integrity sha512-+xafeXzwnFa4Evak9Wq+jrpimWITio4Yv9WeSbKInNakIPO+wJNBClBneca1XQ+LFy4bMRuqgWYJueUct+E3tA== +"@abp/aspnetcore.mvc.ui.theme.basic@^7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-7.2.0-rc.1.tgz#3d0229c0b30aec8fa64f12becd60a1dce1a5e555" + integrity sha512-ZmKeFcNnicsvNoUWRstfioB0yGRvKlhrUtywI366Ve4eV6uucxTtrZdteGYAhmd41pNHZkQ/SloQLgpqR8Sszg== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~7.2.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-7.2.0-rc.1.tgz#502329f921b809e4ab390d4aca0c67646aa34b9d" + integrity sha512-LhOURgIwBSBg626fnJ8xKnpMfF63Pc8e+JWBQpvWNffLy8LjDeY/GCVTUDGJO2TKvMoYymeCCfzSG4f2EBqtJg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~7.2.0-rc.1" + "@abp/bootstrap" "~7.2.0-rc.1" + "@abp/bootstrap-datepicker" "~7.2.0-rc.1" + "@abp/bootstrap-daterangepicker" "~7.2.0-rc.1" + "@abp/datatables.net-bs5" "~7.2.0-rc.1" + "@abp/font-awesome" "~7.2.0-rc.1" + "@abp/jquery-form" "~7.2.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~7.2.0-rc.1" + "@abp/lodash" "~7.2.0-rc.1" + "@abp/luxon" "~7.2.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~7.2.0-rc.1" + "@abp/moment" "~7.2.0-rc.1" + "@abp/select2" "~7.2.0-rc.1" + "@abp/sweetalert2" "~7.2.0-rc.1" + "@abp/timeago" "~7.2.0-rc.1" + "@abp/toastr" "~7.2.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-7.2.0-rc.1.tgz#97d228aa9e7d817dacda5fdd170a95f5a5fdba7b" + integrity sha512-qmxBqN5LGtgmQnjbrW0hY3gguFvHwdbYfj2b4wnzhlMryo0Z9U1cPtjeVsDN4++ml2oivhybWmY4AzTlNYo9Hw== dependencies: ansi-colors "^4.1.1" extend-object "^1.0.0" @@ -43,158 +43,158 @@ merge-stream "^2.0.0" micromatch "^4.0.2" -"@abp/bootstrap-datepicker@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-7.1.1.tgz#45c9b9086b3a64ce4ba6193320afdf2e81d12136" - integrity sha512-/T2FlMlPV19J70t8yueyxj9k72+4t3b2aVDrNHCf7uPuSqClwVKEylzGr8RFc7VXHZZwwaUrbLhxYkhkCKLuLA== +"@abp/bootstrap-datepicker@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-7.2.0-rc.1.tgz#a625bc18ef6148fd856657b987561c1269780ce9" + integrity sha512-bmAGNhHsKFs/oL/LqpEDCeX4fOzvXXrcjFQcEG4pB1lHPQ0T9bm758f4dwEoT5qZQRBLwShQ7cKbWfCdrnXFTQ== dependencies: bootstrap-datepicker "^1.9.0" -"@abp/bootstrap-daterangepicker@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-7.1.1.tgz#19349099f6c007feef1ebe73c9c1059f8d271bc1" - integrity sha512-pCTiPRNW4gnzo0rWKbu2A52dRUeXRI3MqJW7h46yNk4n1ZrnsmwH6/b/ebp89YlbNXWaatDrEpk3NbqxSDDAdQ== +"@abp/bootstrap-daterangepicker@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-7.2.0-rc.1.tgz#5bfc4272efe98e3ce50da1a00f45c3050a19b0a1" + integrity sha512-dbI3nYhDRyvANGjNiZESs3Isfo0ai3xV1IaVzUwxRy90HDS2JupocXEXOMOnXs0+r05xYyl0/uXwVdtUQKFJ+w== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-7.1.1.tgz#1481b984a7f31f92f262d6957340fcaa87eb8ece" - integrity sha512-qFNLuBExQeVDOlFKP/STa3r+8CHhPUfsOFnPaknkS2QLewmtAZw3BJFEgvpJQkSvQdaBXW+EjutaJiFGdDrkEQ== +"@abp/bootstrap@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-7.2.0-rc.1.tgz#b87e8734492980377487bd775e7e5a75af64ac5b" + integrity sha512-4tOOusawRhVUttSQrSnhMeoZnuGbK3kV0QhitLgfqckvexo9mRtzDFSdpq/0W7/9gO7B3zdajToASMNcOdmSnQ== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" bootstrap "^5.1.3" -"@abp/core@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-7.1.1.tgz#de4d666d26fba4ab5f7b3e6fff38f2f5f034d121" - integrity sha512-d/vHAAU60v6gdH3+VpchXDD1l5yXNmKsb3i92gvG9M0orjgVy3dJmb6zBVw50nnZxNSfq3Z0S1TC/QdA2C1rQg== +"@abp/core@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-7.2.0-rc.1.tgz#edc1f7188d15fc6e62385576d34ea2e0c2f6afbd" + integrity sha512-KkLelSvFpOFxmzCQ+1cs3e6hd69IstqRH+5j5lnTASZtVMro86NB2RoqsAdmSDDG8SoHA2TzZpki56jo8ji6Yg== dependencies: - "@abp/utils" "~7.1.1" + "@abp/utils" "~7.2.0-rc.1" -"@abp/datatables.net-bs5@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-7.1.1.tgz#b7058a0cad4119cc7391493a7d148250efc41b72" - integrity sha512-uPqHzfE9dH5nEuocvIduQYcjEa4MwBXMjtnY5tHM+PK2yB8DsDOrXVopOX0YPTgFk49pLvOVbgxsftuyPb3xKQ== +"@abp/datatables.net-bs5@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-7.2.0-rc.1.tgz#4e204d44642f072320bc1ef83025b8dc579bfcfa" + integrity sha512-qVK/kTe9sf/1NZM2K3ixpwf/bBm1q2eogqygqBO7WeiA0UCXWu92WZ0cIKUeYCumKKsMbb/D3lX3FGIgqFqhkw== dependencies: - "@abp/datatables.net" "~7.1.1" + "@abp/datatables.net" "~7.2.0-rc.1" datatables.net-bs5 "^1.11.4" -"@abp/datatables.net@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-7.1.1.tgz#a84975c8ab0d7406e524d2eae41f7a04bc00f13c" - integrity sha512-eKIxvap/bKc1G7Dev+t9V8HvHWQYza0Y4RdYmC0bPOyRthlTW9AH8jyKK5HtJlpNpj9rjB2jy3/I9D1uzD67QQ== +"@abp/datatables.net@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-7.2.0-rc.1.tgz#e3aa60d69ffb27c96da9469543ce0f0c48f3e312" + integrity sha512-LnIwvU2m9JEtKdILQkQLobVSCik4VcIuYDuUq60TqgRtC2TBYbsX5Ngtp5LoUkJ+1O7PNF/aKkx92H55X27ZsA== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" datatables.net "^1.11.4" -"@abp/font-awesome@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-7.1.1.tgz#da4a0be295b0acf9b62d8299d1c567ae192a320f" - integrity sha512-AVjbSFXj5IzzQwqwP/fgsuRG1NzV6/KGn5owsfn6HeKSOBjqW4h4EGyunMNoAOW4fsdFxvE4zjBpsG1/E9tuQg== +"@abp/font-awesome@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-7.2.0-rc.1.tgz#80d7915ff756b8f569de95322f607a8fa47ace00" + integrity sha512-829G90oNOxZyHRIPkZUtxBTkwLMhkourDQOZTvLV0c/IQzMdSEuU4VW5BZ4QdrVJrWJ5pPn/uFhbM7R7viskJg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" "@fortawesome/fontawesome-free" "^5.15.4" -"@abp/jquery-form@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-7.1.1.tgz#03c17ccb19820e0a56be58275e2ebba7e7ebaa5f" - integrity sha512-UurenNEYZRN192B70R3DR1NsFUae45h/2huAQD07OM0fyJyM6ji5N7q/Q2Aao0jqBLwRNPrEinUcP8BmJxe2Tw== +"@abp/jquery-form@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-7.2.0-rc.1.tgz#8c0dddb6907aaa40187ee93eab045c485a1d49eb" + integrity sha512-FK0GMHoB0u0VnizEwN+Gbc6yNg/G5VjSv0/u/9J3dHk4KVR5mo68xwbfPCIqvS0SOeOBgxYOfaxjfFrArCVFbg== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-7.1.1.tgz#255146ccc553bb9f9197ccf87fa71d930698cf65" - integrity sha512-oUYvNmiGxeyJeGoG3EWAzy2Ld9EKgyK6U28gKaAMrXFlYbiEMnX5+8v1Tdb3sQuOJ68bdiyYjO3Ke9NLsTZHFg== +"@abp/jquery-validation-unobtrusive@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-7.2.0-rc.1.tgz#2d7e559397192ded4409153d606120b96ef6958a" + integrity sha512-q+83bKCNOyqjOutRJ6lChg89lzvSUD04MkPj6teMOVWwqzbQ0B/lnkovfCtJRw7cAO8UBhzd3Q029JjhtG4WPw== dependencies: - "@abp/jquery-validation" "~7.1.1" + "@abp/jquery-validation" "~7.2.0-rc.1" jquery-validation-unobtrusive "^3.2.12" -"@abp/jquery-validation@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-7.1.1.tgz#b3af6606daaa6303c28f6a04aeaa2d6612c5248b" - integrity sha512-ZkDWUbHqF9NkczPdvEZH4gkb6NeXRI5JsROXzmx3K+QIOGUhs//4gOzSYYak0kn0Mljeg8fjJQNa55914d8Xow== +"@abp/jquery-validation@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-7.2.0-rc.1.tgz#1768ae95e2870ccf25d541b6fc65d7dfd8f6c567" + integrity sha512-IRNyw4ak/ntliaGWpqQLn3ZGOlg3DdgMLtINLdSF6STX2nEcts2jnv3bxI2iFUjcYF+x6pCjUrUCpegdgtTNrw== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" jquery-validation "^1.19.3" -"@abp/jquery@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-7.1.1.tgz#43adacf3d345576ff7ca42a5a470eb61fb827e23" - integrity sha512-3Epxyyoz1BJge7lbimkg0Ha4DmNlZN5vYFgVKa8SOCoKfoZ7+8gmbXlUEAUe4wnsjP5tQ4/AjoqgzjPL9KQcCg== +"@abp/jquery@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-7.2.0-rc.1.tgz#6020b62df568dae3d2659447314587793ef320ec" + integrity sha512-lt668fxX83pC/f+uA7edo5XwaPkmpZ2sQYqdBh9IQGD9hmkFIZdp7t6ABbcSsOiCFuLok2RXODAvJeDqV+x0TA== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" jquery "~3.6.0" -"@abp/lodash@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-7.1.1.tgz#7371484331867775adcb5f4a92d63d4cbed25f19" - integrity sha512-hwNcYcRNZZV5OgH+W775OkpJ5JmrDi+LiVFDAmelWgAXSgqxic8bDla+UUL/pjnkKxwgI4BAlOIctYN/2QM3iA== +"@abp/lodash@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-7.2.0-rc.1.tgz#e9c50df914b54f9d53f5ada9c80fb04906388889" + integrity sha512-Acl+ipVflcZPt4BMRsVl4yt2zxU+//u/N9Wr7wawpz0vLpMOTAi86YKHJHqjh1W7Ixeujn6gfjcwZLMwd95d1Q== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-7.1.1.tgz#b0cf4a72ffe66f77d403b896ea5d1ea007ebc9b7" - integrity sha512-2RDIdHrPUDvOoowQlMInfQ0rDZA8IOf2fVs7C2bcZmhjGoK7+vsUJsw/q9awpgeKrHwqJ0o1zsFGfFFKlYMnew== +"@abp/luxon@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-7.2.0-rc.1.tgz#ce254b096f2a96c19f0576046d0962e1e415d40c" + integrity sha512-33SfVt9VUbriGLbRyOsEIkRBiwOhXH4XAf1jE3Z8cwjOw5X+ZmKZUyZGJsvGtJfwMqZ54FT9lDuovp8L9U1OoA== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" luxon "^2.3.0" -"@abp/malihu-custom-scrollbar-plugin@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-7.1.1.tgz#8a25f3dd78c1f0c395ac255976567d2919d3ec38" - integrity sha512-kfW+B+kFr0Qao17rDginL0ICPwGA3t387hx5LhPIxP2p7aluaA3qyiEbM50Izz+t4mL4JdaBN8DU0kLziqVERw== +"@abp/malihu-custom-scrollbar-plugin@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-7.2.0-rc.1.tgz#785afe744620eb2b1648e8099b1f6f61a8f619cf" + integrity sha512-Qcoyy1wLClej8eCGnJ+W9TJ47R4I/eZpu2m0tmSWgdnw8Zqahti9xK09LOUG7piHoOC/qyv8Qwb+UdTSqCtzkw== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-7.1.1.tgz#5cf7f815cc4dbe55c9c363d146592683f8a90d62" - integrity sha512-tgg4rTmAGZE+B8OBpeq1ADXJW07EdkCkQUSrLykWMaQr1PZfs9xi0tgsi4CpdITLOK48b9BueRmUdZOgmFXKiQ== +"@abp/moment@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-7.2.0-rc.1.tgz#96697eabd63e67f24c774baa68b37b75d5d774be" + integrity sha512-s+7tgMxBGW/4uQwKEAfdLdgU7gX1t2XD/e0BxfSgex8diaxUQ9DoWrq4qK6EBk1keWqq1fKuMZ4fqbnRFRG+ag== dependencies: moment "^2.9.0" -"@abp/select2@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-7.1.1.tgz#1afa414ce68c1f35c3e7ab1beee00f924604de51" - integrity sha512-+5MMLQuXlj07VIXhVKEAmeqsfuGXHWwtpDY2LMsT15lNJbrvq0wF9KZJ0eMF8u29Nyk8IuBJf1YRUzx815PiVg== +"@abp/select2@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-7.2.0-rc.1.tgz#7c076ad31efe5087f361ea01f66cf00bc409c8b1" + integrity sha512-Hmmfl11hgHb7TSss7ptj48zqgez75wTHHfUhAyZsU/qu3/w2s7qTOAIoJczuARKBJ3eXKku9U1otzC7gR7LqKQ== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-7.1.1.tgz#9ba7578ab53af056f26ef34ae0f2fddc28722c12" - integrity sha512-8hjmEqmcRoMN3Cmk7k0lNdtsm8JytrjPzvHahjqKHIcK1Zi0RbjWJpafbvDu5IFlFrRNYHXlqpUw8e3dtCEp3A== +"@abp/sweetalert2@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-7.2.0-rc.1.tgz#c6cc72b5eb8a4909c42be27566077c4b1ce2e377" + integrity sha512-VSeaSxCuzEziQPjLQ2IXhuyC2PYOI8dp7Bi5uEtFG3fnHz042rcRZSgh6teks6eRRUNxuv17YnV/LAEvm2UQtg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" sweetalert2 "^11.3.6" -"@abp/timeago@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-7.1.1.tgz#c7be25a320aa311e2e9c7a8186b51766db4523ac" - integrity sha512-FsIjAiP2dqRHwrrKx/5tWgLMZ2LboNLhrHeRb1FFol/0163uVEQGEJkxLOE5xY530mdaFFfAOc0x6aniSLE4ZQ== +"@abp/timeago@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-7.2.0-rc.1.tgz#1f0f0ba199501c760cf53e493fd63bbe8a6329f2" + integrity sha512-QfbnOOBye76m+x+uOPcZG40zDOIyIgWssoUyBQDch6Z3A9HcDhw6qQBlsoeuX2+N/be1KCIfUHvjHE92Zdhktg== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" timeago "^1.6.7" -"@abp/toastr@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-7.1.1.tgz#5ef7da983a226f226d8b9b85f2fa9ff7eeed41aa" - integrity sha512-8x8FQt8BSmgI1b6JXK7N+JJJ0ksBcFSMQol0AbzTOFOBO2T77eXIuiVh8961ynaeIECjGWcazXUMuG09Drq6Ig== +"@abp/toastr@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-7.2.0-rc.1.tgz#758a74cd8d699c9c8fb1cc23b7e39762b6929861" + integrity sha512-IREF8C/CYb2PJrSWqYWoqvrzDrgBDrQSkGJvMVNo4DRj2V66UzHUfMFQBoQA40m0tY354SEhowhPRbj9BhQGtA== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" toastr "^2.1.4" -"@abp/utils@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-7.1.1.tgz#e11bc878573dd8118e42b3c1582c44d8b5c71d83" - integrity sha512-G4S0ndDUe8W525O8KUBucLcrESoSFjeqLjRZ+W7N7K9D/oLisYU9Siwxb2csTdjXz6JeQ7AtQl7ak1WpAMiJ/g== +"@abp/utils@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-7.2.0-rc.1.tgz#25726da9d39e887a490eff44b2ce9a28826ec4dd" + integrity sha512-g/G+En4Te3b9x/7bSf8WDwUjBusiLf4oVcUVk65/wbC0BezMsxnrzRr1ZMZQyYYGJYJ3DdnUftOLziUx9o7U6A== dependencies: just-compare "^1.3.0" diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/fi.json b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/fi.json index 70eef69695..2e0c11d63f 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/fi.json +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/fi.json @@ -1,17 +1,27 @@ { "culture": "fi", "texts": { - "Settings": "asetukset", - "SuccessfullySaved": "Tallentaminen onnistui", + "Settings": "Asetukset", + "SuccessfullySaved": "Tallennettu onnistuneesti", "Permission:SettingManagement": "Asetusten hallinta", "Permission:Emailing": "Sähköpostiviestit", + "Permission:EmailingTest": "Sähköpostitesti", + "SendTestEmail": "Lähetä testisähköposti", + "SenderEmailAddress": "Lähettäjän sähköpostiosoite", + "TargetEmailAddress": "Kohdesähköpostiosoite", + "Subject": "Aihe", + "Body": "Runko", + "TestEmailSubject": "Testisähköposti {0}", + "TestEmailBody": "Testaa sähköpostiviestiä täällä", + "SuccessfullySent": "Lähetetty onnistuneesti", + "Send": "Lähetä", "Menu:Emailing": "Sähköpostiviestit", "SmtpHost": "Isäntä", - "SmtpPort": "Satama", + "SmtpPort": "Portti", "SmtpUserName": "Käyttäjänimi", "SmtpPassword": "Salasana", "SmtpDomain": "Verkkotunnus", - "SmtpEnableSsl": "Ota käyttöön ssl", + "SmtpEnableSsl": "Ota käyttöön SSL", "SmtpUseDefaultCredentials": "Käytä oletusarvoisia tunnistetietoja", "DefaultFromAddress": "Oletus osoitteesta", "DefaultFromDisplayName": "Oletus näyttönimestä", @@ -21,4 +31,4 @@ "Feature:AllowChangingEmailSettings": "Salli sähköpostiasetusten muuttaminen.", "Feature:AllowChangingEmailSettingsDescription": "Salli sähköpostiasetusten muuttaminen." } -} +} \ No newline at end of file diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json index 179ec3c1d6..7721629201 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json @@ -8,14 +8,14 @@ "TenantName": "Vuokralaisen nimi", "DisplayName:TenantName": "Vuokralaisen nimi", "TenantDeletionConfirmationMessage": "Vuokralainen {0} poistetaan. Vahvistatko sen?", - "ConnectionStrings": "Yhteysjonot", - "DisplayName:DefaultConnectionString": "Oletusyhteysmerkkijono", + "ConnectionStrings": "Tietokantayhteydet", + "DisplayName:DefaultConnectionString": "Oletus tietokantayhteys", "DisplayName:UseSharedDatabase": "Käytä jaettua tietokantaa", "Permission:TenantManagement": "Vuokralaisten hallinta", - "Permission:Create": "Luoda", - "Permission:Edit": "Muokata", - "Permission:Delete": "Poistaa", - "Permission:ManageConnectionStrings": "Hallitse yhteysmerkkijonoja", + "Permission:Create": "Luonti", + "Permission:Edit": "Muokkaus", + "Permission:Delete": "Poisto", + "Permission:ManageConnectionStrings": "Hallitse tietokantayhteyksiä", "Permission:ManageFeatures": "Hallitse ominaisuuksia", "DisplayName:AdminEmailAddress": "Järjestelmänvalvojan sähköpostiosoite", "DisplayName:AdminPassword": "Järjestelmänvalvojan salasana" diff --git a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/package.json b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/package.json index 383d7fd0fb..86ff22f0b4 100644 --- a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/package.json +++ b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~7.1.1", - "@abp/virtual-file-explorer": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.0-rc.1", + "@abp/virtual-file-explorer": "^7.2.0-rc.1" } } diff --git a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/yarn.lock b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/yarn.lock index df3dcbecdc..9989e0e70a 100644 --- a/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/yarn.lock +++ b/modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/yarn.lock @@ -2,39 +2,39 @@ # yarn lockfile v1 -"@abp/aspnetcore.mvc.ui.theme.basic@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-7.1.1.tgz#9368779919662a804a8119ac6cf9b731fa2a9728" - integrity sha512-xMUBHJv9pLWp3wx3Oc6+F4G8biZ+BgCskYzAgV2lLWFjQAUxe8klbP0dsVr0EZemyMctX6zlHLURRIl+Os8Z2Q== - dependencies: - "@abp/aspnetcore.mvc.ui.theme.shared" "~7.1.1" - -"@abp/aspnetcore.mvc.ui.theme.shared@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-7.1.1.tgz#48cf683b8a147bc5955de5e812a0dfa3b7184f29" - integrity sha512-caHzC5zOr2vXY2QDRKuFQ4qIWOS/DbsJUO+UhfKSHvP/bAv7Cu10K3gHwrbfuNCChDJ9iLK0+oJYXUtYBXRA3g== - dependencies: - "@abp/aspnetcore.mvc.ui" "~7.1.1" - "@abp/bootstrap" "~7.1.1" - "@abp/bootstrap-datepicker" "~7.1.1" - "@abp/bootstrap-daterangepicker" "~7.1.1" - "@abp/datatables.net-bs5" "~7.1.1" - "@abp/font-awesome" "~7.1.1" - "@abp/jquery-form" "~7.1.1" - "@abp/jquery-validation-unobtrusive" "~7.1.1" - "@abp/lodash" "~7.1.1" - "@abp/luxon" "~7.1.1" - "@abp/malihu-custom-scrollbar-plugin" "~7.1.1" - "@abp/moment" "~7.1.1" - "@abp/select2" "~7.1.1" - "@abp/sweetalert2" "~7.1.1" - "@abp/timeago" "~7.1.1" - "@abp/toastr" "~7.1.1" - -"@abp/aspnetcore.mvc.ui@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-7.1.1.tgz#f862b77573b5c34d9b938160669400edbf06154d" - integrity sha512-+xafeXzwnFa4Evak9Wq+jrpimWITio4Yv9WeSbKInNakIPO+wJNBClBneca1XQ+LFy4bMRuqgWYJueUct+E3tA== +"@abp/aspnetcore.mvc.ui.theme.basic@^7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.basic/-/aspnetcore.mvc.ui.theme.basic-7.2.0-rc.1.tgz#3d0229c0b30aec8fa64f12becd60a1dce1a5e555" + integrity sha512-ZmKeFcNnicsvNoUWRstfioB0yGRvKlhrUtywI366Ve4eV6uucxTtrZdteGYAhmd41pNHZkQ/SloQLgpqR8Sszg== + dependencies: + "@abp/aspnetcore.mvc.ui.theme.shared" "~7.2.0-rc.1" + +"@abp/aspnetcore.mvc.ui.theme.shared@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui.theme.shared/-/aspnetcore.mvc.ui.theme.shared-7.2.0-rc.1.tgz#502329f921b809e4ab390d4aca0c67646aa34b9d" + integrity sha512-LhOURgIwBSBg626fnJ8xKnpMfF63Pc8e+JWBQpvWNffLy8LjDeY/GCVTUDGJO2TKvMoYymeCCfzSG4f2EBqtJg== + dependencies: + "@abp/aspnetcore.mvc.ui" "~7.2.0-rc.1" + "@abp/bootstrap" "~7.2.0-rc.1" + "@abp/bootstrap-datepicker" "~7.2.0-rc.1" + "@abp/bootstrap-daterangepicker" "~7.2.0-rc.1" + "@abp/datatables.net-bs5" "~7.2.0-rc.1" + "@abp/font-awesome" "~7.2.0-rc.1" + "@abp/jquery-form" "~7.2.0-rc.1" + "@abp/jquery-validation-unobtrusive" "~7.2.0-rc.1" + "@abp/lodash" "~7.2.0-rc.1" + "@abp/luxon" "~7.2.0-rc.1" + "@abp/malihu-custom-scrollbar-plugin" "~7.2.0-rc.1" + "@abp/moment" "~7.2.0-rc.1" + "@abp/select2" "~7.2.0-rc.1" + "@abp/sweetalert2" "~7.2.0-rc.1" + "@abp/timeago" "~7.2.0-rc.1" + "@abp/toastr" "~7.2.0-rc.1" + +"@abp/aspnetcore.mvc.ui@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/aspnetcore.mvc.ui/-/aspnetcore.mvc.ui-7.2.0-rc.1.tgz#97d228aa9e7d817dacda5fdd170a95f5a5fdba7b" + integrity sha512-qmxBqN5LGtgmQnjbrW0hY3gguFvHwdbYfj2b4wnzhlMryo0Z9U1cPtjeVsDN4++ml2oivhybWmY4AzTlNYo9Hw== dependencies: ansi-colors "^4.1.1" extend-object "^1.0.0" @@ -43,185 +43,185 @@ merge-stream "^2.0.0" micromatch "^4.0.2" -"@abp/bootstrap-datepicker@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-7.1.1.tgz#45c9b9086b3a64ce4ba6193320afdf2e81d12136" - integrity sha512-/T2FlMlPV19J70t8yueyxj9k72+4t3b2aVDrNHCf7uPuSqClwVKEylzGr8RFc7VXHZZwwaUrbLhxYkhkCKLuLA== +"@abp/bootstrap-datepicker@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-datepicker/-/bootstrap-datepicker-7.2.0-rc.1.tgz#a625bc18ef6148fd856657b987561c1269780ce9" + integrity sha512-bmAGNhHsKFs/oL/LqpEDCeX4fOzvXXrcjFQcEG4pB1lHPQ0T9bm758f4dwEoT5qZQRBLwShQ7cKbWfCdrnXFTQ== dependencies: bootstrap-datepicker "^1.9.0" -"@abp/bootstrap-daterangepicker@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-7.1.1.tgz#19349099f6c007feef1ebe73c9c1059f8d271bc1" - integrity sha512-pCTiPRNW4gnzo0rWKbu2A52dRUeXRI3MqJW7h46yNk4n1ZrnsmwH6/b/ebp89YlbNXWaatDrEpk3NbqxSDDAdQ== +"@abp/bootstrap-daterangepicker@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap-daterangepicker/-/bootstrap-daterangepicker-7.2.0-rc.1.tgz#5bfc4272efe98e3ce50da1a00f45c3050a19b0a1" + integrity sha512-dbI3nYhDRyvANGjNiZESs3Isfo0ai3xV1IaVzUwxRy90HDS2JupocXEXOMOnXs0+r05xYyl0/uXwVdtUQKFJ+w== dependencies: bootstrap-daterangepicker "^3.1.0" -"@abp/bootstrap@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-7.1.1.tgz#1481b984a7f31f92f262d6957340fcaa87eb8ece" - integrity sha512-qFNLuBExQeVDOlFKP/STa3r+8CHhPUfsOFnPaknkS2QLewmtAZw3BJFEgvpJQkSvQdaBXW+EjutaJiFGdDrkEQ== +"@abp/bootstrap@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/bootstrap/-/bootstrap-7.2.0-rc.1.tgz#b87e8734492980377487bd775e7e5a75af64ac5b" + integrity sha512-4tOOusawRhVUttSQrSnhMeoZnuGbK3kV0QhitLgfqckvexo9mRtzDFSdpq/0W7/9gO7B3zdajToASMNcOdmSnQ== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" bootstrap "^5.1.3" -"@abp/clipboard@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-7.1.1.tgz#06985266e399a03f819585ec9b9ae17ffcbfef0b" - integrity sha512-IxlQJgNlhp6hMVAkPqRgzmB0a5bKdrZ0whVlaxNKR42geetutV+5KPo/koCmliksHLAFTfiAedQXOXsJ90p2AQ== +"@abp/clipboard@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/clipboard/-/clipboard-7.2.0-rc.1.tgz#d559d426b146ef519441021eafa74ea29e7393d9" + integrity sha512-t5Ik/9g+K4vQzvyk8C5duLvX6v0j5zFKs2QEWX3WXhwK+j1aOP8wSA8S5AKb0VHoGCTiqxzpdgcePv/sXh3t1w== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" clipboard "^2.0.8" -"@abp/core@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/core/-/core-7.1.1.tgz#de4d666d26fba4ab5f7b3e6fff38f2f5f034d121" - integrity sha512-d/vHAAU60v6gdH3+VpchXDD1l5yXNmKsb3i92gvG9M0orjgVy3dJmb6zBVw50nnZxNSfq3Z0S1TC/QdA2C1rQg== +"@abp/core@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/core/-/core-7.2.0-rc.1.tgz#edc1f7188d15fc6e62385576d34ea2e0c2f6afbd" + integrity sha512-KkLelSvFpOFxmzCQ+1cs3e6hd69IstqRH+5j5lnTASZtVMro86NB2RoqsAdmSDDG8SoHA2TzZpki56jo8ji6Yg== dependencies: - "@abp/utils" "~7.1.1" + "@abp/utils" "~7.2.0-rc.1" -"@abp/datatables.net-bs5@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-7.1.1.tgz#b7058a0cad4119cc7391493a7d148250efc41b72" - integrity sha512-uPqHzfE9dH5nEuocvIduQYcjEa4MwBXMjtnY5tHM+PK2yB8DsDOrXVopOX0YPTgFk49pLvOVbgxsftuyPb3xKQ== +"@abp/datatables.net-bs5@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net-bs5/-/datatables.net-bs5-7.2.0-rc.1.tgz#4e204d44642f072320bc1ef83025b8dc579bfcfa" + integrity sha512-qVK/kTe9sf/1NZM2K3ixpwf/bBm1q2eogqygqBO7WeiA0UCXWu92WZ0cIKUeYCumKKsMbb/D3lX3FGIgqFqhkw== dependencies: - "@abp/datatables.net" "~7.1.1" + "@abp/datatables.net" "~7.2.0-rc.1" datatables.net-bs5 "^1.11.4" -"@abp/datatables.net@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-7.1.1.tgz#a84975c8ab0d7406e524d2eae41f7a04bc00f13c" - integrity sha512-eKIxvap/bKc1G7Dev+t9V8HvHWQYza0Y4RdYmC0bPOyRthlTW9AH8jyKK5HtJlpNpj9rjB2jy3/I9D1uzD67QQ== +"@abp/datatables.net@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/datatables.net/-/datatables.net-7.2.0-rc.1.tgz#e3aa60d69ffb27c96da9469543ce0f0c48f3e312" + integrity sha512-LnIwvU2m9JEtKdILQkQLobVSCik4VcIuYDuUq60TqgRtC2TBYbsX5Ngtp5LoUkJ+1O7PNF/aKkx92H55X27ZsA== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" datatables.net "^1.11.4" -"@abp/font-awesome@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-7.1.1.tgz#da4a0be295b0acf9b62d8299d1c567ae192a320f" - integrity sha512-AVjbSFXj5IzzQwqwP/fgsuRG1NzV6/KGn5owsfn6HeKSOBjqW4h4EGyunMNoAOW4fsdFxvE4zjBpsG1/E9tuQg== +"@abp/font-awesome@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/font-awesome/-/font-awesome-7.2.0-rc.1.tgz#80d7915ff756b8f569de95322f607a8fa47ace00" + integrity sha512-829G90oNOxZyHRIPkZUtxBTkwLMhkourDQOZTvLV0c/IQzMdSEuU4VW5BZ4QdrVJrWJ5pPn/uFhbM7R7viskJg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" "@fortawesome/fontawesome-free" "^5.15.4" -"@abp/jquery-form@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-7.1.1.tgz#03c17ccb19820e0a56be58275e2ebba7e7ebaa5f" - integrity sha512-UurenNEYZRN192B70R3DR1NsFUae45h/2huAQD07OM0fyJyM6ji5N7q/Q2Aao0jqBLwRNPrEinUcP8BmJxe2Tw== +"@abp/jquery-form@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-form/-/jquery-form-7.2.0-rc.1.tgz#8c0dddb6907aaa40187ee93eab045c485a1d49eb" + integrity sha512-FK0GMHoB0u0VnizEwN+Gbc6yNg/G5VjSv0/u/9J3dHk4KVR5mo68xwbfPCIqvS0SOeOBgxYOfaxjfFrArCVFbg== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" jquery-form "^4.3.0" -"@abp/jquery-validation-unobtrusive@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-7.1.1.tgz#255146ccc553bb9f9197ccf87fa71d930698cf65" - integrity sha512-oUYvNmiGxeyJeGoG3EWAzy2Ld9EKgyK6U28gKaAMrXFlYbiEMnX5+8v1Tdb3sQuOJ68bdiyYjO3Ke9NLsTZHFg== +"@abp/jquery-validation-unobtrusive@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-7.2.0-rc.1.tgz#2d7e559397192ded4409153d606120b96ef6958a" + integrity sha512-q+83bKCNOyqjOutRJ6lChg89lzvSUD04MkPj6teMOVWwqzbQ0B/lnkovfCtJRw7cAO8UBhzd3Q029JjhtG4WPw== dependencies: - "@abp/jquery-validation" "~7.1.1" + "@abp/jquery-validation" "~7.2.0-rc.1" jquery-validation-unobtrusive "^3.2.12" -"@abp/jquery-validation@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-7.1.1.tgz#b3af6606daaa6303c28f6a04aeaa2d6612c5248b" - integrity sha512-ZkDWUbHqF9NkczPdvEZH4gkb6NeXRI5JsROXzmx3K+QIOGUhs//4gOzSYYak0kn0Mljeg8fjJQNa55914d8Xow== +"@abp/jquery-validation@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery-validation/-/jquery-validation-7.2.0-rc.1.tgz#1768ae95e2870ccf25d541b6fc65d7dfd8f6c567" + integrity sha512-IRNyw4ak/ntliaGWpqQLn3ZGOlg3DdgMLtINLdSF6STX2nEcts2jnv3bxI2iFUjcYF+x6pCjUrUCpegdgtTNrw== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" jquery-validation "^1.19.3" -"@abp/jquery@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-7.1.1.tgz#43adacf3d345576ff7ca42a5a470eb61fb827e23" - integrity sha512-3Epxyyoz1BJge7lbimkg0Ha4DmNlZN5vYFgVKa8SOCoKfoZ7+8gmbXlUEAUe4wnsjP5tQ4/AjoqgzjPL9KQcCg== +"@abp/jquery@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/jquery/-/jquery-7.2.0-rc.1.tgz#6020b62df568dae3d2659447314587793ef320ec" + integrity sha512-lt668fxX83pC/f+uA7edo5XwaPkmpZ2sQYqdBh9IQGD9hmkFIZdp7t6ABbcSsOiCFuLok2RXODAvJeDqV+x0TA== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" jquery "~3.6.0" -"@abp/lodash@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-7.1.1.tgz#7371484331867775adcb5f4a92d63d4cbed25f19" - integrity sha512-hwNcYcRNZZV5OgH+W775OkpJ5JmrDi+LiVFDAmelWgAXSgqxic8bDla+UUL/pjnkKxwgI4BAlOIctYN/2QM3iA== +"@abp/lodash@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/lodash/-/lodash-7.2.0-rc.1.tgz#e9c50df914b54f9d53f5ada9c80fb04906388889" + integrity sha512-Acl+ipVflcZPt4BMRsVl4yt2zxU+//u/N9Wr7wawpz0vLpMOTAi86YKHJHqjh1W7Ixeujn6gfjcwZLMwd95d1Q== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" lodash "^4.17.21" -"@abp/luxon@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-7.1.1.tgz#b0cf4a72ffe66f77d403b896ea5d1ea007ebc9b7" - integrity sha512-2RDIdHrPUDvOoowQlMInfQ0rDZA8IOf2fVs7C2bcZmhjGoK7+vsUJsw/q9awpgeKrHwqJ0o1zsFGfFFKlYMnew== +"@abp/luxon@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/luxon/-/luxon-7.2.0-rc.1.tgz#ce254b096f2a96c19f0576046d0962e1e415d40c" + integrity sha512-33SfVt9VUbriGLbRyOsEIkRBiwOhXH4XAf1jE3Z8cwjOw5X+ZmKZUyZGJsvGtJfwMqZ54FT9lDuovp8L9U1OoA== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" luxon "^2.3.0" -"@abp/malihu-custom-scrollbar-plugin@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-7.1.1.tgz#8a25f3dd78c1f0c395ac255976567d2919d3ec38" - integrity sha512-kfW+B+kFr0Qao17rDginL0ICPwGA3t387hx5LhPIxP2p7aluaA3qyiEbM50Izz+t4mL4JdaBN8DU0kLziqVERw== +"@abp/malihu-custom-scrollbar-plugin@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/malihu-custom-scrollbar-plugin/-/malihu-custom-scrollbar-plugin-7.2.0-rc.1.tgz#785afe744620eb2b1648e8099b1f6f61a8f619cf" + integrity sha512-Qcoyy1wLClej8eCGnJ+W9TJ47R4I/eZpu2m0tmSWgdnw8Zqahti9xK09LOUG7piHoOC/qyv8Qwb+UdTSqCtzkw== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" malihu-custom-scrollbar-plugin "^3.1.5" -"@abp/moment@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-7.1.1.tgz#5cf7f815cc4dbe55c9c363d146592683f8a90d62" - integrity sha512-tgg4rTmAGZE+B8OBpeq1ADXJW07EdkCkQUSrLykWMaQr1PZfs9xi0tgsi4CpdITLOK48b9BueRmUdZOgmFXKiQ== +"@abp/moment@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/moment/-/moment-7.2.0-rc.1.tgz#96697eabd63e67f24c774baa68b37b75d5d774be" + integrity sha512-s+7tgMxBGW/4uQwKEAfdLdgU7gX1t2XD/e0BxfSgex8diaxUQ9DoWrq4qK6EBk1keWqq1fKuMZ4fqbnRFRG+ag== dependencies: moment "^2.9.0" -"@abp/prismjs@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-7.1.1.tgz#bfcee96e5a1e2f98fb29006f16aeeb227a4e773d" - integrity sha512-7o7FRzgGNPR9GxQ6CPskWL2N87LykoylKnkCm0Cz0n+x0JSrAEMv2yEiJJT2L1S+51ldCQhBmF2blOjxgUT98A== +"@abp/prismjs@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/prismjs/-/prismjs-7.2.0-rc.1.tgz#c775a9a04e9edb55cac06bf355c2a5f013837874" + integrity sha512-TaMfj18i5UXGVHBOP/JTHIVnEg/CdrfpIRwGjyG51CjWOK28xYfeRRYU41q+7UXTv3AjgwWT+B1ksyst6DA7Fw== dependencies: - "@abp/clipboard" "~7.1.1" - "@abp/core" "~7.1.1" + "@abp/clipboard" "~7.2.0-rc.1" + "@abp/core" "~7.2.0-rc.1" prismjs "^1.26.0" -"@abp/select2@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-7.1.1.tgz#1afa414ce68c1f35c3e7ab1beee00f924604de51" - integrity sha512-+5MMLQuXlj07VIXhVKEAmeqsfuGXHWwtpDY2LMsT15lNJbrvq0wF9KZJ0eMF8u29Nyk8IuBJf1YRUzx815PiVg== +"@abp/select2@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/select2/-/select2-7.2.0-rc.1.tgz#7c076ad31efe5087f361ea01f66cf00bc409c8b1" + integrity sha512-Hmmfl11hgHb7TSss7ptj48zqgez75wTHHfUhAyZsU/qu3/w2s7qTOAIoJczuARKBJ3eXKku9U1otzC7gR7LqKQ== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" select2 "^4.0.13" -"@abp/sweetalert2@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-7.1.1.tgz#9ba7578ab53af056f26ef34ae0f2fddc28722c12" - integrity sha512-8hjmEqmcRoMN3Cmk7k0lNdtsm8JytrjPzvHahjqKHIcK1Zi0RbjWJpafbvDu5IFlFrRNYHXlqpUw8e3dtCEp3A== +"@abp/sweetalert2@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/sweetalert2/-/sweetalert2-7.2.0-rc.1.tgz#c6cc72b5eb8a4909c42be27566077c4b1ce2e377" + integrity sha512-VSeaSxCuzEziQPjLQ2IXhuyC2PYOI8dp7Bi5uEtFG3fnHz042rcRZSgh6teks6eRRUNxuv17YnV/LAEvm2UQtg== dependencies: - "@abp/core" "~7.1.1" + "@abp/core" "~7.2.0-rc.1" sweetalert2 "^11.3.6" -"@abp/timeago@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-7.1.1.tgz#c7be25a320aa311e2e9c7a8186b51766db4523ac" - integrity sha512-FsIjAiP2dqRHwrrKx/5tWgLMZ2LboNLhrHeRb1FFol/0163uVEQGEJkxLOE5xY530mdaFFfAOc0x6aniSLE4ZQ== +"@abp/timeago@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/timeago/-/timeago-7.2.0-rc.1.tgz#1f0f0ba199501c760cf53e493fd63bbe8a6329f2" + integrity sha512-QfbnOOBye76m+x+uOPcZG40zDOIyIgWssoUyBQDch6Z3A9HcDhw6qQBlsoeuX2+N/be1KCIfUHvjHE92Zdhktg== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" timeago "^1.6.7" -"@abp/toastr@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-7.1.1.tgz#5ef7da983a226f226d8b9b85f2fa9ff7eeed41aa" - integrity sha512-8x8FQt8BSmgI1b6JXK7N+JJJ0ksBcFSMQol0AbzTOFOBO2T77eXIuiVh8961ynaeIECjGWcazXUMuG09Drq6Ig== +"@abp/toastr@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/toastr/-/toastr-7.2.0-rc.1.tgz#758a74cd8d699c9c8fb1cc23b7e39762b6929861" + integrity sha512-IREF8C/CYb2PJrSWqYWoqvrzDrgBDrQSkGJvMVNo4DRj2V66UzHUfMFQBoQA40m0tY354SEhowhPRbj9BhQGtA== dependencies: - "@abp/jquery" "~7.1.1" + "@abp/jquery" "~7.2.0-rc.1" toastr "^2.1.4" -"@abp/utils@~7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-7.1.1.tgz#e11bc878573dd8118e42b3c1582c44d8b5c71d83" - integrity sha512-G4S0ndDUe8W525O8KUBucLcrESoSFjeqLjRZ+W7N7K9D/oLisYU9Siwxb2csTdjXz6JeQ7AtQl7ak1WpAMiJ/g== +"@abp/utils@~7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-7.2.0-rc.1.tgz#25726da9d39e887a490eff44b2ce9a28826ec4dd" + integrity sha512-g/G+En4Te3b9x/7bSf8WDwUjBusiLf4oVcUVk65/wbC0BezMsxnrzRr1ZMZQyYYGJYJ3DdnUftOLziUx9o7U6A== dependencies: just-compare "^1.3.0" -"@abp/virtual-file-explorer@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@abp/virtual-file-explorer/-/virtual-file-explorer-7.1.1.tgz#8d569a73cc53b8989b2c51838ae5a1e7f25e398f" - integrity sha512-YRlQIJEyKv5Ai0OAGzgm3pwRTQ9PkAb/pTxGrK12R2YIOTPPfpRfEyK6PSjlt/OGOiFHk2phhW48QjqWBDER+g== +"@abp/virtual-file-explorer@^7.2.0-rc.1": + version "7.2.0-rc.1" + resolved "https://registry.yarnpkg.com/@abp/virtual-file-explorer/-/virtual-file-explorer-7.2.0-rc.1.tgz#c75581e12a0bce3c445a561697aa1fc94d6b496f" + integrity sha512-TzNIUOcHj0+PVbHCc5ROVY+ln1Ps6YWrpypvWjGCPgYofgEq7NLUUbXQn3mlnlJsnJdygaFswRtPOO/uKjm0pg== dependencies: - "@abp/clipboard" "~7.1.1" - "@abp/prismjs" "~7.1.1" + "@abp/clipboard" "~7.2.0-rc.1" + "@abp/prismjs" "~7.2.0-rc.1" "@fortawesome/fontawesome-free@^5.15.4": version "5.15.4" diff --git a/npm/lerna.json b/npm/lerna.json index 1221175ab6..b8b3d92ef0 100644 --- a/npm/lerna.json +++ b/npm/lerna.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "packages": [ "packs/*" ], diff --git a/npm/ng-packs/angular.json b/npm/ng-packs/angular.json index 01e482cd85..14416d1d3a 100644 --- a/npm/ng-packs/angular.json +++ b/npm/ng-packs/angular.json @@ -195,14 +195,54 @@ "assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"], "styles": [ { - "input": "node_modules/bootstrap/dist/css/bootstrap.rtl.min.css", + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css", "inject": false, - "bundleName": "bootstrap-rtl.min" + "bundleName": "bootstrap-dim" }, { - "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", - "inject": true, - "bundleName": "bootstrap-ltr.min" + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/ng-bundle.css", + "inject": false, + "bundleName": "ng-bundle" + }, + { + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/side-menu/layout-bundle.css", + "inject": false, + "bundleName": "layout-bundle" + }, + { + "input": "node_modules/@abp/ng.theme.lepton-x/assets/css/abp-bundle.css", + "inject": false, + "bundleName": "abp-bundle" + }, + { + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.rtl.css", + "inject": false, + "bundleName": "bootstrap-dim.rtl" + }, + { + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/ng-bundle.rtl.css", + "inject": false, + "bundleName": "ng-bundle.rtl" + }, + { + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/side-menu/layout-bundle.rtl.css", + "inject": false, + "bundleName": "layout-bundle.rtl" + }, + { + "input": "node_modules/@abp/ng.theme.lepton-x/assets/css/abp-bundle.rtl.css", + "inject": false, + "bundleName": "abp-bundle.rtl" + }, + { + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/font-bundle.rtl.css", + "inject": false, + "bundleName": "font-bundle.rtl" + }, + { + "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/font-bundle.css", + "inject": false, + "bundleName": "font-bundle" }, { "input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css", @@ -234,6 +274,7 @@ "inject": false, "bundleName": "ng-zorro-antd-tree" }, + "node_modules/bootstrap-icons/font/bootstrap-icons.css", "apps/dev-app/src/styles.scss" ], "scripts": [] @@ -715,7 +756,7 @@ } }, "tags": [], - "implicitDependencies": ["core","oauth"] + "implicitDependencies": ["core", "oauth"] } } } 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 index 52ebd38362..56e38b40ee 100644 --- a/npm/ng-packs/apps/dev-app/src/app/app.module.ts +++ b/npm/ng-packs/apps/dev-app/src/app/app.module.ts @@ -4,7 +4,8 @@ import { registerLocale } from '@abp/ng.core/locale'; import { IdentityConfigModule } from '@abp/ng.identity/config'; import { SettingManagementConfigModule } from '@abp/ng.setting-management/config'; import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config'; -import { ThemeBasicModule } from '@abp/ng.theme.basic'; +import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x'; +import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts'; import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; @@ -34,7 +35,8 @@ import { AbpOAuthModule } from '@abp/ng.oauth'; TenantManagementConfigModule.forRoot(), FeatureManagementModule.forRoot(), SettingManagementConfigModule.forRoot(), - ThemeBasicModule.forRoot(), + ThemeLeptonXModule.forRoot(), + SideMenuLayoutModule.forRoot(), ], providers: [APP_ROUTE_PROVIDER], declarations: [AppComponent], diff --git a/npm/ng-packs/apps/dev-app/src/app/home/home.component.html b/npm/ng-packs/apps/dev-app/src/app/home/home.component.html index 2d249da3d8..7024ab69e5 100644 --- a/npm/ng-packs/apps/dev-app/src/app/home/home.component.html +++ b/npm/ng-packs/apps/dev-app/src/app/home/home.component.html @@ -26,8 +26,8 @@

Let's improve your application!

Here are some links to help you get started:

-
-
+ +
-
-
+ +

Meet the ABP Commercial

A Complete Web Application Platform Built on the ABP Framework

- -
-
+ +

ABP Commercial is a platform based on the open source ABP framework. It provides pre-built application modules, rapid @@ -271,8 +270,9 @@ " >

-
- + + +

=12.0.0", "@angular/core": ">=12.0.0" }, diff --git a/npm/ng-packs/packages/account/package.json b/npm/ng-packs/packages/account/package.json index 38a568ce31..ba0152de26 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": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.account.core": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.account.core": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/components/package.json b/npm/ng-packs/packages/components/package.json index 8c07ea8c96..9850fb3fd4 100644 --- a/npm/ng-packs/packages/components/package.json +++ b/npm/ng-packs/packages/components/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.components", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "peerDependencies": { - "@abp/ng.core": ">=7.1.1", - "@abp/ng.theme.shared": ">=7.1.1", + "@abp/ng.core": ">=7.2.0-rc.1", + "@abp/ng.theme.shared": ">=7.2.0-rc.1", "@ng-bootstrap/ng-bootstrap": ">=10.0.0" }, "dependencies": { diff --git a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts index 5df8ed5ee0..ccc44cde0b 100644 --- a/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts +++ b/npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts @@ -1,4 +1,6 @@ import { + ChangeDetectionStrategy, + ChangeDetectorRef, Component, ContentChild, EventEmitter, @@ -26,6 +28,7 @@ export type DropEvent = NzFormatEmitEvent & { pos: number }; styleUrls: ['tree.component.scss'], encapsulation: ViewEncapsulation.None, providers: [SubscriptionService], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TreeComponent implements OnInit { dropPosition: number; @@ -38,6 +41,7 @@ export class TreeComponent implements OnInit { @Optional() @Inject(DISABLE_TREE_STYLE_LOADING_TOKEN) private disableTreeStyleLoading: boolean | undefined, + private cdr: ChangeDetectorRef, ) {} @ContentChild('menu') menu: TemplateRef; @@ -77,6 +81,21 @@ export class TreeComponent implements OnInit { this.subscriptionService.addOne(loaded$); } + private findNode(target: any, nodes: any[]) { + for (const node of nodes) { + if (node.key === target.id) { + return node; + } + if (node.children) { + let res = this.findNode(target, node.children); + if (res) { + return res; + } + } + } + return null; + } + onSelectedNodeChange(node: NzTreeNode) { this.selectedNode = node.origin.entity; if (this.changeCheckboxWithNode) { @@ -116,4 +135,10 @@ export class TreeComponent implements OnInit { initDropdown(key: string, dropdown: NgbDropdown) { this.dropdowns[key] = dropdown; } + + setSelectedNode(node: any) { + let newSelectedNode = this.findNode(node, this.nodes); + this.selectedNode = { ...newSelectedNode }; + this.cdr.markForCheck(); + } } diff --git a/npm/ng-packs/packages/core/package.json b/npm/ng-packs/packages/core/package.json index e89e42f1b5..818fa4a254 100644 --- a/npm/ng-packs/packages/core/package.json +++ b/npm/ng-packs/packages/core/package.json @@ -1,13 +1,13 @@ { "name": "@abp/ng.core", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/utils": "~7.1.1", + "@abp/utils": "~7.2.0-rc.1", "angular-oauth2-oidc": "^15.0.1", "just-clone": "^6.1.1", "just-compare": "^2.3.0", diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index 9655be6c5f..c2d497ae7b 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -24,6 +24,7 @@ import { ToInjectorPipe } from './pipes/to-injector.pipe'; import { CookieLanguageProvider } from './providers/cookie-language.provider'; import { LocaleProvider } from './providers/locale.provider'; import { LocalizationService } from './services/localization.service'; +import { OTHERS_GROUP } from './tokens'; import { localizationContributor, LOCALIZATIONS } from './tokens/localization.token'; import { CORE_OPTIONS, coreOptionsFactory } from './tokens/options.token'; import { TENANT_KEY } from './tokens/tenant-key.token'; @@ -179,6 +180,10 @@ export class CoreModule { provide: QUEUE_MANAGER, useClass: DefaultQueueManager, }, + { + provide: OTHERS_GROUP, + useValue: options.othersGroup || 'AbpUi::OthersGroup', + }, IncludeLocalizationResourcesProvider, ], }; diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 12318357dd..7a285b4461 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -12,6 +12,7 @@ export namespace ABP { sendNullsAsQueryParam?: boolean; tenantKey?: string; localizations?: Localization[]; + othersGroup?: string; } export interface Child { @@ -70,6 +71,7 @@ export namespace ABP { path?: string; layout?: eLayoutType; iconClass?: string; + group?: string; } export interface Tab extends Nav { diff --git a/npm/ng-packs/packages/core/src/lib/models/rest.ts b/npm/ng-packs/packages/core/src/lib/models/rest.ts index c5517ffa98..74cc3407f0 100644 --- a/npm/ng-packs/packages/core/src/lib/models/rest.ts +++ b/npm/ng-packs/packages/core/src/lib/models/rest.ts @@ -4,6 +4,7 @@ export namespace Rest { export type Config = Partial<{ apiName: string; skipHandleError: boolean; + skipAddingHeader: boolean; observe: Observe; httpParamEncoder?: HttpParameterCodec; }>; diff --git a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts index e9a6e89851..a7ee7a491b 100644 --- a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts @@ -2,6 +2,7 @@ import { HttpClient, HttpParameterCodec, HttpParams, HttpRequest } from '@angula import { Inject, Injectable } from '@angular/core'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; +import { ExternalHttpClient } from '../clients/http.client'; import { ABP } from '../models/common'; import { Rest } from '../models/rest'; import { CORE_OPTIONS } from '../tokens/options.token'; @@ -16,6 +17,7 @@ export class RestService { constructor( @Inject(CORE_OPTIONS) protected options: ABP.Root, protected http: HttpClient, + protected externalHttp: ExternalHttpClient, protected environment: EnvironmentService, protected httpErrorReporter: HttpErrorReporterService, ) {} @@ -39,7 +41,9 @@ export class RestService { const { method, params, ...options } = request; const { observe = Rest.Observe.Body, skipHandleError } = config; const url = this.removeDuplicateSlashes(api + request.url); - return this.http + + const httpClient: HttpClient = this.getHttpClient(config.skipAddingHeader); + return httpClient .request(method, url, { observe, ...(params && { @@ -49,6 +53,9 @@ export class RestService { } as any) .pipe(catchError(err => (skipHandleError ? throwError(err) : this.handleError(err)))); } + private getHttpClient(isExternal: boolean) { + return isExternal ? this.externalHttp : this.http; + } private getParams(params: Rest.Params, encoder?: HttpParameterCodec): HttpParams { const filteredParams = Object.entries(params).reduce((acc, [key, value]) => { diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index 32f8b473d0..329d2a370c 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -1,13 +1,20 @@ import { Injectable, Injector, OnDestroy } from '@angular/core'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, map } from 'rxjs'; import { ABP } from '../models/common'; +import { OTHERS_GROUP } from '../tokens'; import { pushValueTo } from '../utils/array-utils'; -import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils'; +import { + BaseTreeNode, + createTreeFromList, + TreeNode, + RouteGroup, + createGroupMap, +} from '../utils/tree-utils'; import { ConfigStateService } from './config-state.service'; import { PermissionService } from './permission.service'; // eslint-disable-next-line @typescript-eslint/ban-types -export abstract class AbstractTreeService { +export abstract class AbstractTreeService { abstract id: string; abstract parentId: string; abstract hide: (item: T) => boolean; @@ -17,6 +24,8 @@ export abstract class AbstractTreeService[]>([]); private _visible$ = new BehaviorSubject[]>([]); + protected othersGroup: string; + get flat(): T[] { return this._flat$.value; } @@ -50,6 +59,15 @@ export abstract class AbstractTreeService[]): RouteGroup[] | undefined { + const map = createGroupMap(list, this.othersGroup); + if (!map) { + return undefined; + } + + return Array.from(map, ([key, items]) => ({ group: key, items })); + } + private filterWith(setOrMap: Set | Map): T[] { return this._flat$.value.filter(item => !setOrMap.has(item[this.id])); } @@ -157,6 +175,7 @@ export abstract class AbstractNavTreeService .createOnUpdateStream(state => state) .subscribe(() => this.refresh()); this.permissionService = injector.get(PermissionService); + this.othersGroup = injector.get(OTHERS_GROUP); } protected isGranted({ requiredPolicy }: T): boolean { @@ -180,4 +199,19 @@ export abstract class AbstractNavTreeService } @Injectable({ providedIn: 'root' }) -export class RoutesService extends AbstractNavTreeService {} +export class RoutesService extends AbstractNavTreeService { + private hasPathOrChild(item: TreeNode): boolean { + return Boolean(item.path) || this.hasChildren(item.name); + } + + get groupedVisible(): RouteGroup[] | undefined { + return this.createGroupedTree(this.visible.filter(item => this.hasPathOrChild(item))); + } + + get groupedVisible$(): Observable[] | undefined> { + return this.visible$.pipe( + map(items => items.filter(item => this.hasPathOrChild(item))), + map(visible => this.createGroupedTree(visible)), + ); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts index 51c81a5b3c..ab9c6a76ae 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts @@ -1,4 +1,4 @@ -import { Subject } from 'rxjs'; +import { Subject, lastValueFrom } from 'rxjs'; import { take } from 'rxjs/operators'; import { RoutesService } from '../services/routes.service'; import { DummyInjector } from './utils/common.utils'; @@ -10,6 +10,7 @@ export const mockRoutesService = (injectorPayload = {} as { [key: string]: any } const injector = new DummyInjector({ PermissionService: mockPermissionService(), ConfigStateService: { createOnUpdateStream: () => updateStream$ }, + OTHERS_GROUP: 'OthersGroup', ...injectorPayload, }); return new RoutesService(injector); @@ -17,6 +18,11 @@ export const mockRoutesService = (injectorPayload = {} as { [key: string]: any } describe('Routes Service', () => { let service: RoutesService; + + const fooGroup = 'FooGroup'; + const barGroup = 'BarGroup'; + const othersGroup = 'OthersGroup'; + const routes = [ { path: '/foo', name: 'foo' }, { path: '/foo/bar', name: 'bar', parentName: 'foo', invisible: true, order: 2 }, @@ -25,6 +31,14 @@ describe('Routes Service', () => { { path: '/foo/x', name: 'x', parentName: 'foo', order: 1 }, ]; + const groupedRoutes = [ + { path: '/foo', name: 'foo', group: fooGroup }, + { path: '/foo/y', name: 'y', parentName: 'foo' }, + { path: '/foo/bar', name: 'bar', group: barGroup }, + { path: '/foo/bar/baz', name: 'baz', group: barGroup }, + { path: '/foo/z', name: 'z' }, + ]; + beforeEach(() => { service = mockRoutesService(); }); @@ -33,9 +47,9 @@ describe('Routes Service', () => { it('should add given routes as flat$, tree$, and visible$', async () => { service.add(routes); - const flat = await service.flat$.pipe(take(1)).toPromise(); - const tree = await service.tree$.pipe(take(1)).toPromise(); - const visible = await service.visible$.pipe(take(1)).toPromise(); + const flat = await lastValueFrom(service.flat$.pipe(take(1))); + const tree = await lastValueFrom(service.tree$.pipe(take(1))); + const visible = await lastValueFrom(service.visible$.pipe(take(1))); expect(flat.length).toBe(5); expect(flat[0].name).toBe('baz'); @@ -59,6 +73,52 @@ describe('Routes Service', () => { }); }); + describe('#groupedVisible', () => { + it('should return undefined when there are no visible routes', async () => { + service.add(routes); + const result = await lastValueFrom(service.groupedVisible$.pipe(take(1))); + expect(result).toBeUndefined(); + }); + + it( + 'should group visible routes under "' + othersGroup + '" when no group is specified', + async () => { + service.add([ + { path: '/foo', name: 'foo' }, + { path: '/foo/bar', name: 'bar', group: '' }, + { path: '/foo/bar/baz', name: 'baz', group: undefined }, + { path: '/x', name: 'y', group: 'z' }, + ]); + + const result = await lastValueFrom(service.groupedVisible$.pipe(take(1))); + + expect(result[0].group).toBe(othersGroup); + expect(result[0].items[0].name).toBe('foo'); + expect(result[0].items[1].name).toBe('bar'); + expect(result[0].items[2].name).toBe('baz'); + }, + ); + + it('should return grouped route list', async () => { + service.add(groupedRoutes); + + const tree = await lastValueFrom(service.groupedVisible$.pipe(take(1))); + + expect(tree.length).toBe(3); + + expect(tree[0].group).toBe('FooGroup'); + expect(tree[0].items[0].name).toBe('foo'); + expect(tree[0].items[0].children[0].name).toBe('y'); + + expect(tree[1].group).toBe('BarGroup'); + expect(tree[1].items[0].name).toBe('bar'); + expect(tree[1].items[1].name).toBe('baz'); + + expect(tree[2].group).toBe(othersGroup); + expect(tree[2].items[0].name).toBe('z'); + }); + }); + describe('#find', () => { it('should return node found based on query', () => { service.add(routes); diff --git a/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts b/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts index e568b63a17..01612a987e 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts @@ -14,6 +14,6 @@ export class DummyInjector extends Injector { ): T; get(token: any, notFoundValue?: any): any; get(token, notFoundValue?, flags?: InjectFlags): any { - return this.payload[token.name || token]; + return this.payload[token.name || token._desc || token]; } } diff --git a/npm/ng-packs/packages/core/src/lib/tokens/index.ts b/npm/ng-packs/packages/core/src/lib/tokens/index.ts index f0e724259a..d01f652b98 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/index.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/index.ts @@ -12,3 +12,4 @@ export * from './pipe-to-login.token'; export * from './set-token-response-to-storage.token'; export * from './check-authentication-state'; export * from './http-context.token'; +export * from './others-group.token' \ No newline at end of file diff --git a/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts new file mode 100644 index 0000000000..23d7d65b92 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tokens/others-group.token.ts @@ -0,0 +1,3 @@ +import { InjectionToken } from '@angular/core'; + +export const OTHERS_GROUP = new InjectionToken('OTHERS_GROUP'); diff --git a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts index bfc938c158..8ea8cc504c 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts @@ -1,3 +1,5 @@ +import { isArray } from './common-utils'; + /* eslint-disable @typescript-eslint/ban-types */ export class BaseTreeNode { children: TreeNode[] = []; @@ -74,6 +76,28 @@ export function createTreeNodeFilterCreator( }; } +export function createGroupMap( + list: TreeNode[], + othersGroupKey: string, +) { + if (!isArray(list) || !list.some(node => Boolean(node.group))) return undefined; + + const mapGroup = new Map[]>(); + + for (const node of list) { + const group = node?.group || othersGroupKey; + if (typeof group !== 'string') { + throw new Error(`Invalid group: ${group}`); + } + + const items = mapGroup.get(group) || []; + items.push(node); + mapGroup.set(group, items); + } + + return mapGroup; +} + export type TreeNode = { [K in keyof T]: T[K]; } & { @@ -82,6 +106,11 @@ export type TreeNode = { parent?: TreeNode; }; +export type RouteGroup = { + readonly group: string; + readonly items: TreeNode[]; +}; + export type NodeKey = number | string | symbol | undefined | null; export type NodeValue any> = F extends undefined diff --git a/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts b/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts index 65e1763817..7fd171c1d4 100644 --- a/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts +++ b/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts @@ -2,6 +2,7 @@ import { ABP, CORE_OPTIONS, EnvironmentService, + ExternalHttpClient, HttpErrorReporterService, RestService, } from '@abp/ng.core'; @@ -16,9 +17,10 @@ export class MockRestService extends RestService { constructor( @Inject(CORE_OPTIONS) protected options: ABP.Root, protected http: HttpClient, + protected externalhttp: ExternalHttpClient, protected environment: EnvironmentService, ) { - super(options, http, environment, null as unknown as HttpErrorReporterService); + super(options, http,externalhttp, environment, null as unknown as HttpErrorReporterService); } handleError(err: any): Observable { diff --git a/npm/ng-packs/packages/feature-management/package.json b/npm/ng-packs/packages/feature-management/package.json index c365e2fcb2..136ba93177 100644 --- a/npm/ng-packs/packages/feature-management/package.json +++ b/npm/ng-packs/packages/feature-management/package.json @@ -1,13 +1,13 @@ { "name": "@abp/ng.feature-management", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/identity/package.json b/npm/ng-packs/packages/identity/package.json index 47b715c5ea..670fe7bd10 100644 --- a/npm/ng-packs/packages/identity/package.json +++ b/npm/ng-packs/packages/identity/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.identity", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.permission-management": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.permission-management": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index 0b7db30ace..eaf21949f3 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -49,18 +49,24 @@ *ngFor="let roleGroup of roleGroups; let i = index; trackBy: trackByFn" class="form-check mb-2" > - - + [label]="roles[i].name" + > +

-
diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts index cb0cdd9755..6dd1ab9f17 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts @@ -1,12 +1,28 @@ -import { ListService, PagedResultDto } from "@abp/ng.core"; -import { GetIdentityUsersInput, IdentityRoleDto, IdentityUserDto, IdentityUserService } from "@abp/ng.identity/proxy"; -import { ePermissionManagementComponents } from "@abp/ng.permission-management"; -import { Confirmation, ConfirmationService, ToasterService } from "@abp/ng.theme.shared"; -import { EXTENSIONS_IDENTIFIER, FormPropData, generateFormFromProps } from "@abp/ng.theme.shared/extensions"; -import { Component, Injector, OnInit, TemplateRef, TrackByFunction, ViewChild } from "@angular/core"; -import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from "@angular/forms"; -import { finalize, switchMap, tap } from "rxjs/operators"; -import { eIdentityComponents } from "../../enums/components"; +import { ListService, PagedResultDto } from '@abp/ng.core'; +import { + GetIdentityUsersInput, + IdentityRoleDto, + IdentityUserDto, + IdentityUserService, +} from '@abp/ng.identity/proxy'; +import { ePermissionManagementComponents } from '@abp/ng.permission-management'; +import {Confirmation, ConfirmationService, eFormComponets, ToasterService} from '@abp/ng.theme.shared'; +import { + EXTENSIONS_IDENTIFIER, + FormPropData, + generateFormFromProps, +} from '@abp/ng.theme.shared/extensions'; +import { + Component, + Injector, + OnInit, + TemplateRef, + TrackByFunction, + ViewChild, +} from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { finalize, switchMap, tap } from 'rxjs/operators'; +import { eIdentityComponents } from '../../enums/components'; @Component({ selector: 'abp-users', @@ -43,7 +59,9 @@ export class UsersComponent implements OnInit { permissionManagementKey = ePermissionManagementComponents.PermissionManagement; - entityDisplayName?: string; + entityDisplayName: string; + + inputKey=eFormComponets.FormCheckboxComponent trackByFn: TrackByFunction = (index, item) => Object.keys(item)[0] || index; diff --git a/npm/ng-packs/packages/oauth/package.json b/npm/ng-packs/packages/oauth/package.json index 675e6879c0..c637f42f3d 100644 --- a/npm/ng-packs/packages/oauth/package.json +++ b/npm/ng-packs/packages/oauth/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.oauth", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.core": "~7.1.1", - "@abp/utils": "~7.1.1", + "@abp/ng.core": "~7.2.0-rc.1", + "@abp/utils": "~7.2.0-rc.1", "angular-oauth2-oidc": "^15.0.1", "just-clone": "^6.1.1", "just-compare": "^1.4.0", diff --git a/npm/ng-packs/packages/permission-management/package.json b/npm/ng-packs/packages/permission-management/package.json index 0e0431c154..48990be8ef 100644 --- a/npm/ng-packs/packages/permission-management/package.json +++ b/npm/ng-packs/packages/permission-management/package.json @@ -1,13 +1,13 @@ { "name": "@abp/ng.permission-management", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts index 6193a5bc20..5a3373121c 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts @@ -81,7 +81,7 @@ export class PermissionManagementComponent }); }); } else { - this.selectedGroup = null; + this.setSelectedGroup(null); this._visible = false; this.visibleChange.emit(false); } @@ -110,10 +110,22 @@ export class PermissionManagementComponent modalBusy = false; + selectedGroupPermissions: PermissionWithStyle[] = []; + trackByFn: TrackByFunction = (_, item) => item.name; - get selectedGroupPermissions(): PermissionWithStyle[] { - if (!this.selectedGroup) return []; + constructor(protected service: PermissionsService, protected configState: ConfigStateService) {} + + getChecked(name: string) { + return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted; + } + + setSelectedGroup(group: PermissionGroupDto) { + this.selectedGroup = group; + if (!this.selectedGroup) { + this.selectedGroupPermissions = []; + return; + } const margin = `margin-${ (document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left' @@ -123,7 +135,7 @@ export class PermissionManagementComponent (this.data.groups.find(group => group.name === this.selectedGroup?.name) || {}).permissions || []; - return permissions.map( + this.selectedGroupPermissions = permissions.map( permission => ({ ...permission, @@ -133,12 +145,6 @@ export class PermissionManagementComponent ); } - constructor(protected service: PermissionsService, protected configState: ConfigStateService) {} - - getChecked(name: string) { - return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted; - } - setDisabled(permissions: PermissionGrantInfoDto[]) { if (permissions.length) { this.disableSelectAllTab = permissions.every( @@ -248,7 +254,7 @@ export class PermissionManagementComponent onChangeGroup(group: PermissionGroupDto) { this.setDisabled(group.permissions); - this.selectedGroup = group; + this.setSelectedGroup(group); this.setTabCheckboxState(); } @@ -291,8 +297,8 @@ export class PermissionManagementComponent return this.service.get(this.providerName, this.providerKey).pipe( tap((permissionRes: GetPermissionListResultDto) => { this.data = permissionRes; - this.selectedGroup = permissionRes.groups[0]; this.permissions = getPermissions(permissionRes.groups); + this.setSelectedGroup(permissionRes.groups[0]); this.disabledSelectAllInAllTabs = this.permissions.every( per => per.isGranted && diff --git a/npm/ng-packs/packages/schematics/package.json b/npm/ng-packs/packages/schematics/package.json index 9ae4303046..7d5e2d6e98 100644 --- a/npm/ng-packs/packages/schematics/package.json +++ b/npm/ng-packs/packages/schematics/package.json @@ -1,6 +1,6 @@ { "name": "@abp/ng.schematics", - "version": "7.1.1", + "version": "7.2.0-rc.1", "description": "Schematics that works with ABP Backend", "keywords": [ "schematics" diff --git a/npm/ng-packs/packages/schematics/src/commands/api/files-service/proxy/__namespace@dir__/__name@kebab__.service.ts.template b/npm/ng-packs/packages/schematics/src/commands/api/files-service/proxy/__namespace@dir__/__name@kebab__.service.ts.template index 1e1cc4564a..aae3b43471 100644 --- a/npm/ng-packs/packages/schematics/src/commands/api/files-service/proxy/__namespace@dir__/__name@kebab__.service.ts.template +++ b/npm/ng-packs/packages/schematics/src/commands/api/files-service/proxy/__namespace@dir__/__name@kebab__.service.ts.template @@ -25,7 +25,7 @@ export class <%= name %>Service { if (body.body) { %> body: <%= body.body %>,<% } %> }, - { apiName: this.apiName });<% } %> + { apiName: this.apiName,...config });<% } %> constructor(private restService: RestService) {} } diff --git a/npm/ng-packs/packages/schematics/src/utils/service.ts b/npm/ng-packs/packages/schematics/src/utils/service.ts index 28ce82e3f7..0b633a8dd5 100644 --- a/npm/ng-packs/packages/schematics/src/utils/service.ts +++ b/npm/ng-packs/packages/schematics/src/utils/service.ts @@ -22,7 +22,7 @@ import { } from './type'; import { eBindingSourceId } from '../enums'; import { camelizeHyphen } from './text'; -import {VOLO_REMOTE_STREAM_CONTENT} from "../constants"; +import { VOLO_REMOTE_STREAM_CONTENT } from '../constants'; export function serializeParameters(parameters: Property[]) { return parameters.map(p => p.name + p.optional + ': ' + p.type + p.default, '').join(', '); @@ -39,9 +39,12 @@ export function createControllerToServiceMapper({ const name = controller.controllerName; const namespace = parseNamespace(solution, controller.type); const actions = Object.values(controller.actions); - const typeWithoutIRemoteStreamContent = getTypesWithoutIRemoteStreamContent(types) - const imports = actions.reduce(createActionToImportsReducer(solution, typeWithoutIRemoteStreamContent, namespace), []); - imports.push(new Import({ path: '@abp/ng.core', specifiers: ['RestService'] })); + const typeWithoutIRemoteStreamContent = getTypesWithoutIRemoteStreamContent(types); + const imports = actions.reduce( + createActionToImportsReducer(solution, typeWithoutIRemoteStreamContent, namespace), + [], + ); + imports.push(new Import({ path: '@abp/ng.core', specifiers: ['RestService', 'Rest'] })); imports.push(new Import({ path: '@angular/core', specifiers: ['Injectable'] })); sortImports(imports); const methods = actions.map(mapActionToMethod); @@ -51,9 +54,9 @@ export function createControllerToServiceMapper({ } function getTypesWithoutIRemoteStreamContent(types: Record) { - const newType = {...types} - delete newType[VOLO_REMOTE_STREAM_CONTENT] - return newType + const newType = { ...types }; + delete newType[VOLO_REMOTE_STREAM_CONTENT]; + return newType; } function sortMethods(methods: Method[]) { methods.sort((a, b) => (a.signature.name > b.signature.name ? 1 : -1)); @@ -76,7 +79,7 @@ export function createActionToBodyMapper() { return ({ httpMethod, parameters, returnValue, url }: Action) => { const responseType = adaptType(returnValue.typeSimple); const responseTypeWithNamespace = returnValue.typeSimple; - const body = new Body({ method: httpMethod, responseType, url ,responseTypeWithNamespace}); + const body = new Body({ method: httpMethod, responseType, url, responseTypeWithNamespace }); parameters.forEach(body.registerActionParameter); @@ -90,6 +93,8 @@ export function createActionToSignatureMapper() { return (action: Action) => { const signature = new Signature({ name: getMethodNameFromAction(action) }); const versionParameter = getVersionParameter(action); + const restConfig = new Property({ name: 'config', type: 'Partial' }); + restConfig.setOptional(true); const parameters = [ ...action.parametersOnMethod, ...(versionParameter ? [versionParameter] : []), @@ -101,6 +106,7 @@ export function createActionToSignatureMapper() { parameter.setOptional(p.isOptional); return parameter; }); + signature.parameters.push(restConfig); return signature; }; diff --git a/npm/ng-packs/packages/setting-management/package.json b/npm/ng-packs/packages/setting-management/package.json index ebb9b30826..582f228270 100644 --- a/npm/ng-packs/packages/setting-management/package.json +++ b/npm/ng-packs/packages/setting-management/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.setting-management", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.components": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.components": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/tenant-management/package.json b/npm/ng-packs/packages/tenant-management/package.json index f8dd446f3f..2c5a9de3ef 100644 --- a/npm/ng-packs/packages/tenant-management/package.json +++ b/npm/ng-packs/packages/tenant-management/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.tenant-management", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.feature-management": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.feature-management": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/theme-basic/package.json b/npm/ng-packs/packages/theme-basic/package.json index c053c88967..9858e579d7 100644 --- a/npm/ng-packs/packages/theme-basic/package.json +++ b/npm/ng-packs/packages/theme-basic/package.json @@ -1,14 +1,14 @@ { "name": "@abp/ng.theme.basic", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.account.core": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.account.core": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "tslib": "^2.0.0" }, "publishConfig": { diff --git a/npm/ng-packs/packages/theme-shared/package.json b/npm/ng-packs/packages/theme-shared/package.json index dd05125b19..02db35818b 100644 --- a/npm/ng-packs/packages/theme-shared/package.json +++ b/npm/ng-packs/packages/theme-shared/package.json @@ -1,13 +1,13 @@ { "name": "@abp/ng.theme.shared", - "version": "7.1.1", + "version": "7.2.0-rc.1", "homepage": "https://abp.io", "repository": { "type": "git", "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.core": "~7.1.1", + "@abp/ng.core": "~7.2.0-rc.1", "@fortawesome/fontawesome-free": "^5.15.4", "@ng-bootstrap/ng-bootstrap": "^14.0.0", "@ngx-validate/core": "^0.2.0", diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts new file mode 100644 index 0000000000..e983083a88 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts @@ -0,0 +1,13 @@ +import { Component, HostBinding, Input } from '@angular/core'; + +@Component({ + selector: 'abp-card-body', + template: `
+ +
`, +}) +export class CardBodyComponent { + @HostBinding('class') componentClass = 'card-body'; + @Input() cardBodyClass: string; + @Input() cardBodyStyle: string; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-footer.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-footer.component.ts new file mode 100644 index 0000000000..d82a8725c1 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-footer.component.ts @@ -0,0 +1,16 @@ +import { Component, HostBinding, Input } from '@angular/core'; + +@Component({ + selector: 'abp-card-footer', + template: ` +
+ +
+ `, + styles: [], +}) +export class CardFooterComponent { + @HostBinding('class') componentClass = 'card-footer'; + @Input() cardFooterStyle: string; + @Input() cardFooterClass: string; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.component.ts new file mode 100644 index 0000000000..7dfb75b2d9 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.component.ts @@ -0,0 +1,16 @@ +import { Component, HostBinding, Input } from '@angular/core'; + +@Component({ + selector: 'abp-card-header', + template: ` +
+ +
+ `, + styles: [], +}) +export class CardHeaderComponent { + @HostBinding('class') componentClass = 'card-header'; + @Input() cardHeaderClass: string; + @Input() cardHeaderStyle: string; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.directive.ts new file mode 100644 index 0000000000..44b8ff0eb5 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-header.directive.ts @@ -0,0 +1,8 @@ +import { Directive, HostBinding } from '@angular/core'; + +@Directive({ + selector: `abp-card-header, [abp-card-header], [abpCardHeader]`, +}) +export class CardHeaderDirective { + @HostBinding('class') directiveClass = 'card-header'; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-img-top.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-img-top.directive.ts new file mode 100644 index 0000000000..405ea1bb24 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-img-top.directive.ts @@ -0,0 +1,8 @@ +import { Directive, HostBinding } from '@angular/core'; + +@Directive({ + selector: `abp-card-img-top, [abp-card-img-top], [abpCardImgTop]`, +}) +export class CardImgTopDirective { + @HostBinding('class') directiveClass = 'card-img-top'; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-subtitle.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-subtitle.directive.ts new file mode 100644 index 0000000000..57ba722500 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-subtitle.directive.ts @@ -0,0 +1,8 @@ +import { Directive, HostBinding } from '@angular/core'; + +@Directive({ + selector: `abp-card-subtitle, [abp-card-subtitle], [abpCardSubtitle]`, +}) +export class CardSubtitleDirective { + @HostBinding('class') directiveClass = 'card-subtitle'; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-title.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-title.directive.ts new file mode 100644 index 0000000000..0bb92d9263 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-title.directive.ts @@ -0,0 +1,8 @@ +import { Directive, HostBinding } from '@angular/core'; + +@Directive({ + selector: `abp-card-title, [abp-card-title], [abpCardTitle]`, +}) +export class CardTitleDirective { + @HostBinding('class') directiveClass = 'card-title'; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts new file mode 100644 index 0000000000..fc5279be66 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'abp-card', + template: `
+ +
`, +}) +export class CardComponent { + @Input() cardClass: string; + + @Input() cardStyle: string; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.module.ts new file mode 100644 index 0000000000..ac7e28e568 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.module.ts @@ -0,0 +1,28 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { CardBodyComponent } from './card-body.component'; +import { CardComponent } from './card.component'; +import { CardHeaderComponent } from './card-header.component'; +import { CardFooterComponent } from './card-footer.component'; +import { CardTitleDirective } from './card-title.directive'; +import { CardSubtitleDirective } from './card-subtitle.directive'; +import { CardImgTopDirective } from './card-img-top.directive'; +import { CardHeaderDirective } from './card-header.directive'; + +const declarationsWithExports = [ + CardComponent, + CardBodyComponent, + CardHeaderComponent, + CardFooterComponent, + CardTitleDirective, + CardSubtitleDirective, + CardImgTopDirective, + CardHeaderDirective, +]; + +@NgModule({ + declarations: [...declarationsWithExports], + imports: [CommonModule], + exports: [...declarationsWithExports], +}) +export class CardModule {} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/index.ts new file mode 100644 index 0000000000..ab901f35fe --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/index.ts @@ -0,0 +1,9 @@ +export * from './card.module'; +export * from './card.component'; +export * from './card-body.component'; +export * from './card-footer.component'; +export * from './card-header.component'; +export * from './card-title.directive'; +export * from './card-subtitle.directive'; +export * from './card-img-top.directive'; +export * from './card-header.directive'; \ No newline at end of file diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts new file mode 100644 index 0000000000..ee2dd5aeac --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts @@ -0,0 +1,50 @@ +import { AbstractNgModelComponent } from '@abp/ng.core'; +import { Component, EventEmitter, forwardRef, Injector, Input, Output } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +@Component({ + selector: 'abp-checkbox', + template: ` +
+ + +
+ `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FormCheckboxComponent), + multi: true, + }, + ], +}) +export class FormCheckboxComponent extends AbstractNgModelComponent { + @Input() label?: string; + @Input() labelClass = 'form-check-label'; + @Input() checkboxId!: string; + @Input() checkboxStyle: + | { + [klass: string]: any; + } + | null + | undefined; + @Input() checkboxClass = 'form-check-input'; + @Input() checkboxReadonly = false; + @Output() checkboxBlur = new EventEmitter(); + @Output() checkboxFocus = new EventEmitter(); + + constructor(injector: Injector) { + super(injector); + } +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts new file mode 100644 index 0000000000..991383fe5a --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts @@ -0,0 +1,53 @@ +import { AbstractNgModelComponent } from '@abp/ng.core'; +import { Component, EventEmitter, forwardRef, Injector, Input, Output } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +@Component({ + selector: 'abp-form-input', + template: ` +
+ + +
+ `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FormInputComponent), + multi: true, + }, + ], +}) +export class FormInputComponent extends AbstractNgModelComponent { + @Input() inputId!: string; + @Input() inputReadonly = false; + @Input() label = ''; + @Input() labelClass = 'form-label'; + @Input() inputPlaceholder = ''; + @Input() inputType = 'text'; + @Input() inputStyle: + | { + [klass: string]: any; + } + | null + | undefined; + @Input() inputClass = 'form-control'; + @Output() formBlur = new EventEmitter(); + @Output() formFocus = new EventEmitter(); + + constructor(injector: Injector) { + super(injector); + } +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts index 810d5a991a..238bc19589 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts @@ -11,3 +11,6 @@ export * from './modal/modal.component'; export * from './toast-container/toast-container.component'; export * from './toast/toast.component'; export * from './password/password.component'; +export * from './card/index'; +export * from './checkbox/checkbox.component'; +export * from './form-input/form-input.component'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/enums/form.ts b/npm/ng-packs/packages/theme-shared/src/lib/enums/form.ts new file mode 100644 index 0000000000..9ccbb93655 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/enums/form.ts @@ -0,0 +1,4 @@ +export enum eFormComponets { + FormInputComponent = 'FormInputComponent', + FormCheckboxComponent = 'FormCheckboxComponent', +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts index 3bda94b078..9e781067f7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts @@ -1 +1,2 @@ +export * from './form'; export * from './route-names'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-body.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-body.component.spec.ts new file mode 100644 index 0000000000..83cc302625 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-body.component.spec.ts @@ -0,0 +1,46 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardBodyComponent } from '../components'; + +describe('AbpCardBodyComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(CardBodyComponent); + + beforeEach( + () => + (spectator = createHost( + ` +

Body

+
`, + { + hostProps: { attributes: { autofocus: '', name: 'abp-card-body' } }, + }, + )), + ); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-body', () => { + expect(spectator.element.classList).toContain('card-body'); + }); + + it('should have div', () => { + expect(spectator.query('div')).toBeTruthy(); + }); + + it('should have background-color red', () => { + expect((spectator.query('div') as HTMLElement).style.backgroundColor).toEqual('red'); + }); + + it('should have p tag', () => { + expect(spectator.query('p')).toBeTruthy(); + }); + + it('should have p tag with Body text', () => { + expect(spectator.query('p').textContent).toContain('Body'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-footer.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-footer.component.spec.ts new file mode 100644 index 0000000000..2b98479b9f --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-footer.component.spec.ts @@ -0,0 +1,46 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardFooterComponent } from '../components'; + +describe('AbpCardFooterComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(CardFooterComponent); + + beforeEach( + () => + (spectator = createHost( + ` +

Footer

+
`, + { + hostProps: { attributes: { autofocus: '', name: 'abp-card-footer' } }, + }, + )), + ); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-footer', () => { + expect(spectator.element.classList).toContain('card-footer'); + }); + + it('should have div', () => { + expect(spectator.query('div')).toBeTruthy(); + }); + + it('should have background-color red', () => { + expect((spectator.query('div') as HTMLElement).style.backgroundColor).toEqual('red'); + }); + + it('should have p tag', () => { + expect(spectator.query('p')).toBeTruthy(); + }); + + it('should have p tag with Footer text', () => { + expect((spectator.query('p') as HTMLElement).textContent).toContain('Footer'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-header.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-header.component.spec.ts new file mode 100644 index 0000000000..279cfe90bf --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-header.component.spec.ts @@ -0,0 +1,37 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardHeaderComponent } from '../components'; + +describe('AbpCardHeaderComponent', () => { + let spectator: SpectatorHost; + const createHost = createHostFactory(CardHeaderComponent); + + beforeEach( + () => + (spectator = createHost( + ` + Header + `, + { + hostProps: { attributes: { autofocus: '', name: 'abp-card-header' } }, + }, + )), + ); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-header', () => { + expect(spectator.element.classList).toContain('card-header'); + }); + + it('should have background-color red', () => { + expect((spectator.query('div') as HTMLElement).style.backgroundColor).toEqual('red'); + }); + + it('should have Header text', () => { + expect(spectator.element.textContent).toContain('Header'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-header.directive.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-header.directive.spec.ts new file mode 100644 index 0000000000..122de05ed8 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-header.directive.spec.ts @@ -0,0 +1,28 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardHeaderDirective } from '../components'; + +describe('AbpCardHeaderDirective', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(CardHeaderDirective); + + beforeEach( + () => + (spectator = createHost( + `
+
`, + { + hostProps: { attributes: { autofocus: '', name: 'abp-card-header' } }, + }, + )), + ); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-header', () => { + expect(spectator.element.classList).toContain('card-header'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-img-top.directive.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-img-top.directive.spec.ts new file mode 100644 index 0000000000..008d9a4528 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-img-top.directive.spec.ts @@ -0,0 +1,25 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardImgTopDirective } from '../components'; + +describe('AbpCardImgTopDirective', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(CardImgTopDirective); + + beforeEach( + () => + (spectator = createHost( + ``, + )), + ); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-img-top', () => { + expect(spectator.element.classList).toContain('card-img-top'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-subtitle.directive.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-subtitle.directive.spec.ts new file mode 100644 index 0000000000..004beaecae --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-subtitle.directive.spec.ts @@ -0,0 +1,22 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardSubtitleDirective } from '../components'; + +describe('AbpCardSubtitleDirective', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(CardSubtitleDirective); + + beforeEach(() => (spectator = createHost(`

CardSubtitle

`))); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-subtitle', () => { + expect(spectator.element.classList).toContain('card-subtitle'); + }); + + it('should have CardSubtitle text', () => { + expect(spectator.element.textContent).toContain('CardSubtitle'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card-title.directive.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-title.directive.spec.ts new file mode 100644 index 0000000000..9b9688f9e0 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card-title.directive.spec.ts @@ -0,0 +1,18 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { CardTitleDirective } from '../components'; + +describe('AbpCardTitleDirective', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(CardTitleDirective); + + beforeEach(() => (spectator = createHost(`
CardTitle
`))); + + it('should create an instance', () => { + expect(spectator).toBeTruthy(); + }); + + it('should have class card-title', () => { + expect(spectator.element.classList).toContain('card-title'); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/card.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/card.component.spec.ts new file mode 100644 index 0000000000..a5c8a5c43b --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/card.component.spec.ts @@ -0,0 +1,75 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { + CardComponent, + CardBodyComponent, + CardFooterComponent, + CardHeaderComponent, + CardHeaderDirective, + CardTitleDirective, + CardImgTopDirective, + CardSubtitleDirective, +} from '../components/card'; + +describe('CardComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory({ + component: CardComponent, + declarations: [ + CardHeaderComponent, + CardTitleDirective, + CardSubtitleDirective, + CardBodyComponent, + CardImgTopDirective, + CardFooterComponent, + ], + }); + + beforeEach( + () => + (spectator = createHost( + ` + + + Card title +

Card subtitle

+
+ + +

Some quick example text to build on the card title and make up the bulk of the card's content.

+
+ +
Go somewhere + + + `, + { + hostProps: { attributes: { autofocus: '', name: 'abp-card' } }, + }, + )), + ); + + it('should display the card-header', () => { + expect(spectator.query('abp-card-header')).toBeTruthy(); + }); + + it('should display the card-title', () => { + expect(spectator.query('abp-card-title')).toBeTruthy(); + }); + + it('should display the card-subtitle', () => { + expect(spectator.query('p[abp-card-subtitle]')).toBeTruthy(); + }); + + it('should display the card-body', () => { + expect(spectator.query('abp-card-body')).toBeTruthy(); + }); + + it('should display the card-img-top', () => { + expect(spectator.query('abp-card-img-top')).toBeTruthy(); + }); + + it('should display the card-footer', () => { + expect(spectator.query('abp-card-footer')).toBeTruthy(); + }); +}); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/checkbox.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/checkbox.component.spec.ts new file mode 100644 index 0000000000..e2fba6d0da --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/checkbox.component.spec.ts @@ -0,0 +1,44 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { FormCheckboxComponent } from '../components/checkbox/checkbox.component'; + +describe('FormCheckboxComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(FormCheckboxComponent); + + beforeEach( + () => + (spectator = createHost( + '', + { + hostProps: { attributes: { autofocus: '', name: 'abp-checkbox' } }, + }, + )), + ); + + it('should display the input', () => { + expect(spectator.query('input')).toBeTruthy(); + }); + + it('should equal the default classes to form-check-input', () => { + expect(spectator.query('input')).toHaveClass('form-check-input'); + }); + + it('should equal the default type to checkbox', () => { + expect(spectator.query('input')).toHaveAttribute('type', 'checkbox'); + }); + + it('should be readonly when checkboxReadonly is true', () => { + spectator.component.checkboxReadonly = true; + spectator.detectComponentChanges(); + expect(spectator.query('[readonly]')).toBeTruthy(); + }); + + it('should not contain readonly when checboxReadonly is false', () => { + spectator.component.checkboxReadonly = false; + spectator.detectComponentChanges(); + expect(spectator.query('[disabled]')).toBeFalsy(); + }); + +}); + diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/form-input.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/form-input.component.spec.ts new file mode 100644 index 0000000000..660cb72165 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/form-input.component.spec.ts @@ -0,0 +1,46 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { FormInputComponent } from '../components/form-input/form-input.component'; + + +describe('FormInputComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(FormInputComponent); + + beforeEach( + () => + (spectator = createHost( + '', + { + hostProps: { attributes: { autofocus: '', name: 'abp-form-input' } }, + }, + )), + ); + + it('should display the input', () => { + expect(spectator.query('input')).toBeTruthy(); + }); + + it('should equal the default classes to form-control', () => { + expect(spectator.query('input')).toHaveClass('form-control'); + }); + + it('should equal the default type to text', () => { + expect(spectator.query('input')).toHaveAttribute('type', 'text'); + }); + + it('should be readonly when inputReadonly is true', () => { + spectator.component.inputReadonly = true; + spectator.detectComponentChanges(); + expect(spectator.query('[readonly]')).toBeTruthy(); + }); + + it('should not contain readonly when inputReadonly is false', () => { + spectator.component.inputReadonly = false; + spectator.detectComponentChanges(); + expect(spectator.query('[disabled]')).toBeFalsy(); + }); + +}); + diff --git a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts index 20c7de13d4..0fea3f166c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts @@ -36,7 +36,10 @@ import { HTTP_ERROR_CONFIG, httpErrorConfigFactory } from './tokens/http-error.t import { DateParserFormatter } from './utils/date-parser-formatter'; import { CONFIRMATION_ICONS, DEFAULT_CONFIRMATION_ICONS } from './tokens/confirmation-icons.token'; import { PasswordComponent } from './components/password/password.component'; +import { CardModule } from './components/card/card.module'; import { AbpVisibleDirective } from './directives'; +import { FormInputComponent } from './components/form-input/form-input.component'; +import { FormCheckboxComponent } from './components/checkbox/checkbox.component'; const declarationsWithExports = [ BreadcrumbComponent, @@ -54,6 +57,8 @@ const declarationsWithExports = [ LoadingDirective, ModalCloseDirective, AbpVisibleDirective, + FormInputComponent, + FormCheckboxComponent ]; @NgModule({ @@ -63,12 +68,20 @@ const declarationsWithExports = [ NgxValidateCoreModule, NgbPaginationModule, EllipsisModule, + CardModule, + ], declarations: [...declarationsWithExports, HttpErrorWrapperComponent], - exports: [NgxDatatableModule, EllipsisModule, NgxValidateCoreModule, ...declarationsWithExports], + exports: [ + NgxDatatableModule, + EllipsisModule, + NgxValidateCoreModule, + CardModule, + ...declarationsWithExports + ], providers: [DatePipe], }) -export class BaseThemeSharedModule {} +export class BaseThemeSharedModule { } @NgModule({ imports: [BaseThemeSharedModule], diff --git a/npm/ng-packs/tsconfig.base.json b/npm/ng-packs/tsconfig.base.json index ac29fd53ad..71e32f80ed 100644 --- a/npm/ng-packs/tsconfig.base.json +++ b/npm/ng-packs/tsconfig.base.json @@ -30,6 +30,7 @@ "@abp/ng.identity": ["packages/identity/src/public-api.ts"], "@abp/ng.identity/config": ["packages/identity/config/src/public-api.ts"], "@abp/ng.identity/proxy": ["packages/identity/proxy/src/public-api.ts"], + "@abp/ng.oauth": ["packages/oauth/src/public-api.ts"], "@abp/ng.permission-management": ["packages/permission-management/src/public-api.ts"], "@abp/ng.permission-management/proxy": [ "packages/permission-management/proxy/src/public-api.ts" @@ -43,8 +44,7 @@ "@abp/ng.theme.basic/testing": ["packages/theme-basic/testing/src/public-api.ts"], "@abp/ng.theme.shared": ["packages/theme-shared/src/public-api.ts"], "@abp/ng.theme.shared/extensions": ["packages/theme-shared/extensions/src/public-api.ts"], - "@abp/ng.theme.shared/testing": ["packages/theme-shared/testing/src/public-api.ts"], - "@abp/ng.oauth": ["packages/oauth/src/public-api.ts"] + "@abp/ng.theme.shared/testing": ["packages/theme-shared/testing/src/public-api.ts"] } }, "exclude": ["node_modules", "tmp"] diff --git a/npm/packs/anchor-js/package.json b/npm/packs/anchor-js/package.json index 27ba6d883d..b396087bb6 100644 --- a/npm/packs/anchor-js/package.json +++ b/npm/packs/anchor-js/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/anchor-js", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "anchor-js": "^4.3.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/aspnetcore.components.server.basictheme/package.json b/npm/packs/aspnetcore.components.server.basictheme/package.json index 81175b9918..62f89d2654 100644 --- a/npm/packs/aspnetcore.components.server.basictheme/package.json +++ b/npm/packs/aspnetcore.components.server.basictheme/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/aspnetcore.components.server.basictheme", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/aspnetcore.components.server.theming": "~7.1.1" + "@abp/aspnetcore.components.server.theming": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/aspnetcore.components.server.theming/package.json b/npm/packs/aspnetcore.components.server.theming/package.json index ec3a349a56..254c55cee0 100644 --- a/npm/packs/aspnetcore.components.server.theming/package.json +++ b/npm/packs/aspnetcore.components.server.theming/package.json @@ -1,12 +1,12 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/aspnetcore.components.server.theming", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/bootstrap": "~7.1.1", - "@abp/font-awesome": "~7.1.1" + "@abp/bootstrap": "~7.2.0-rc.1", + "@abp/font-awesome": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/aspnetcore.mvc.ui.theme.basic/package.json b/npm/packs/aspnetcore.mvc.ui.theme.basic/package.json index 9e360d64ef..f6d00194cd 100644 --- a/npm/packs/aspnetcore.mvc.ui.theme.basic/package.json +++ b/npm/packs/aspnetcore.mvc.ui.theme.basic/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/aspnetcore.mvc.ui.theme.basic", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.shared": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.shared": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/aspnetcore.mvc.ui.theme.shared/package.json b/npm/packs/aspnetcore.mvc.ui.theme.shared/package.json index 1be5bf9432..8bb7ae182e 100644 --- a/npm/packs/aspnetcore.mvc.ui.theme.shared/package.json +++ b/npm/packs/aspnetcore.mvc.ui.theme.shared/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/aspnetcore.mvc.ui.theme.shared", "repository": { "type": "git", @@ -10,22 +10,22 @@ "access": "public" }, "dependencies": { - "@abp/aspnetcore.mvc.ui": "~7.1.1", - "@abp/bootstrap": "~7.1.1", - "@abp/bootstrap-datepicker": "~7.1.1", - "@abp/bootstrap-daterangepicker": "~7.1.1", - "@abp/datatables.net-bs5": "~7.1.1", - "@abp/font-awesome": "~7.1.1", - "@abp/jquery-form": "~7.1.1", - "@abp/jquery-validation-unobtrusive": "~7.1.1", - "@abp/lodash": "~7.1.1", - "@abp/luxon": "~7.1.1", - "@abp/malihu-custom-scrollbar-plugin": "~7.1.1", - "@abp/moment": "~7.1.1", - "@abp/select2": "~7.1.1", - "@abp/sweetalert2": "~7.1.1", - "@abp/timeago": "~7.1.1", - "@abp/toastr": "~7.1.1" + "@abp/aspnetcore.mvc.ui": "~7.2.0-rc.1", + "@abp/bootstrap": "~7.2.0-rc.1", + "@abp/bootstrap-datepicker": "~7.2.0-rc.1", + "@abp/bootstrap-daterangepicker": "~7.2.0-rc.1", + "@abp/datatables.net-bs5": "~7.2.0-rc.1", + "@abp/font-awesome": "~7.2.0-rc.1", + "@abp/jquery-form": "~7.2.0-rc.1", + "@abp/jquery-validation-unobtrusive": "~7.2.0-rc.1", + "@abp/lodash": "~7.2.0-rc.1", + "@abp/luxon": "~7.2.0-rc.1", + "@abp/malihu-custom-scrollbar-plugin": "~7.2.0-rc.1", + "@abp/moment": "~7.2.0-rc.1", + "@abp/select2": "~7.2.0-rc.1", + "@abp/sweetalert2": "~7.2.0-rc.1", + "@abp/timeago": "~7.2.0-rc.1", + "@abp/toastr": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/aspnetcore.mvc.ui/package-lock.json b/npm/packs/aspnetcore.mvc.ui/package-lock.json index 622466d103..cb532dc92b 100644 --- a/npm/packs/aspnetcore.mvc.ui/package-lock.json +++ b/npm/packs/aspnetcore.mvc.ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "@abp/aspnetcore.mvc.ui", - "version": "7.1.1", + "version": "7.2.0-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/npm/packs/aspnetcore.mvc.ui/package.json b/npm/packs/aspnetcore.mvc.ui/package.json index 1c0be4788d..f3136ecc06 100644 --- a/npm/packs/aspnetcore.mvc.ui/package.json +++ b/npm/packs/aspnetcore.mvc.ui/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/aspnetcore.mvc.ui", "repository": { "type": "git", diff --git a/npm/packs/blogging/package.json b/npm/packs/blogging/package.json index 641b231688..71fd312c24 100644 --- a/npm/packs/blogging/package.json +++ b/npm/packs/blogging/package.json @@ -1,14 +1,14 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/blogging", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.shared": "~7.1.1", - "@abp/owl.carousel": "~7.1.1", - "@abp/prismjs": "~7.1.1", - "@abp/tui-editor": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.shared": "~7.2.0-rc.1", + "@abp/owl.carousel": "~7.2.0-rc.1", + "@abp/prismjs": "~7.2.0-rc.1", + "@abp/tui-editor": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/bootstrap-datepicker/package.json b/npm/packs/bootstrap-datepicker/package.json index b48332a0b3..10baca334c 100644 --- a/npm/packs/bootstrap-datepicker/package.json +++ b/npm/packs/bootstrap-datepicker/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/bootstrap-datepicker", "repository": { "type": "git", diff --git a/npm/packs/bootstrap-daterangepicker/package.json b/npm/packs/bootstrap-daterangepicker/package.json index 5b74344e06..faa3df31de 100644 --- a/npm/packs/bootstrap-daterangepicker/package.json +++ b/npm/packs/bootstrap-daterangepicker/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/bootstrap-daterangepicker", "repository": { "type": "git", diff --git a/npm/packs/bootstrap/package.json b/npm/packs/bootstrap/package.json index 6f2a3cb4dd..e3b7658fb9 100644 --- a/npm/packs/bootstrap/package.json +++ b/npm/packs/bootstrap/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/bootstrap", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "bootstrap": "^5.1.3" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/chart.js/package.json b/npm/packs/chart.js/package.json index 55bf5e253c..63da2e8df7 100644 --- a/npm/packs/chart.js/package.json +++ b/npm/packs/chart.js/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/chart.js", "publishConfig": { "access": "public" diff --git a/npm/packs/clipboard/package.json b/npm/packs/clipboard/package.json index 18b874f5c8..24a9bfdc55 100644 --- a/npm/packs/clipboard/package.json +++ b/npm/packs/clipboard/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/clipboard", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "clipboard": "^2.0.8" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/cms-kit.admin/package.json b/npm/packs/cms-kit.admin/package.json index ad9ec270a0..ce07079d60 100644 --- a/npm/packs/cms-kit.admin/package.json +++ b/npm/packs/cms-kit.admin/package.json @@ -1,15 +1,15 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/cms-kit.admin", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/codemirror": "~7.1.1", - "@abp/jstree": "~7.1.1", - "@abp/slugify": "~7.1.1", - "@abp/tui-editor": "~7.1.1", - "@abp/uppy": "~7.1.1" + "@abp/codemirror": "~7.2.0-rc.1", + "@abp/jstree": "~7.2.0-rc.1", + "@abp/slugify": "~7.2.0-rc.1", + "@abp/tui-editor": "~7.2.0-rc.1", + "@abp/uppy": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/cms-kit.public/package.json b/npm/packs/cms-kit.public/package.json index bc53ebdb30..f0d85f436e 100644 --- a/npm/packs/cms-kit.public/package.json +++ b/npm/packs/cms-kit.public/package.json @@ -1,12 +1,12 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/cms-kit.public", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/highlight.js": "~7.1.1", - "@abp/star-rating-svg": "~7.1.1" + "@abp/highlight.js": "~7.2.0-rc.1", + "@abp/star-rating-svg": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/cms-kit/package.json b/npm/packs/cms-kit/package.json index b36fa850a3..f5820c7cd4 100644 --- a/npm/packs/cms-kit/package.json +++ b/npm/packs/cms-kit/package.json @@ -1,12 +1,12 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/cms-kit", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/cms-kit.admin": "~7.1.1", - "@abp/cms-kit.public": "~7.1.1" + "@abp/cms-kit.admin": "~7.2.0-rc.1", + "@abp/cms-kit.public": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/codemirror/package.json b/npm/packs/codemirror/package.json index f8d48dfe35..853b042435 100644 --- a/npm/packs/codemirror/package.json +++ b/npm/packs/codemirror/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/codemirror", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "codemirror": "^5.65.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/core/package.json b/npm/packs/core/package.json index d52d2ec19c..c600b5d802 100644 --- a/npm/packs/core/package.json +++ b/npm/packs/core/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/core", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/utils": "~7.1.1" + "@abp/utils": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/cropperjs/package.json b/npm/packs/cropperjs/package.json index c99dcdba69..ebefe2025b 100644 --- a/npm/packs/cropperjs/package.json +++ b/npm/packs/cropperjs/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/cropperjs", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "cropperjs": "^1.5.12" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/datatables.net-bs4/package.json b/npm/packs/datatables.net-bs4/package.json index 344760a74a..b02d15bfd0 100644 --- a/npm/packs/datatables.net-bs4/package.json +++ b/npm/packs/datatables.net-bs4/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/datatables.net-bs4", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/datatables.net": "~7.1.1", + "@abp/datatables.net": "~7.2.0-rc.1", "datatables.net-bs4": "^1.11.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/datatables.net-bs5/package.json b/npm/packs/datatables.net-bs5/package.json index 3b5f0a7e69..c957d45424 100644 --- a/npm/packs/datatables.net-bs5/package.json +++ b/npm/packs/datatables.net-bs5/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/datatables.net-bs5", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/datatables.net": "~7.1.1", + "@abp/datatables.net": "~7.2.0-rc.1", "datatables.net-bs5": "^1.11.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/datatables.net/package.json b/npm/packs/datatables.net/package.json index a108d1935f..dfb00d2f1f 100644 --- a/npm/packs/datatables.net/package.json +++ b/npm/packs/datatables.net/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/datatables.net", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "datatables.net": "^1.11.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/docs/package.json b/npm/packs/docs/package.json index 906e452b2e..bad11fff00 100644 --- a/npm/packs/docs/package.json +++ b/npm/packs/docs/package.json @@ -1,15 +1,15 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/docs", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/anchor-js": "~7.1.1", - "@abp/clipboard": "~7.1.1", - "@abp/malihu-custom-scrollbar-plugin": "~7.1.1", - "@abp/popper.js": "~7.1.1", - "@abp/prismjs": "~7.1.1" + "@abp/anchor-js": "~7.2.0-rc.1", + "@abp/clipboard": "~7.2.0-rc.1", + "@abp/malihu-custom-scrollbar-plugin": "~7.2.0-rc.1", + "@abp/popper.js": "~7.2.0-rc.1", + "@abp/prismjs": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/flag-icon-css/abp.resourcemapping.js b/npm/packs/flag-icon-css/abp.resourcemapping.js deleted file mode 100644 index 8c3ae431dd..0000000000 --- a/npm/packs/flag-icon-css/abp.resourcemapping.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - mappings: { - "@node_modules/flag-icon-css/css/*": "@libs/flag-icon-css/css", - "@node_modules/flag-icon-css/flags/1x1/*": "@libs/flag-icon-css/flags/1x1" - } -} \ No newline at end of file diff --git a/npm/packs/flag-icon-css/package.json b/npm/packs/flag-icon-css/package.json index fa7d50d540..9a1e2b6a8a 100644 --- a/npm/packs/flag-icon-css/package.json +++ b/npm/packs/flag-icon-css/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/flag-icon-css", "publishConfig": { "access": "public" diff --git a/npm/packs/flag-icons/abp.resourcemapping.js b/npm/packs/flag-icons/abp.resourcemapping.js new file mode 100644 index 0000000000..377a2aee6f --- /dev/null +++ b/npm/packs/flag-icons/abp.resourcemapping.js @@ -0,0 +1,6 @@ +module.exports = { + mappings: { + "@node_modules/flag-icons/css/*": "@libs/flag-icons/css", + "@node_modules/flag-icons/flags/1x1/*": "@libs/flag-icons/flags/1x1" + } +} \ No newline at end of file diff --git a/npm/packs/flag-icons/package.json b/npm/packs/flag-icons/package.json new file mode 100644 index 0000000000..d984a010d4 --- /dev/null +++ b/npm/packs/flag-icons/package.json @@ -0,0 +1,11 @@ +{ + "version": "7.2.0-rc.1", + "name": "@abp/flag-icons", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "flag-icons": "6.6.6" + }, + "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" +} diff --git a/npm/packs/font-awesome/package.json b/npm/packs/font-awesome/package.json index 0936117c00..a2b5f4600b 100644 --- a/npm/packs/font-awesome/package.json +++ b/npm/packs/font-awesome/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/font-awesome", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "@fortawesome/fontawesome-free": "^5.15.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/highlight.js/package.json b/npm/packs/highlight.js/package.json index ddc346f948..8376f5e405 100644 --- a/npm/packs/highlight.js/package.json +++ b/npm/packs/highlight.js/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/highlight.js", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "@highlightjs/cdn-assets": "~11.4.0" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/jquery-form/package.json b/npm/packs/jquery-form/package.json index d8134c8e54..e39357052b 100644 --- a/npm/packs/jquery-form/package.json +++ b/npm/packs/jquery-form/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/jquery-form", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "jquery-form": "^4.3.0" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/jquery-validation-unobtrusive/package.json b/npm/packs/jquery-validation-unobtrusive/package.json index a192b3cdd9..c9e5155672 100644 --- a/npm/packs/jquery-validation-unobtrusive/package.json +++ b/npm/packs/jquery-validation-unobtrusive/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/jquery-validation-unobtrusive", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/jquery-validation": "~7.1.1", + "@abp/jquery-validation": "~7.2.0-rc.1", "jquery-validation-unobtrusive": "^3.2.12" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/jquery-validation/package.json b/npm/packs/jquery-validation/package.json index 24b58bfe62..f32c63f73a 100644 --- a/npm/packs/jquery-validation/package.json +++ b/npm/packs/jquery-validation/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/jquery-validation", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "jquery-validation": "^1.19.3" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/jquery/package.json b/npm/packs/jquery/package.json index af77bb739a..6b7bd45c7e 100644 --- a/npm/packs/jquery/package.json +++ b/npm/packs/jquery/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/jquery", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "jquery": "~3.6.0" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/jstree/package.json b/npm/packs/jstree/package.json index 67f879d5f4..955d6cc97f 100644 --- a/npm/packs/jstree/package.json +++ b/npm/packs/jstree/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/jstree", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "jstree": "^3.3.12" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/lodash/package.json b/npm/packs/lodash/package.json index 536139af6c..9d6021dcab 100644 --- a/npm/packs/lodash/package.json +++ b/npm/packs/lodash/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/lodash", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "lodash": "^4.17.21" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/luxon/package.json b/npm/packs/luxon/package.json index 700051ba88..753dcbc0f8 100644 --- a/npm/packs/luxon/package.json +++ b/npm/packs/luxon/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/luxon", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "luxon": "^2.3.0" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/malihu-custom-scrollbar-plugin/package.json b/npm/packs/malihu-custom-scrollbar-plugin/package.json index d7bcedd184..b2066bedeb 100644 --- a/npm/packs/malihu-custom-scrollbar-plugin/package.json +++ b/npm/packs/malihu-custom-scrollbar-plugin/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/malihu-custom-scrollbar-plugin", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "malihu-custom-scrollbar-plugin": "^3.1.5" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/markdown-it/package.json b/npm/packs/markdown-it/package.json index a4038188ae..79f0e9a5bb 100644 --- a/npm/packs/markdown-it/package.json +++ b/npm/packs/markdown-it/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/markdown-it", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "markdown-it": "^12.3.2" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/moment/package.json b/npm/packs/moment/package.json index 4c90e3a41b..fa531c9072 100644 --- a/npm/packs/moment/package.json +++ b/npm/packs/moment/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/moment", "repository": { "type": "git", diff --git a/npm/packs/owl.carousel/package.json b/npm/packs/owl.carousel/package.json index cbae7bcb09..9b568ffd91 100644 --- a/npm/packs/owl.carousel/package.json +++ b/npm/packs/owl.carousel/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/owl.carousel", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "owl.carousel": "^2.3.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/popper.js/package.json b/npm/packs/popper.js/package.json index 5e68ca747b..43d820dc0f 100644 --- a/npm/packs/popper.js/package.json +++ b/npm/packs/popper.js/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/popper.js", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "@popperjs/core": "^2.11.2" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/prismjs/package.json b/npm/packs/prismjs/package.json index bd792c2652..4651d21cfa 100644 --- a/npm/packs/prismjs/package.json +++ b/npm/packs/prismjs/package.json @@ -1,12 +1,12 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/prismjs", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/clipboard": "~7.1.1", - "@abp/core": "~7.1.1", + "@abp/clipboard": "~7.2.0-rc.1", + "@abp/core": "~7.2.0-rc.1", "prismjs": "^1.26.0" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/qrcode/abp.resourcemapping.js b/npm/packs/qrcode/abp.resourcemapping.js new file mode 100644 index 0000000000..3758875205 --- /dev/null +++ b/npm/packs/qrcode/abp.resourcemapping.js @@ -0,0 +1,5 @@ +module.exports = { + mappings: { + "@node_modules/@abp/qrcode/src/*.*": "@libs/qrcode/" + } +} \ No newline at end of file diff --git a/npm/packs/qrcode/package.json b/npm/packs/qrcode/package.json new file mode 100644 index 0000000000..9a71fe67a0 --- /dev/null +++ b/npm/packs/qrcode/package.json @@ -0,0 +1,16 @@ +{ + "version": "7.2.0-rc.1", + "name": "@abp/qrcode", + "repository": { + "type": "git", + "url": "https://github.com/abpframework/abp.git", + "directory": "npm/packs/qrcode" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@abp/core": "~7.2.0-rc.1" + }, + "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" +} diff --git a/npm/packs/qrcode/src/qrcode.js b/npm/packs/qrcode/src/qrcode.js new file mode 100644 index 0000000000..5507c154ff --- /dev/null +++ b/npm/packs/qrcode/src/qrcode.js @@ -0,0 +1,614 @@ +/** + * @fileoverview + * - Using the 'QRCode for Javascript library' + * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. + * - this library has no dependencies. + * + * @author davidshimjs + * @see http://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ +var QRCode; + +(function () { + //--------------------------------------------------------------------- + // QRCode for JavaScript + // + // Copyright (c) 2009 Kazuhiko Arase + // + // URL: http://www.d-project.com/ + // + // Licensed under the MIT license: + // http://www.opensource.org/licenses/mit-license.php + // + // The word "QR Code" is registered trademark of + // DENSO WAVE INCORPORATED + // http://www.denso-wave.com/qrcode/faqpatent-e.html + // + //--------------------------------------------------------------------- + function QR8bitByte(data) { + this.mode = QRMode.MODE_8BIT_BYTE; + this.data = data; + this.parsedData = []; + + // Added to support UTF-8 Characters + for (var i = 0, l = this.data.length; i < l; i++) { + var byteArray = []; + var code = this.data.charCodeAt(i); + + if (code > 0x10000) { + byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18); + byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12); + byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[3] = 0x80 | (code & 0x3F); + } else if (code > 0x800) { + byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12); + byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6); + byteArray[2] = 0x80 | (code & 0x3F); + } else if (code > 0x80) { + byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6); + byteArray[1] = 0x80 | (code & 0x3F); + } else { + byteArray[0] = code; + } + + this.parsedData.push(byteArray); + } + + this.parsedData = Array.prototype.concat.apply([], this.parsedData); + + if (this.parsedData.length != this.data.length) { + this.parsedData.unshift(191); + this.parsedData.unshift(187); + this.parsedData.unshift(239); + } + } + + QR8bitByte.prototype = { + getLength: function (buffer) { + return this.parsedData.length; + }, + write: function (buffer) { + for (var i = 0, l = this.parsedData.length; i < l; i++) { + buffer.put(this.parsedData[i], 8); + } + } + }; + + function QRCodeModel(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber; + this.errorCorrectLevel = errorCorrectLevel; + this.modules = null; + this.moduleCount = 0; + this.dataCache = null; + this.dataList = []; + } + + QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);} + return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row=7){this.setupTypeNumber(test);} + if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);} + this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}} + return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;} + for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}} + for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}} + this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex>>bitIndex)&1)==1);} + var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;} + this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}} + row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;itotalDataCount*8){throw new Error("code length overflow. (" + +buffer.getLengthInBits() + +">" + +totalDataCount*8 + +")");} + if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);} + while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);} + while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;} + buffer.put(QRCodeModel.PAD1,8);} + return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r=0)?modPoly.get(modIndex):0;}} + var totalCodeCount=0;for(var i=0;i=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));} + return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));} + return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;} + return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i5){lostPoint+=(3+sameCount-5);}}} + for(var row=0;row=256){n-=255;} + return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);} + if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));} + this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]]; + + function _isSupportCanvas() { + return typeof CanvasRenderingContext2D != "undefined"; + } + + // android 2.x doesn't support Data-URI spec + function _getAndroid() { + var android = false; + var sAgent = navigator.userAgent; + + if (/android/i.test(sAgent)) { // android + android = true; + var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i); + + if (aMat && aMat[1]) { + android = parseFloat(aMat[1]); + } + } + + return android; + } + + var svgDrawer = (function() { + + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + + this.clear(); + + function makeSVG(tag, attrs) { + var el = document.createElementNS('http://www.w3.org/2000/svg', tag); + for (var k in attrs) + if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]); + return el; + } + + var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight}); + svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); + _el.appendChild(svg); + + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorLight, "width": "100%", "height": "100%"})); + svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"})); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + if (oQRCode.isDark(row, col)) { + var child = makeSVG("use", {"x": String(col), "y": String(row)}); + child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template") + svg.appendChild(child); + } + } + } + }; + Drawing.prototype.clear = function () { + while (this._el.hasChildNodes()) + this._el.removeChild(this._el.lastChild); + }; + return Drawing; + })(); + + var useSVG = document.documentElement.tagName.toLowerCase() === "svg"; + + // Drawing in DOM by using Table tag + var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () { + var Drawing = function (el, htOption) { + this._el = el; + this._htOption = htOption; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _htOption = this._htOption; + var _el = this._el; + var nCount = oQRCode.getModuleCount(); + var nWidth = Math.floor(_htOption.width / nCount); + var nHeight = Math.floor(_htOption.height / nCount); + var aHTML = ['']; + + for (var row = 0; row < nCount; row++) { + aHTML.push(''); + + for (var col = 0; col < nCount; col++) { + aHTML.push(''); + } + + aHTML.push(''); + } + + aHTML.push('
'); + _el.innerHTML = aHTML.join(''); + + // Fix the margin values as real size. + var elTable = _el.childNodes[0]; + var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2; + var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2; + + if (nLeftMarginTable > 0 && nTopMarginTable > 0) { + elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px"; + } + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._el.innerHTML = ''; + }; + + return Drawing; + })() : (function () { // Drawing in Canvas + function _onMakeImage() { + this._elImage.src = this._elCanvas.toDataURL("image/png"); + this._elImage.style.display = "block"; + this._elCanvas.style.display = "none"; + } + + // Android 2.1 bug workaround + // http://code.google.com/p/android/issues/detail?id=5141 + if (this._android && this._android <= 2.1) { + var factor = 1 / window.devicePixelRatio; + var drawImage = CanvasRenderingContext2D.prototype.drawImage; + CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) { + if (("nodeName" in image) && /img/i.test(image.nodeName)) { + for (var i = arguments.length - 1; i >= 1; i--) { + arguments[i] = arguments[i] * factor; + } + } else if (typeof dw == "undefined") { + arguments[1] *= factor; + arguments[2] *= factor; + arguments[3] *= factor; + arguments[4] *= factor; + } + + drawImage.apply(this, arguments); + }; + } + + /** + * Check whether the user's browser supports Data URI or not + * + * @private + * @param {Function} fSuccess Occurs if it supports Data URI + * @param {Function} fFail Occurs if it doesn't support Data URI + */ + function _safeSetDataURI(fSuccess, fFail) { + var self = this; + self._fFail = fFail; + self._fSuccess = fSuccess; + + // Check it just once + if (self._bSupportDataURI === null) { + var el = document.createElement("img"); + var fOnError = function() { + self._bSupportDataURI = false; + + if (self._fFail) { + self._fFail.call(self); + } + }; + var fOnSuccess = function() { + self._bSupportDataURI = true; + + if (self._fSuccess) { + self._fSuccess.call(self); + } + }; + + el.onabort = fOnError; + el.onerror = fOnError; + el.onload = fOnSuccess; + el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data. + return; + } else if (self._bSupportDataURI === true && self._fSuccess) { + self._fSuccess.call(self); + } else if (self._bSupportDataURI === false && self._fFail) { + self._fFail.call(self); + } + }; + + /** + * Drawing QRCode by using canvas + * + * @constructor + * @param {HTMLElement} el + * @param {Object} htOption QRCode Options + */ + var Drawing = function (el, htOption) { + this._bIsPainted = false; + this._android = _getAndroid(); + + this._htOption = htOption; + this._elCanvas = document.createElement("canvas"); + this._elCanvas.width = htOption.width; + this._elCanvas.height = htOption.height; + el.appendChild(this._elCanvas); + this._el = el; + this._oContext = this._elCanvas.getContext("2d"); + this._bIsPainted = false; + this._elImage = document.createElement("img"); + this._elImage.alt = "Scan me!"; + this._elImage.style.display = "none"; + this._el.appendChild(this._elImage); + this._bSupportDataURI = null; + }; + + /** + * Draw the QRCode + * + * @param {QRCode} oQRCode + */ + Drawing.prototype.draw = function (oQRCode) { + var _elImage = this._elImage; + var _oContext = this._oContext; + var _htOption = this._htOption; + + var nCount = oQRCode.getModuleCount(); + var nWidth = _htOption.width / nCount; + var nHeight = _htOption.height / nCount; + var nRoundedWidth = Math.round(nWidth); + var nRoundedHeight = Math.round(nHeight); + + _elImage.style.display = "none"; + this.clear(); + + for (var row = 0; row < nCount; row++) { + for (var col = 0; col < nCount; col++) { + var bIsDark = oQRCode.isDark(row, col); + var nLeft = col * nWidth; + var nTop = row * nHeight; + _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.lineWidth = 1; + _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight; + _oContext.fillRect(nLeft, nTop, nWidth, nHeight); + + // 안티 앨리어싱 방지 처리 + _oContext.strokeRect( + Math.floor(nLeft) + 0.5, + Math.floor(nTop) + 0.5, + nRoundedWidth, + nRoundedHeight + ); + + _oContext.strokeRect( + Math.ceil(nLeft) - 0.5, + Math.ceil(nTop) - 0.5, + nRoundedWidth, + nRoundedHeight + ); + } + } + + this._bIsPainted = true; + }; + + /** + * Make the image from Canvas if the browser supports Data URI. + */ + Drawing.prototype.makeImage = function () { + if (this._bIsPainted) { + _safeSetDataURI.call(this, _onMakeImage); + } + }; + + /** + * Return whether the QRCode is painted or not + * + * @return {Boolean} + */ + Drawing.prototype.isPainted = function () { + return this._bIsPainted; + }; + + /** + * Clear the QRCode + */ + Drawing.prototype.clear = function () { + this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height); + this._bIsPainted = false; + }; + + /** + * @private + * @param {Number} nNumber + */ + Drawing.prototype.round = function (nNumber) { + if (!nNumber) { + return nNumber; + } + + return Math.floor(nNumber * 1000) / 1000; + }; + + return Drawing; + })(); + + /** + * Get the type by string length + * + * @private + * @param {String} sText + * @param {Number} nCorrectLevel + * @return {Number} type + */ + function _getTypeNumber(sText, nCorrectLevel) { + var nType = 1; + var length = _getUTF8Length(sText); + + for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { + var nLimit = 0; + + switch (nCorrectLevel) { + case QRErrorCorrectLevel.L : + nLimit = QRCodeLimitLength[i][0]; + break; + case QRErrorCorrectLevel.M : + nLimit = QRCodeLimitLength[i][1]; + break; + case QRErrorCorrectLevel.Q : + nLimit = QRCodeLimitLength[i][2]; + break; + case QRErrorCorrectLevel.H : + nLimit = QRCodeLimitLength[i][3]; + break; + } + + if (length <= nLimit) { + break; + } else { + nType++; + } + } + + if (nType > QRCodeLimitLength.length) { + throw new Error("Too long data"); + } + + return nType; + } + + function _getUTF8Length(sText) { + var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a'); + return replacedText.length + (replacedText.length != sText ? 3 : 0); + } + + /** + * @class QRCode + * @constructor + * @example + * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); + * + * @example + * var oQRCode = new QRCode("test", { + * text : "http://naver.com", + * width : 128, + * height : 128 + * }); + * + * oQRCode.clear(); // Clear the QRCode. + * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. + * + * @param {HTMLElement|String} el target element or 'id' attribute of element. + * @param {Object|String} vOption + * @param {String} vOption.text QRCode link data + * @param {Number} [vOption.width=256] + * @param {Number} [vOption.height=256] + * @param {String} [vOption.colorDark="#000000"] + * @param {String} [vOption.colorLight="#ffffff"] + * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] + */ + QRCode = function (el, vOption) { + this._htOption = { + width : 256, + height : 256, + typeNumber : 4, + colorDark : "#000000", + colorLight : "#ffffff", + correctLevel : QRErrorCorrectLevel.H + }; + + if (typeof vOption === 'string') { + vOption = { + text : vOption + }; + } + + // Overwrites options + if (vOption) { + for (var i in vOption) { + this._htOption[i] = vOption[i]; + } + } + + if (typeof el == "string") { + el = document.getElementById(el); + } + + if (this._htOption.useSVG) { + Drawing = svgDrawer; + } + + this._android = _getAndroid(); + this._el = el; + this._oQRCode = null; + this._oDrawing = new Drawing(this._el, this._htOption); + + if (this._htOption.text) { + this.makeCode(this._htOption.text); + } + }; + + /** + * Make the QRCode + * + * @param {String} sText link data + */ + QRCode.prototype.makeCode = function (sText) { + this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel); + this._oQRCode.addData(sText); + this._oQRCode.make(); + this._el.title = sText; + this._oDrawing.draw(this._oQRCode); + this.makeImage(); + }; + + /** + * Make the Image from Canvas element + * - It occurs automatically + * - Android below 3 doesn't support Data-URI spec. + * + * @private + */ + QRCode.prototype.makeImage = function () { + if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) { + this._oDrawing.makeImage(); + } + }; + + /** + * Clear the QRCode + */ + QRCode.prototype.clear = function () { + this._oDrawing.clear(); + }; + + /** + * @name QRCode.CorrectLevel + */ + QRCode.CorrectLevel = QRErrorCorrectLevel; +})(); diff --git a/npm/packs/qrcode/src/qrcode.min.js b/npm/packs/qrcode/src/qrcode.min.js new file mode 100644 index 0000000000..993e88f396 --- /dev/null +++ b/npm/packs/qrcode/src/qrcode.min.js @@ -0,0 +1 @@ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file diff --git a/npm/packs/select2/package.json b/npm/packs/select2/package.json index 321c0a396c..16a563a54d 100644 --- a/npm/packs/select2/package.json +++ b/npm/packs/select2/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/select2", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "select2": "^4.0.13" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/signalr/package.json b/npm/packs/signalr/package.json index 466f5caed6..67d72ceaff 100644 --- a/npm/packs/signalr/package.json +++ b/npm/packs/signalr/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/signalr", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "@microsoft/signalr": "~6.0.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/slugify/package.json b/npm/packs/slugify/package.json index 2d03fe344a..4540d98e7f 100644 --- a/npm/packs/slugify/package.json +++ b/npm/packs/slugify/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/slugify", "publishConfig": { "access": "public" diff --git a/npm/packs/star-rating-svg/package.json b/npm/packs/star-rating-svg/package.json index a87f44169e..e6c7e826f1 100644 --- a/npm/packs/star-rating-svg/package.json +++ b/npm/packs/star-rating-svg/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/star-rating-svg", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "star-rating-svg": "^3.5.0" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/sweetalert2/package.json b/npm/packs/sweetalert2/package.json index 988772a888..590ef61b59 100644 --- a/npm/packs/sweetalert2/package.json +++ b/npm/packs/sweetalert2/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/sweetalert2", "publishConfig": { "access": "public" @@ -10,7 +10,7 @@ "directory": "npm/packs/sweetalert2" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "sweetalert2": "^11.3.6" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/timeago/package.json b/npm/packs/timeago/package.json index 9c389abd02..219afc13d4 100644 --- a/npm/packs/timeago/package.json +++ b/npm/packs/timeago/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/timeago", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "timeago": "^1.6.7" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/toastr/package.json b/npm/packs/toastr/package.json index 1766b7446f..f8563b9b62 100644 --- a/npm/packs/toastr/package.json +++ b/npm/packs/toastr/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/toastr", "repository": { "type": "git", @@ -10,7 +10,7 @@ "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", + "@abp/jquery": "~7.2.0-rc.1", "toastr": "^2.1.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/tui-editor/package.json b/npm/packs/tui-editor/package.json index e68b17ab24..cc2fa8679e 100644 --- a/npm/packs/tui-editor/package.json +++ b/npm/packs/tui-editor/package.json @@ -1,12 +1,12 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/tui-editor", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/jquery": "~7.1.1", - "@abp/prismjs": "~7.1.1" + "@abp/jquery": "~7.2.0-rc.1", + "@abp/prismjs": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/uppy/package.json b/npm/packs/uppy/package.json index 8c038ca99f..467765c632 100644 --- a/npm/packs/uppy/package.json +++ b/npm/packs/uppy/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/uppy", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/core": "~7.1.1", + "@abp/core": "~7.2.0-rc.1", "uppy": "^1.16.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/utils/package.json b/npm/packs/utils/package.json index 4df6a565e4..b93cc7bdf8 100644 --- a/npm/packs/utils/package.json +++ b/npm/packs/utils/package.json @@ -1,6 +1,6 @@ { "name": "@abp/utils", - "version": "7.1.1", + "version": "7.2.0-rc.1", "scripts": { "prepublishOnly": "yarn install --ignore-scripts && node prepublish.js", "ng": "ng", diff --git a/npm/packs/vee-validate/package.json b/npm/packs/vee-validate/package.json index 03e68df0b4..d2b1df6648 100644 --- a/npm/packs/vee-validate/package.json +++ b/npm/packs/vee-validate/package.json @@ -1,11 +1,11 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/vee-validate", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/vue": "~7.1.1", + "@abp/vue": "~7.2.0-rc.1", "vee-validate": "~3.4.4" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" diff --git a/npm/packs/virtual-file-explorer/package.json b/npm/packs/virtual-file-explorer/package.json index f007b3a928..3d578d8d3f 100644 --- a/npm/packs/virtual-file-explorer/package.json +++ b/npm/packs/virtual-file-explorer/package.json @@ -1,12 +1,12 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/virtual-file-explorer", "publishConfig": { "access": "public" }, "dependencies": { - "@abp/clipboard": "~7.1.1", - "@abp/prismjs": "~7.1.1" + "@abp/clipboard": "~7.2.0-rc.1", + "@abp/prismjs": "~7.2.0-rc.1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/vue/package.json b/npm/packs/vue/package.json index 7353dd5303..4ab5b57f2f 100644 --- a/npm/packs/vue/package.json +++ b/npm/packs/vue/package.json @@ -1,5 +1,5 @@ { - "version": "7.1.1", + "version": "7.2.0-rc.1", "name": "@abp/vue", "publishConfig": { "access": "public" diff --git a/nupkg/pack.ps1 b/nupkg/pack.ps1 index 316f7d777f..4c45e9e8c3 100644 --- a/nupkg/pack.ps1 +++ b/nupkg/pack.ps1 @@ -24,8 +24,7 @@ foreach($project in $projects) { Set-Location $projectFolder #dotnet clean - dotnet pack -c Release --no-build - + dotnet pack -c Release --no-build -- /maxcpucount if (-Not $?) { Write-Error "Packaging failed for the project: $projectName" diff --git a/source-code/Volo.Abp.Account.SourceCode/Volo.Abp.Account.SourceCode.zip b/source-code/Volo.Abp.Account.SourceCode/Volo.Abp.Account.SourceCode.zip index b20c5a2189..98f9486d66 100644 Binary files a/source-code/Volo.Abp.Account.SourceCode/Volo.Abp.Account.SourceCode.zip and b/source-code/Volo.Abp.Account.SourceCode/Volo.Abp.Account.SourceCode.zip differ diff --git a/source-code/Volo.Abp.AuditLogging.SourceCode/FodyWeavers.xml b/source-code/Volo.Abp.AuditLogging.SourceCode/FodyWeavers.xml new file mode 100644 index 0000000000..00e1d9a1c1 --- /dev/null +++ b/source-code/Volo.Abp.AuditLogging.SourceCode/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/source-code/Volo.Abp.AuditLogging.SourceCode/FodyWeavers.xsd b/source-code/Volo.Abp.AuditLogging.SourceCode/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/source-code/Volo.Abp.AuditLogging.SourceCode/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/source-code/Volo.Abp.AuditLogging.SourceCode/Volo.Abp.AuditLogging.SourceCode.zip b/source-code/Volo.Abp.AuditLogging.SourceCode/Volo.Abp.AuditLogging.SourceCode.zip index 4cbf9ac4ff..59d3026349 100644 Binary files a/source-code/Volo.Abp.AuditLogging.SourceCode/Volo.Abp.AuditLogging.SourceCode.zip and b/source-code/Volo.Abp.AuditLogging.SourceCode/Volo.Abp.AuditLogging.SourceCode.zip differ diff --git a/source-code/Volo.Abp.BackgroundJobs.SourceCode/Volo.Abp.BackgroundJobs.SourceCode.zip b/source-code/Volo.Abp.BackgroundJobs.SourceCode/Volo.Abp.BackgroundJobs.SourceCode.zip index 23a2d6badd..94ee51d1db 100644 Binary files a/source-code/Volo.Abp.BackgroundJobs.SourceCode/Volo.Abp.BackgroundJobs.SourceCode.zip and b/source-code/Volo.Abp.BackgroundJobs.SourceCode/Volo.Abp.BackgroundJobs.SourceCode.zip differ diff --git a/source-code/Volo.Abp.BasicTheme.SourceCode/Volo.Abp.BasicTheme.SourceCode.zip b/source-code/Volo.Abp.BasicTheme.SourceCode/Volo.Abp.BasicTheme.SourceCode.zip index c00fa0f2b8..26c1f518d5 100644 Binary files a/source-code/Volo.Abp.BasicTheme.SourceCode/Volo.Abp.BasicTheme.SourceCode.zip and b/source-code/Volo.Abp.BasicTheme.SourceCode/Volo.Abp.BasicTheme.SourceCode.zip differ diff --git a/source-code/Volo.Abp.BlobStoring.Database.SourceCode/Volo.Abp.BlobStoring.Database.SourceCode.zip b/source-code/Volo.Abp.BlobStoring.Database.SourceCode/Volo.Abp.BlobStoring.Database.SourceCode.zip index 032724e465..ff0e61ca5e 100644 Binary files a/source-code/Volo.Abp.BlobStoring.Database.SourceCode/Volo.Abp.BlobStoring.Database.SourceCode.zip and b/source-code/Volo.Abp.BlobStoring.Database.SourceCode/Volo.Abp.BlobStoring.Database.SourceCode.zip differ diff --git a/source-code/Volo.Abp.FeatureManagement.SourceCode/Volo.Abp.FeatureManagement.SourceCode.zip b/source-code/Volo.Abp.FeatureManagement.SourceCode/Volo.Abp.FeatureManagement.SourceCode.zip index 48ef5b3422..e580f20873 100644 Binary files a/source-code/Volo.Abp.FeatureManagement.SourceCode/Volo.Abp.FeatureManagement.SourceCode.zip and b/source-code/Volo.Abp.FeatureManagement.SourceCode/Volo.Abp.FeatureManagement.SourceCode.zip differ diff --git a/source-code/Volo.Abp.Identity.SourceCode/Volo.Abp.Identity.SourceCode.zip b/source-code/Volo.Abp.Identity.SourceCode/Volo.Abp.Identity.SourceCode.zip index c48cdb333c..2c181ad03f 100644 Binary files a/source-code/Volo.Abp.Identity.SourceCode/Volo.Abp.Identity.SourceCode.zip and b/source-code/Volo.Abp.Identity.SourceCode/Volo.Abp.Identity.SourceCode.zip differ diff --git a/source-code/Volo.Abp.IdentityServer.SourceCode/Volo.Abp.IdentityServer.SourceCode.zip b/source-code/Volo.Abp.IdentityServer.SourceCode/Volo.Abp.IdentityServer.SourceCode.zip index e44e975181..b648b1849d 100644 Binary files a/source-code/Volo.Abp.IdentityServer.SourceCode/Volo.Abp.IdentityServer.SourceCode.zip and b/source-code/Volo.Abp.IdentityServer.SourceCode/Volo.Abp.IdentityServer.SourceCode.zip differ diff --git a/source-code/Volo.Abp.OpenIddict.SourceCode/Volo.Abp.OpenIddict.SourceCode.zip b/source-code/Volo.Abp.OpenIddict.SourceCode/Volo.Abp.OpenIddict.SourceCode.zip index 402cb27505..482d8f0ab2 100644 Binary files a/source-code/Volo.Abp.OpenIddict.SourceCode/Volo.Abp.OpenIddict.SourceCode.zip and b/source-code/Volo.Abp.OpenIddict.SourceCode/Volo.Abp.OpenIddict.SourceCode.zip differ diff --git a/source-code/Volo.Abp.PermissionManagement.SourceCode/Volo.Abp.PermissionManagement.SourceCode.zip b/source-code/Volo.Abp.PermissionManagement.SourceCode/Volo.Abp.PermissionManagement.SourceCode.zip index b44c560e64..f0c8c079ed 100644 Binary files a/source-code/Volo.Abp.PermissionManagement.SourceCode/Volo.Abp.PermissionManagement.SourceCode.zip and b/source-code/Volo.Abp.PermissionManagement.SourceCode/Volo.Abp.PermissionManagement.SourceCode.zip differ diff --git a/source-code/Volo.Abp.SettingManagement.SourceCode/Volo.Abp.SettingManagement.SourceCode.zip b/source-code/Volo.Abp.SettingManagement.SourceCode/Volo.Abp.SettingManagement.SourceCode.zip index 12666a8314..92a4cddb52 100644 Binary files a/source-code/Volo.Abp.SettingManagement.SourceCode/Volo.Abp.SettingManagement.SourceCode.zip and b/source-code/Volo.Abp.SettingManagement.SourceCode/Volo.Abp.SettingManagement.SourceCode.zip differ diff --git a/source-code/Volo.Abp.TenantManagement.SourceCode/Volo.Abp.TenantManagement.SourceCode.zip b/source-code/Volo.Abp.TenantManagement.SourceCode/Volo.Abp.TenantManagement.SourceCode.zip index 6afa6219db..f4a6c7bcb6 100644 Binary files a/source-code/Volo.Abp.TenantManagement.SourceCode/Volo.Abp.TenantManagement.SourceCode.zip and b/source-code/Volo.Abp.TenantManagement.SourceCode/Volo.Abp.TenantManagement.SourceCode.zip differ diff --git a/source-code/Volo.Abp.Users.SourceCode/Volo.Abp.Users.SourceCode.zip b/source-code/Volo.Abp.Users.SourceCode/Volo.Abp.Users.SourceCode.zip index 6ee9c21c76..7b3128d21a 100644 Binary files a/source-code/Volo.Abp.Users.SourceCode/Volo.Abp.Users.SourceCode.zip and b/source-code/Volo.Abp.Users.SourceCode/Volo.Abp.Users.SourceCode.zip differ diff --git a/source-code/Volo.Abp.VirtualFileExplorer.SourceCode/Volo.Abp.VirtualFileExplorer.SourceCode.zip b/source-code/Volo.Abp.VirtualFileExplorer.SourceCode/Volo.Abp.VirtualFileExplorer.SourceCode.zip index 5c6e8b8a97..d3b947be5a 100644 Binary files a/source-code/Volo.Abp.VirtualFileExplorer.SourceCode/Volo.Abp.VirtualFileExplorer.SourceCode.zip and b/source-code/Volo.Abp.VirtualFileExplorer.SourceCode/Volo.Abp.VirtualFileExplorer.SourceCode.zip differ diff --git a/source-code/Volo.Blogging.SourceCode/Volo.Blogging.SourceCode.zip b/source-code/Volo.Blogging.SourceCode/Volo.Blogging.SourceCode.zip index 79d4fd2c57..3a78964736 100644 Binary files a/source-code/Volo.Blogging.SourceCode/Volo.Blogging.SourceCode.zip and b/source-code/Volo.Blogging.SourceCode/Volo.Blogging.SourceCode.zip differ diff --git a/source-code/Volo.ClientSimulation.SourceCode/FodyWeavers.xml b/source-code/Volo.ClientSimulation.SourceCode/FodyWeavers.xml new file mode 100644 index 0000000000..00e1d9a1c1 --- /dev/null +++ b/source-code/Volo.ClientSimulation.SourceCode/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/source-code/Volo.ClientSimulation.SourceCode/FodyWeavers.xsd b/source-code/Volo.ClientSimulation.SourceCode/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/source-code/Volo.ClientSimulation.SourceCode/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/source-code/Volo.ClientSimulation.SourceCode/Volo.ClientSimulation.SourceCode.zip b/source-code/Volo.ClientSimulation.SourceCode/Volo.ClientSimulation.SourceCode.zip index 7adceb986b..daabd25fd2 100644 Binary files a/source-code/Volo.ClientSimulation.SourceCode/Volo.ClientSimulation.SourceCode.zip and b/source-code/Volo.ClientSimulation.SourceCode/Volo.ClientSimulation.SourceCode.zip differ diff --git a/source-code/Volo.CmsKit.SourceCode/Volo.CmsKit.SourceCode.zip b/source-code/Volo.CmsKit.SourceCode/Volo.CmsKit.SourceCode.zip index 087f68a6b7..4f5b4cc6f7 100644 Binary files a/source-code/Volo.CmsKit.SourceCode/Volo.CmsKit.SourceCode.zip and b/source-code/Volo.CmsKit.SourceCode/Volo.CmsKit.SourceCode.zip differ diff --git a/source-code/Volo.Docs.SourceCode/Volo.Docs.SourceCode.zip b/source-code/Volo.Docs.SourceCode/Volo.Docs.SourceCode.zip index 554adc9372..1bb0a4f107 100644 Binary files a/source-code/Volo.Docs.SourceCode/Volo.Docs.SourceCode.zip and b/source-code/Volo.Docs.SourceCode/Volo.Docs.SourceCode.zip differ diff --git a/templates/app-nolayers/angular/package.json b/templates/app-nolayers/angular/package.json index 56e1d2c337..d6e4eeeb37 100644 --- a/templates/app-nolayers/angular/package.json +++ b/templates/app-nolayers/angular/package.json @@ -12,14 +12,14 @@ }, "private": true, "dependencies": { - "@abp/ng.account": "~7.1.1", - "@abp/ng.components": "~7.1.1", - "@abp/ng.core": "~7.1.1", - "@abp/ng.oauth": "~7.1.1", - "@abp/ng.identity": "~7.1.1", - "@abp/ng.setting-management": "~7.1.1", - "@abp/ng.tenant-management": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.account": "~7.2.0-rc.1", + "@abp/ng.components": "~7.2.0-rc.1", + "@abp/ng.core": "~7.2.0-rc.1", + "@abp/ng.oauth": "~7.2.0-rc.1", + "@abp/ng.identity": "~7.2.0-rc.1", + "@abp/ng.setting-management": "~7.2.0-rc.1", + "@abp/ng.tenant-management": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "@abp/ng.theme.lepton-x": "~2.1.0", "@angular/animations": "^15.0.1", "@angular/common": "^15.0.1", @@ -36,7 +36,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@abp/ng.schematics": "~7.1.1", + "@abp/ng.schematics": "~7.2.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/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20221220114435_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20230324070018_Initial.Designer.cs similarity index 98% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20221220114435_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20230324070018_Initial.Designer.cs index a1747ee5fa..6baa1f955f 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20221220114435_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20230324070018_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20221220114435_Initial")] + [Migration("20230324070018_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -717,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -765,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -827,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations 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") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20221220114435_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20230324070018_Initial.cs similarity index 97% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20221220114435_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20230324070018_Initial.cs index 90d52b8c31..f8e92f9d6b 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20221220114435_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20230324070018_Initial.cs @@ -292,6 +292,22 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations table.PrimaryKey("PK_AbpTenants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new @@ -315,7 +331,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -988,6 +1006,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations migrationBuilder.DropTable( name: "AbpUserClaims"); + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + migrationBuilder.DropTable( name: "AbpUserLogins"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs index c881e44e52..3115f987ef 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -714,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -762,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -824,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations 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") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20221205080257_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20221205080257_Initial.cs deleted file mode 100644 index cfed2777bd..0000000000 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20221205080257_Initial.cs +++ /dev/null @@ -1,1030 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace MyCompanyName.MyProjectName.Migrations -{ - /// - public partial class Initial : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "AbpAuditLogs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - UserId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ImpersonatorUserId = table.Column(type: "uniqueidentifier", nullable: true), - ImpersonatorUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ImpersonatorTenantId = table.Column(type: "uniqueidentifier", nullable: true), - ImpersonatorTenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ExecutionTime = table.Column(type: "datetime2", nullable: false), - ExecutionDuration = table.Column(type: "int", nullable: false), - ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - HttpMethod = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), - Url = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - Exceptions = table.Column(type: "nvarchar(max)", nullable: true), - Comments = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - HttpStatusCode = table.Column(type: "int", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpClaimTypes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - Required = table.Column(type: "bit", nullable: false), - IsStatic = table.Column(type: "bit", nullable: false), - Regex = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - RegexDescription = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ValueType = table.Column(type: "int", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpFeatureGroups", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatureGroups", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpFeatures", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - DefaultValue = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - IsVisibleToClients = table.Column(type: "bit", nullable: false), - IsAvailableToHost = table.Column(type: "bit", nullable: false), - AllowedProviders = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ValueType = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatures", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpFeatureValues", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Value = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpLinkUsers", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), - SourceTenantId = table.Column(type: "uniqueidentifier", nullable: true), - TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), - TargetTenantId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpLinkUsers", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpOrganizationUnits", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ParentId = table.Column(type: "uniqueidentifier", nullable: true), - Code = table.Column(type: "nvarchar(95)", maxLength: 95, nullable: false), - DisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpOrganizationUnits", x => x.Id); - table.ForeignKey( - name: "FK_AbpOrganizationUnits_AbpOrganizationUnits_ParentId", - column: x => x.ParentId, - principalTable: "AbpOrganizationUnits", - principalColumn: "Id"); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissionGrants", - 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), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissionGroups", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissions", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - IsEnabled = table.Column(type: "bit", nullable: false), - MultiTenancySide = table.Column(type: "tinyint", nullable: false), - Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissions", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpRoles", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - IsDefault = table.Column(type: "bit", nullable: false), - IsStatic = table.Column(type: "bit", nullable: false), - IsPublic = table.Column(type: "bit", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpRoles", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpSecurityLogs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - Identity = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - Action = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - UserId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpSettings", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Value = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: false), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpSettings", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpTenants", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpTenants", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpUsers", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - Surname = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - EmailConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), - PasswordHash = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - SecurityStamp = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - IsExternal = table.Column(type: "bit", nullable: false, defaultValue: false), - PhoneNumber = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), - PhoneNumberConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), - IsActive = table.Column(type: "bit", nullable: false), - TwoFactorEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), - LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), - LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), - AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUsers", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictApplications", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ClientId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), - ClientSecret = table.Column(type: "nvarchar(max)", nullable: true), - ConsentType = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - DisplayName = table.Column(type: "nvarchar(max)", nullable: true), - DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), - Permissions = table.Column(type: "nvarchar(max)", nullable: true), - PostLogoutRedirectUris = table.Column(type: "nvarchar(max)", nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - RedirectUris = table.Column(type: "nvarchar(max)", nullable: true), - Requirements = table.Column(type: "nvarchar(max)", nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - ClientUri = table.Column(type: "nvarchar(max)", nullable: true), - LogoUri = table.Column(type: "nvarchar(max)", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictApplications", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictScopes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Description = table.Column(type: "nvarchar(max)", nullable: true), - Descriptions = table.Column(type: "nvarchar(max)", nullable: true), - DisplayName = table.Column(type: "nvarchar(max)", nullable: true), - DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), - Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - Resources = table.Column(type: "nvarchar(max)", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictScopes", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpAuditLogActions", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), - ServiceName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - MethodName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - Parameters = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - ExecutionTime = table.Column(type: "datetime2", nullable: false), - ExecutionDuration = table.Column(type: "int", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpAuditLogActions", x => x.Id); - table.ForeignKey( - name: "FK_AbpAuditLogActions_AbpAuditLogs_AuditLogId", - column: x => x.AuditLogId, - principalTable: "AbpAuditLogs", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpEntityChanges", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ChangeTime = table.Column(type: "datetime2", nullable: false), - ChangeType = table.Column(type: "tinyint", nullable: false), - EntityTenantId = table.Column(type: "uniqueidentifier", nullable: true), - EntityId = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - EntityTypeFullName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); - table.ForeignKey( - name: "FK_AbpEntityChanges_AbpAuditLogs_AuditLogId", - column: x => x.AuditLogId, - principalTable: "AbpAuditLogs", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpOrganizationUnitRoles", - columns: table => new - { - RoleId = table.Column(type: "uniqueidentifier", nullable: false), - OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpOrganizationUnitRoles", x => new { x.OrganizationUnitId, x.RoleId }); - table.ForeignKey( - name: "FK_AbpOrganizationUnitRoles_AbpOrganizationUnits_OrganizationUnitId", - column: x => x.OrganizationUnitId, - principalTable: "AbpOrganizationUnits", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AbpOrganizationUnitRoles_AbpRoles_RoleId", - column: x => x.RoleId, - principalTable: "AbpRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpRoleClaims", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - RoleId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); - table.ForeignKey( - name: "FK_AbpRoleClaims_AbpRoles_RoleId", - column: x => x.RoleId, - principalTable: "AbpRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpTenantConnectionStrings", - columns: table => new - { - TenantId = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - Value = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpTenantConnectionStrings", x => new { x.TenantId, x.Name }); - table.ForeignKey( - name: "FK_AbpTenantConnectionStrings_AbpTenants_TenantId", - column: x => x.TenantId, - principalTable: "AbpTenants", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserClaims", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - UserId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserClaims", x => x.Id); - table.ForeignKey( - name: "FK_AbpUserClaims_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserLogins", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ProviderKey = table.Column(type: "nvarchar(196)", maxLength: 196, nullable: false), - ProviderDisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserLogins", x => new { x.UserId, x.LoginProvider }); - table.ForeignKey( - name: "FK_AbpUserLogins_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserOrganizationUnits", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserOrganizationUnits", x => new { x.OrganizationUnitId, x.UserId }); - table.ForeignKey( - name: "FK_AbpUserOrganizationUnits_AbpOrganizationUnits_OrganizationUnitId", - column: x => x.OrganizationUnitId, - principalTable: "AbpOrganizationUnits", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AbpUserOrganizationUnits_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserRoles", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - RoleId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserRoles", x => new { x.UserId, x.RoleId }); - table.ForeignKey( - name: "FK_AbpUserRoles_AbpRoles_RoleId", - column: x => x.RoleId, - principalTable: "AbpRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AbpUserRoles_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserTokens", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - Value = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); - table.ForeignKey( - name: "FK_AbpUserTokens_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictAuthorizations", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), - CreationDate = table.Column(type: "datetime2", nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - Scopes = table.Column(type: "nvarchar(max)", nullable: true), - Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictAuthorizations", x => x.Id); - table.ForeignKey( - name: "FK_OpenIddictAuthorizations_OpenIddictApplications_ApplicationId", - column: x => x.ApplicationId, - principalTable: "OpenIddictApplications", - principalColumn: "Id"); - }); - - migrationBuilder.CreateTable( - name: "AbpEntityPropertyChanges", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - EntityChangeId = table.Column(type: "uniqueidentifier", nullable: false), - NewValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - OriginalValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - PropertyName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - PropertyTypeFullName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); - table.ForeignKey( - name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", - column: x => x.EntityChangeId, - principalTable: "AbpEntityChanges", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictTokens", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), - AuthorizationId = table.Column(type: "uniqueidentifier", nullable: true), - CreationDate = table.Column(type: "datetime2", nullable: true), - ExpirationDate = table.Column(type: "datetime2", nullable: true), - Payload = table.Column(type: "nvarchar(max)", nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - RedemptionDate = table.Column(type: "datetime2", nullable: true), - ReferenceId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), - Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictTokens", x => x.Id); - table.ForeignKey( - name: "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId", - column: x => x.ApplicationId, - principalTable: "OpenIddictApplications", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId", - column: x => x.AuthorizationId, - principalTable: "OpenIddictAuthorizations", - principalColumn: "Id"); - }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogActions_AuditLogId", - table: "AbpAuditLogActions", - column: "AuditLogId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogActions_TenantId_ServiceName_MethodName_ExecutionTime", - table: "AbpAuditLogActions", - columns: new[] { "TenantId", "ServiceName", "MethodName", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogs_TenantId_ExecutionTime", - table: "AbpAuditLogs", - columns: new[] { "TenantId", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogs_TenantId_UserId_ExecutionTime", - table: "AbpAuditLogs", - columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityChanges_AuditLogId", - table: "AbpEntityChanges", - column: "AuditLogId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityChanges_TenantId_EntityTypeFullName_EntityId", - table: "AbpEntityChanges", - columns: new[] { "TenantId", "EntityTypeFullName", "EntityId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityPropertyChanges_EntityChangeId", - table: "AbpEntityPropertyChanges", - column: "EntityChangeId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatureGroups_Name", - table: "AbpFeatureGroups", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatures_GroupName", - table: "AbpFeatures", - column: "GroupName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatures_Name", - table: "AbpFeatures", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", - table: "AbpFeatureValues", - columns: new[] { "Name", "ProviderName", "ProviderKey" }, - unique: true, - filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpLinkUsers_SourceUserId_SourceTenantId_TargetUserId_TargetTenantId", - table: "AbpLinkUsers", - columns: new[] { "SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId" }, - unique: true, - filter: "[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", - table: "AbpOrganizationUnitRoles", - columns: new[] { "RoleId", "OrganizationUnitId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpOrganizationUnits_Code", - table: "AbpOrganizationUnits", - column: "Code"); - - migrationBuilder.CreateIndex( - name: "IX_AbpOrganizationUnits_ParentId", - table: "AbpOrganizationUnits", - column: "ParentId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissionGrants_TenantId_Name_ProviderName_ProviderKey", - table: "AbpPermissionGrants", - columns: new[] { "TenantId", "Name", "ProviderName", "ProviderKey" }, - unique: true, - filter: "[TenantId] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissionGroups_Name", - table: "AbpPermissionGroups", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissions_GroupName", - table: "AbpPermissions", - column: "GroupName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissions_Name", - table: "AbpPermissions", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpRoleClaims_RoleId", - table: "AbpRoleClaims", - column: "RoleId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpRoles_NormalizedName", - table: "AbpRoles", - column: "NormalizedName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_Action", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "Action" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_ApplicationName", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "ApplicationName" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_Identity", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "Identity" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_UserId", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "UserId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSettings_Name_ProviderName_ProviderKey", - table: "AbpSettings", - columns: new[] { "Name", "ProviderName", "ProviderKey" }, - unique: true, - filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpTenants_Name", - table: "AbpTenants", - column: "Name"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserClaims_UserId", - table: "AbpUserClaims", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserLogins_LoginProvider_ProviderKey", - table: "AbpUserLogins", - columns: new[] { "LoginProvider", "ProviderKey" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserOrganizationUnits_UserId_OrganizationUnitId", - table: "AbpUserOrganizationUnits", - columns: new[] { "UserId", "OrganizationUnitId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserRoles_RoleId_UserId", - table: "AbpUserRoles", - columns: new[] { "RoleId", "UserId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_Email", - table: "AbpUsers", - column: "Email"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_NormalizedEmail", - table: "AbpUsers", - column: "NormalizedEmail"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_NormalizedUserName", - table: "AbpUsers", - column: "NormalizedUserName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_UserName", - table: "AbpUsers", - column: "UserName"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictApplications_ClientId", - table: "OpenIddictApplications", - column: "ClientId"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type", - table: "OpenIddictAuthorizations", - columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictScopes_Name", - table: "OpenIddictScopes", - column: "Name"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type", - table: "OpenIddictTokens", - columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictTokens_AuthorizationId", - table: "OpenIddictTokens", - column: "AuthorizationId"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictTokens_ReferenceId", - table: "OpenIddictTokens", - column: "ReferenceId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AbpAuditLogActions"); - - migrationBuilder.DropTable( - name: "AbpClaimTypes"); - - migrationBuilder.DropTable( - name: "AbpEntityPropertyChanges"); - - migrationBuilder.DropTable( - name: "AbpFeatureGroups"); - - migrationBuilder.DropTable( - name: "AbpFeatures"); - - migrationBuilder.DropTable( - name: "AbpFeatureValues"); - - migrationBuilder.DropTable( - name: "AbpLinkUsers"); - - migrationBuilder.DropTable( - name: "AbpOrganizationUnitRoles"); - - migrationBuilder.DropTable( - name: "AbpPermissionGrants"); - - migrationBuilder.DropTable( - name: "AbpPermissionGroups"); - - migrationBuilder.DropTable( - name: "AbpPermissions"); - - migrationBuilder.DropTable( - name: "AbpRoleClaims"); - - migrationBuilder.DropTable( - name: "AbpSecurityLogs"); - - migrationBuilder.DropTable( - name: "AbpSettings"); - - migrationBuilder.DropTable( - name: "AbpTenantConnectionStrings"); - - migrationBuilder.DropTable( - name: "AbpUserClaims"); - - migrationBuilder.DropTable( - name: "AbpUserLogins"); - - migrationBuilder.DropTable( - name: "AbpUserOrganizationUnits"); - - migrationBuilder.DropTable( - name: "AbpUserRoles"); - - migrationBuilder.DropTable( - name: "AbpUserTokens"); - - migrationBuilder.DropTable( - name: "OpenIddictScopes"); - - migrationBuilder.DropTable( - name: "OpenIddictTokens"); - - migrationBuilder.DropTable( - name: "AbpEntityChanges"); - - migrationBuilder.DropTable( - name: "AbpTenants"); - - migrationBuilder.DropTable( - name: "AbpOrganizationUnits"); - - migrationBuilder.DropTable( - name: "AbpRoles"); - - migrationBuilder.DropTable( - name: "AbpUsers"); - - migrationBuilder.DropTable( - name: "OpenIddictAuthorizations"); - - migrationBuilder.DropTable( - name: "AbpAuditLogs"); - - migrationBuilder.DropTable( - name: "OpenIddictApplications"); - } - } -} diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20221205080257_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20230324070058_Initial.Designer.cs similarity index 97% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20221205080257_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20230324070058_Initial.Designer.cs index 81cbbcf0d0..0eba223650 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20221205080257_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20230324070058_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20221205080257_Initial")] + [Migration("20230324070058_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -497,6 +497,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -683,6 +686,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasDefaultValue(false) .HasColumnName("EmailConfirmed"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -711,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -759,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -821,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Migrations 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") @@ -961,6 +1000,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(128)") .HasColumnName("DisplayName"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1539,6 +1581,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20221220114625_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20230324070058_Initial.cs similarity index 97% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20221220114625_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20230324070058_Initial.cs index 75e2c5889d..3c62b40bf4 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20221220114625_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/20230324070058_Initial.cs @@ -292,6 +292,22 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpTenants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new @@ -315,7 +331,9 @@ namespace MyCompanyName.MyProjectName.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -988,6 +1006,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpUserClaims"); + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + migrationBuilder.DropTable( name: "AbpUserLogins"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs index d2becf58f5..60afa4e2c9 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -494,6 +494,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -680,6 +683,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasDefaultValue(false) .HasColumnName("EmailConfirmed"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -708,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -756,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -818,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Migrations 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") @@ -958,6 +997,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(128)") .HasColumnName("DisplayName"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1536,6 +1578,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220913013918_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220913013918_Initial.cs deleted file mode 100644 index d34c67552d..0000000000 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220913013918_Initial.cs +++ /dev/null @@ -1,1027 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace MyCompanyName.MyProjectName.Host.Migrations -{ - public partial class Initial : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "AbpAuditLogs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - UserId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ImpersonatorUserId = table.Column(type: "uniqueidentifier", nullable: true), - ImpersonatorUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ImpersonatorTenantId = table.Column(type: "uniqueidentifier", nullable: true), - ImpersonatorTenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ExecutionTime = table.Column(type: "datetime2", nullable: false), - ExecutionDuration = table.Column(type: "int", nullable: false), - ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - HttpMethod = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), - Url = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - Exceptions = table.Column(type: "nvarchar(max)", nullable: true), - Comments = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - HttpStatusCode = table.Column(type: "int", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpClaimTypes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - Required = table.Column(type: "bit", nullable: false), - IsStatic = table.Column(type: "bit", nullable: false), - Regex = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - RegexDescription = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ValueType = table.Column(type: "int", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpFeatureGroups", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatureGroups", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpFeatures", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - DefaultValue = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - IsVisibleToClients = table.Column(type: "bit", nullable: false), - IsAvailableToHost = table.Column(type: "bit", nullable: false), - AllowedProviders = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ValueType = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatures", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpFeatureValues", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Value = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpLinkUsers", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), - SourceTenantId = table.Column(type: "uniqueidentifier", nullable: true), - TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), - TargetTenantId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpLinkUsers", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpOrganizationUnits", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ParentId = table.Column(type: "uniqueidentifier", nullable: true), - Code = table.Column(type: "nvarchar(95)", maxLength: 95, nullable: false), - DisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpOrganizationUnits", x => x.Id); - table.ForeignKey( - name: "FK_AbpOrganizationUnits_AbpOrganizationUnits_ParentId", - column: x => x.ParentId, - principalTable: "AbpOrganizationUnits", - principalColumn: "Id"); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissionGrants", - 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), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissionGroups", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissions", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - IsEnabled = table.Column(type: "bit", nullable: false), - MultiTenancySide = table.Column(type: "tinyint", nullable: false), - Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissions", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpRoles", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - IsDefault = table.Column(type: "bit", nullable: false), - IsStatic = table.Column(type: "bit", nullable: false), - IsPublic = table.Column(type: "bit", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpRoles", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpSecurityLogs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - Identity = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - Action = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - UserId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpSettings", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Value = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: false), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpSettings", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpTenants", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpTenants", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpUsers", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - Surname = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - EmailConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), - PasswordHash = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - SecurityStamp = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - IsExternal = table.Column(type: "bit", nullable: false, defaultValue: false), - PhoneNumber = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), - PhoneNumberConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), - IsActive = table.Column(type: "bit", nullable: false), - TwoFactorEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), - LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), - LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), - AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUsers", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictApplications", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ClientId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), - ClientSecret = table.Column(type: "nvarchar(max)", nullable: true), - ConsentType = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - DisplayName = table.Column(type: "nvarchar(max)", nullable: true), - DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), - Permissions = table.Column(type: "nvarchar(max)", nullable: true), - PostLogoutRedirectUris = table.Column(type: "nvarchar(max)", nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - RedirectUris = table.Column(type: "nvarchar(max)", nullable: true), - Requirements = table.Column(type: "nvarchar(max)", nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - ClientUri = table.Column(type: "nvarchar(max)", nullable: true), - LogoUri = table.Column(type: "nvarchar(max)", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictApplications", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictScopes", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Description = table.Column(type: "nvarchar(max)", nullable: true), - Descriptions = table.Column(type: "nvarchar(max)", nullable: true), - DisplayName = table.Column(type: "nvarchar(max)", nullable: true), - DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), - Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - Resources = table.Column(type: "nvarchar(max)", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictScopes", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpAuditLogActions", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), - ServiceName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - MethodName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - Parameters = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - ExecutionTime = table.Column(type: "datetime2", nullable: false), - ExecutionDuration = table.Column(type: "int", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpAuditLogActions", x => x.Id); - table.ForeignKey( - name: "FK_AbpAuditLogActions_AbpAuditLogs_AuditLogId", - column: x => x.AuditLogId, - principalTable: "AbpAuditLogs", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpEntityChanges", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ChangeTime = table.Column(type: "datetime2", nullable: false), - ChangeType = table.Column(type: "tinyint", nullable: false), - EntityTenantId = table.Column(type: "uniqueidentifier", nullable: true), - EntityId = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - EntityTypeFullName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); - table.ForeignKey( - name: "FK_AbpEntityChanges_AbpAuditLogs_AuditLogId", - column: x => x.AuditLogId, - principalTable: "AbpAuditLogs", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpOrganizationUnitRoles", - columns: table => new - { - RoleId = table.Column(type: "uniqueidentifier", nullable: false), - OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpOrganizationUnitRoles", x => new { x.OrganizationUnitId, x.RoleId }); - table.ForeignKey( - name: "FK_AbpOrganizationUnitRoles_AbpOrganizationUnits_OrganizationUnitId", - column: x => x.OrganizationUnitId, - principalTable: "AbpOrganizationUnits", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AbpOrganizationUnitRoles_AbpRoles_RoleId", - column: x => x.RoleId, - principalTable: "AbpRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpRoleClaims", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - RoleId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); - table.ForeignKey( - name: "FK_AbpRoleClaims_AbpRoles_RoleId", - column: x => x.RoleId, - principalTable: "AbpRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpTenantConnectionStrings", - columns: table => new - { - TenantId = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - Value = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpTenantConnectionStrings", x => new { x.TenantId, x.Name }); - table.ForeignKey( - name: "FK_AbpTenantConnectionStrings_AbpTenants_TenantId", - column: x => x.TenantId, - principalTable: "AbpTenants", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserClaims", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - UserId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), - ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserClaims", x => x.Id); - table.ForeignKey( - name: "FK_AbpUserClaims_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserLogins", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ProviderKey = table.Column(type: "nvarchar(196)", maxLength: 196, nullable: false), - ProviderDisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserLogins", x => new { x.UserId, x.LoginProvider }); - table.ForeignKey( - name: "FK_AbpUserLogins_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserOrganizationUnits", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserOrganizationUnits", x => new { x.OrganizationUnitId, x.UserId }); - table.ForeignKey( - name: "FK_AbpUserOrganizationUnits_AbpOrganizationUnits_OrganizationUnitId", - column: x => x.OrganizationUnitId, - principalTable: "AbpOrganizationUnits", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AbpUserOrganizationUnits_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserRoles", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - RoleId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserRoles", x => new { x.UserId, x.RoleId }); - table.ForeignKey( - name: "FK_AbpUserRoles_AbpRoles_RoleId", - column: x => x.RoleId, - principalTable: "AbpRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AbpUserRoles_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpUserTokens", - columns: table => new - { - UserId = table.Column(type: "uniqueidentifier", nullable: false), - LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - Value = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); - table.ForeignKey( - name: "FK_AbpUserTokens_AbpUsers_UserId", - column: x => x.UserId, - principalTable: "AbpUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictAuthorizations", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), - CreationDate = table.Column(type: "datetime2", nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - Scopes = table.Column(type: "nvarchar(max)", nullable: true), - Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictAuthorizations", x => x.Id); - table.ForeignKey( - name: "FK_OpenIddictAuthorizations_OpenIddictApplications_ApplicationId", - column: x => x.ApplicationId, - principalTable: "OpenIddictApplications", - principalColumn: "Id"); - }); - - migrationBuilder.CreateTable( - name: "AbpEntityPropertyChanges", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - EntityChangeId = table.Column(type: "uniqueidentifier", nullable: false), - NewValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - OriginalValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - PropertyName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - PropertyTypeFullName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); - table.ForeignKey( - name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", - column: x => x.EntityChangeId, - principalTable: "AbpEntityChanges", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "OpenIddictTokens", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), - AuthorizationId = table.Column(type: "uniqueidentifier", nullable: true), - CreationDate = table.Column(type: "datetime2", nullable: true), - ExpirationDate = table.Column(type: "datetime2", nullable: true), - Payload = table.Column(type: "nvarchar(max)", nullable: true), - Properties = table.Column(type: "nvarchar(max)", nullable: true), - RedemptionDate = table.Column(type: "datetime2", nullable: true), - ReferenceId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), - Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), - Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), - CreationTime = table.Column(type: "datetime2", nullable: false), - CreatorId = table.Column(type: "uniqueidentifier", nullable: true), - LastModificationTime = table.Column(type: "datetime2", nullable: true), - LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), - IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), - DeleterId = table.Column(type: "uniqueidentifier", nullable: true), - DeletionTime = table.Column(type: "datetime2", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OpenIddictTokens", x => x.Id); - table.ForeignKey( - name: "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId", - column: x => x.ApplicationId, - principalTable: "OpenIddictApplications", - principalColumn: "Id"); - table.ForeignKey( - name: "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId", - column: x => x.AuthorizationId, - principalTable: "OpenIddictAuthorizations", - principalColumn: "Id"); - }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogActions_AuditLogId", - table: "AbpAuditLogActions", - column: "AuditLogId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogActions_TenantId_ServiceName_MethodName_ExecutionTime", - table: "AbpAuditLogActions", - columns: new[] { "TenantId", "ServiceName", "MethodName", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogs_TenantId_ExecutionTime", - table: "AbpAuditLogs", - columns: new[] { "TenantId", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogs_TenantId_UserId_ExecutionTime", - table: "AbpAuditLogs", - columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityChanges_AuditLogId", - table: "AbpEntityChanges", - column: "AuditLogId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityChanges_TenantId_EntityTypeFullName_EntityId", - table: "AbpEntityChanges", - columns: new[] { "TenantId", "EntityTypeFullName", "EntityId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityPropertyChanges_EntityChangeId", - table: "AbpEntityPropertyChanges", - column: "EntityChangeId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatureGroups_Name", - table: "AbpFeatureGroups", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatures_GroupName", - table: "AbpFeatures", - column: "GroupName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatures_Name", - table: "AbpFeatures", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", - table: "AbpFeatureValues", - columns: new[] { "Name", "ProviderName", "ProviderKey" }, - unique: true, - filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpLinkUsers_SourceUserId_SourceTenantId_TargetUserId_TargetTenantId", - table: "AbpLinkUsers", - columns: new[] { "SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId" }, - unique: true, - filter: "[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", - table: "AbpOrganizationUnitRoles", - columns: new[] { "RoleId", "OrganizationUnitId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpOrganizationUnits_Code", - table: "AbpOrganizationUnits", - column: "Code"); - - migrationBuilder.CreateIndex( - name: "IX_AbpOrganizationUnits_ParentId", - table: "AbpOrganizationUnits", - column: "ParentId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissionGrants_TenantId_Name_ProviderName_ProviderKey", - table: "AbpPermissionGrants", - columns: new[] { "TenantId", "Name", "ProviderName", "ProviderKey" }, - unique: true, - filter: "[TenantId] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissionGroups_Name", - table: "AbpPermissionGroups", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissions_GroupName", - table: "AbpPermissions", - column: "GroupName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissions_Name", - table: "AbpPermissions", - column: "Name", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AbpRoleClaims_RoleId", - table: "AbpRoleClaims", - column: "RoleId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpRoles_NormalizedName", - table: "AbpRoles", - column: "NormalizedName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_Action", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "Action" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_ApplicationName", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "ApplicationName" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_Identity", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "Identity" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSecurityLogs_TenantId_UserId", - table: "AbpSecurityLogs", - columns: new[] { "TenantId", "UserId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSettings_Name_ProviderName_ProviderKey", - table: "AbpSettings", - columns: new[] { "Name", "ProviderName", "ProviderKey" }, - unique: true, - filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); - - migrationBuilder.CreateIndex( - name: "IX_AbpTenants_Name", - table: "AbpTenants", - column: "Name"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserClaims_UserId", - table: "AbpUserClaims", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserLogins_LoginProvider_ProviderKey", - table: "AbpUserLogins", - columns: new[] { "LoginProvider", "ProviderKey" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserOrganizationUnits_UserId_OrganizationUnitId", - table: "AbpUserOrganizationUnits", - columns: new[] { "UserId", "OrganizationUnitId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpUserRoles_RoleId_UserId", - table: "AbpUserRoles", - columns: new[] { "RoleId", "UserId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_Email", - table: "AbpUsers", - column: "Email"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_NormalizedEmail", - table: "AbpUsers", - column: "NormalizedEmail"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_NormalizedUserName", - table: "AbpUsers", - column: "NormalizedUserName"); - - migrationBuilder.CreateIndex( - name: "IX_AbpUsers_UserName", - table: "AbpUsers", - column: "UserName"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictApplications_ClientId", - table: "OpenIddictApplications", - column: "ClientId"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type", - table: "OpenIddictAuthorizations", - columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictScopes_Name", - table: "OpenIddictScopes", - column: "Name"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type", - table: "OpenIddictTokens", - columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictTokens_AuthorizationId", - table: "OpenIddictTokens", - column: "AuthorizationId"); - - migrationBuilder.CreateIndex( - name: "IX_OpenIddictTokens_ReferenceId", - table: "OpenIddictTokens", - column: "ReferenceId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AbpAuditLogActions"); - - migrationBuilder.DropTable( - name: "AbpClaimTypes"); - - migrationBuilder.DropTable( - name: "AbpEntityPropertyChanges"); - - migrationBuilder.DropTable( - name: "AbpFeatureGroups"); - - migrationBuilder.DropTable( - name: "AbpFeatures"); - - migrationBuilder.DropTable( - name: "AbpFeatureValues"); - - migrationBuilder.DropTable( - name: "AbpLinkUsers"); - - migrationBuilder.DropTable( - name: "AbpOrganizationUnitRoles"); - - migrationBuilder.DropTable( - name: "AbpPermissionGrants"); - - migrationBuilder.DropTable( - name: "AbpPermissionGroups"); - - migrationBuilder.DropTable( - name: "AbpPermissions"); - - migrationBuilder.DropTable( - name: "AbpRoleClaims"); - - migrationBuilder.DropTable( - name: "AbpSecurityLogs"); - - migrationBuilder.DropTable( - name: "AbpSettings"); - - migrationBuilder.DropTable( - name: "AbpTenantConnectionStrings"); - - migrationBuilder.DropTable( - name: "AbpUserClaims"); - - migrationBuilder.DropTable( - name: "AbpUserLogins"); - - migrationBuilder.DropTable( - name: "AbpUserOrganizationUnits"); - - migrationBuilder.DropTable( - name: "AbpUserRoles"); - - migrationBuilder.DropTable( - name: "AbpUserTokens"); - - migrationBuilder.DropTable( - name: "OpenIddictScopes"); - - migrationBuilder.DropTable( - name: "OpenIddictTokens"); - - migrationBuilder.DropTable( - name: "AbpEntityChanges"); - - migrationBuilder.DropTable( - name: "AbpTenants"); - - migrationBuilder.DropTable( - name: "AbpOrganizationUnits"); - - migrationBuilder.DropTable( - name: "AbpRoles"); - - migrationBuilder.DropTable( - name: "AbpUsers"); - - migrationBuilder.DropTable( - name: "OpenIddictAuthorizations"); - - migrationBuilder.DropTable( - name: "AbpAuditLogs"); - - migrationBuilder.DropTable( - name: "OpenIddictApplications"); - } - } -} diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220913013918_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20230324070125_Initial.Designer.cs similarity index 97% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220913013918_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20230324070125_Initial.Designer.cs index bc2a256ed3..fe2d18ec1e 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220913013918_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20230324070125_Initial.Designer.cs @@ -13,18 +13,19 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Host.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220913013918_Initial")] + [Migration("20230324070125_Initial")] partial class Initial { + /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => { @@ -496,6 +497,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -682,6 +686,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasDefaultValue(false) .HasColumnName("EmailConfirmed"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -710,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -758,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -820,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Host.Migrations 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") @@ -960,6 +1000,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("nvarchar(128)") .HasColumnName("DisplayName"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1538,6 +1581,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20230324070125_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20230324070125_Initial.cs new file mode 100644 index 0000000000..7af7c9a871 --- /dev/null +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20230324070125_Initial.cs @@ -0,0 +1,1055 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyCompanyName.MyProjectName.Host.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpAuditLogs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + UserId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ImpersonatorUserId = table.Column(type: "uniqueidentifier", nullable: true), + ImpersonatorUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ImpersonatorTenantId = table.Column(type: "uniqueidentifier", nullable: true), + ImpersonatorTenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ExecutionTime = table.Column(type: "datetime2", nullable: false), + ExecutionDuration = table.Column(type: "int", nullable: false), + ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ClientName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + HttpMethod = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), + Url = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + Exceptions = table.Column(type: "nvarchar(max)", nullable: true), + Comments = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + HttpStatusCode = table.Column(type: "int", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpClaimTypes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Required = table.Column(type: "bit", nullable: false), + IsStatic = table.Column(type: "bit", nullable: false), + Regex = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + RegexDescription = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ValueType = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpFeatureGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatureGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpFeatures", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + DefaultValue = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + IsVisibleToClients = table.Column(type: "bit", nullable: false), + IsAvailableToHost = table.Column(type: "bit", nullable: false), + AllowedProviders = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ValueType = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatures", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpFeatureValues", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Value = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpLinkUsers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + SourceTenantId = table.Column(type: "uniqueidentifier", nullable: true), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetTenantId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpLinkUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpOrganizationUnits", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ParentId = table.Column(type: "uniqueidentifier", nullable: true), + Code = table.Column(type: "nvarchar(95)", maxLength: 95, nullable: false), + DisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpOrganizationUnits", x => x.Id); + table.ForeignKey( + name: "FK_AbpOrganizationUnits_AbpOrganizationUnits_ParentId", + column: x => x.ParentId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissionGrants", + 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), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpRoles", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsDefault = table.Column(type: "bit", nullable: false), + IsStatic = table.Column(type: "bit", nullable: false), + IsPublic = table.Column(type: "bit", nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + Identity = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + Action = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + UserId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpSettings", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Value = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: false), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSettings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpTenants", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpTenants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpUsers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + Surname = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + EmailConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), + PasswordHash = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + SecurityStamp = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsExternal = table.Column(type: "bit", nullable: false, defaultValue: false), + PhoneNumber = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), + PhoneNumberConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), + IsActive = table.Column(type: "bit", nullable: false), + TwoFactorEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), + LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), + LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), + AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictApplications", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ClientId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + ClientSecret = table.Column(type: "nvarchar(max)", nullable: true), + ConsentType = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + DisplayName = table.Column(type: "nvarchar(max)", nullable: true), + DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), + Permissions = table.Column(type: "nvarchar(max)", nullable: true), + PostLogoutRedirectUris = table.Column(type: "nvarchar(max)", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + RedirectUris = table.Column(type: "nvarchar(max)", nullable: true), + Requirements = table.Column(type: "nvarchar(max)", nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ClientUri = table.Column(type: "nvarchar(max)", nullable: true), + LogoUri = table.Column(type: "nvarchar(max)", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictApplications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictScopes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Description = table.Column(type: "nvarchar(max)", nullable: true), + Descriptions = table.Column(type: "nvarchar(max)", nullable: true), + DisplayName = table.Column(type: "nvarchar(max)", nullable: true), + DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + Resources = table.Column(type: "nvarchar(max)", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictScopes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpAuditLogActions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), + ServiceName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + MethodName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + Parameters = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + ExecutionTime = table.Column(type: "datetime2", nullable: false), + ExecutionDuration = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuditLogActions", x => x.Id); + table.ForeignKey( + name: "FK_AbpAuditLogActions_AbpAuditLogs_AuditLogId", + column: x => x.AuditLogId, + principalTable: "AbpAuditLogs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpEntityChanges", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ChangeTime = table.Column(type: "datetime2", nullable: false), + ChangeType = table.Column(type: "tinyint", nullable: false), + EntityTenantId = table.Column(type: "uniqueidentifier", nullable: true), + EntityId = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + EntityTypeFullName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); + table.ForeignKey( + name: "FK_AbpEntityChanges_AbpAuditLogs_AuditLogId", + column: x => x.AuditLogId, + principalTable: "AbpAuditLogs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpOrganizationUnitRoles", + columns: table => new + { + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpOrganizationUnitRoles", x => new { x.OrganizationUnitId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpOrganizationUnitRoles_AbpOrganizationUnits_OrganizationUnitId", + column: x => x.OrganizationUnitId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpOrganizationUnitRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpRoleClaims", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpRoleClaims_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpTenantConnectionStrings", + columns: table => new + { + TenantId = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + Value = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpTenantConnectionStrings", x => new { x.TenantId, x.Name }); + table.ForeignKey( + name: "FK_AbpTenantConnectionStrings_AbpTenants_TenantId", + column: x => x.TenantId, + principalTable: "AbpTenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserClaims", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpUserClaims_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserLogins", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ProviderKey = table.Column(type: "nvarchar(196)", maxLength: 196, nullable: false), + ProviderDisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserLogins", x => new { x.UserId, x.LoginProvider }); + table.ForeignKey( + name: "FK_AbpUserLogins_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserOrganizationUnits", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserOrganizationUnits", x => new { x.OrganizationUnitId, x.UserId }); + table.ForeignKey( + name: "FK_AbpUserOrganizationUnits_AbpOrganizationUnits_OrganizationUnitId", + column: x => x.OrganizationUnitId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserOrganizationUnits_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserRoles", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserTokens", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Value = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AbpUserTokens_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictAuthorizations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + Scopes = table.Column(type: "nvarchar(max)", nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictAuthorizations", x => x.Id); + table.ForeignKey( + name: "FK_OpenIddictAuthorizations_OpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "OpenIddictApplications", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "AbpEntityPropertyChanges", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + EntityChangeId = table.Column(type: "uniqueidentifier", nullable: false), + NewValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + OriginalValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + PropertyName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + PropertyTypeFullName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); + table.ForeignKey( + name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", + column: x => x.EntityChangeId, + principalTable: "AbpEntityChanges", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictTokens", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), + AuthorizationId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: true), + ExpirationDate = table.Column(type: "datetime2", nullable: true), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + RedemptionDate = table.Column(type: "datetime2", nullable: true), + ReferenceId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictTokens", x => x.Id); + table.ForeignKey( + name: "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "OpenIddictApplications", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId", + column: x => x.AuthorizationId, + principalTable: "OpenIddictAuthorizations", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogActions_AuditLogId", + table: "AbpAuditLogActions", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogActions_TenantId_ServiceName_MethodName_ExecutionTime", + table: "AbpAuditLogActions", + columns: new[] { "TenantId", "ServiceName", "MethodName", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogs_TenantId_ExecutionTime", + table: "AbpAuditLogs", + columns: new[] { "TenantId", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogs_TenantId_UserId_ExecutionTime", + table: "AbpAuditLogs", + columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityChanges_AuditLogId", + table: "AbpEntityChanges", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityChanges_TenantId_EntityTypeFullName_EntityId", + table: "AbpEntityChanges", + columns: new[] { "TenantId", "EntityTypeFullName", "EntityId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityPropertyChanges_EntityChangeId", + table: "AbpEntityPropertyChanges", + column: "EntityChangeId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatureGroups_Name", + table: "AbpFeatureGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatures_GroupName", + table: "AbpFeatures", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatures_Name", + table: "AbpFeatures", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", + table: "AbpFeatureValues", + columns: new[] { "Name", "ProviderName", "ProviderKey" }, + unique: true, + filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpLinkUsers_SourceUserId_SourceTenantId_TargetUserId_TargetTenantId", + table: "AbpLinkUsers", + columns: new[] { "SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId" }, + unique: true, + filter: "[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", + table: "AbpOrganizationUnitRoles", + columns: new[] { "RoleId", "OrganizationUnitId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnits_Code", + table: "AbpOrganizationUnits", + column: "Code"); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnits_ParentId", + table: "AbpOrganizationUnits", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGrants_TenantId_Name_ProviderName_ProviderKey", + table: "AbpPermissionGrants", + columns: new[] { "TenantId", "Name", "ProviderName", "ProviderKey" }, + unique: true, + filter: "[TenantId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoleClaims_RoleId", + table: "AbpRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoles_NormalizedName", + table: "AbpRoles", + column: "NormalizedName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSettings_Name_ProviderName_ProviderKey", + table: "AbpSettings", + columns: new[] { "Name", "ProviderName", "ProviderKey" }, + unique: true, + filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_Name", + table: "AbpTenants", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserClaims_UserId", + table: "AbpUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserLogins_LoginProvider_ProviderKey", + table: "AbpUserLogins", + columns: new[] { "LoginProvider", "ProviderKey" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserOrganizationUnits_UserId_OrganizationUnitId", + table: "AbpUserOrganizationUnits", + columns: new[] { "UserId", "OrganizationUnitId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserRoles_RoleId_UserId", + table: "AbpUserRoles", + columns: new[] { "RoleId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_Email", + table: "AbpUsers", + column: "Email"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedEmail", + table: "AbpUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedUserName", + table: "AbpUsers", + column: "NormalizedUserName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_UserName", + table: "AbpUsers", + column: "UserName"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictApplications_ClientId", + table: "OpenIddictApplications", + column: "ClientId"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type", + table: "OpenIddictAuthorizations", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictScopes_Name", + table: "OpenIddictScopes", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type", + table: "OpenIddictTokens", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictTokens_AuthorizationId", + table: "OpenIddictTokens", + column: "AuthorizationId"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictTokens_ReferenceId", + table: "OpenIddictTokens", + column: "ReferenceId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpAuditLogActions"); + + migrationBuilder.DropTable( + name: "AbpClaimTypes"); + + migrationBuilder.DropTable( + name: "AbpEntityPropertyChanges"); + + migrationBuilder.DropTable( + name: "AbpFeatureGroups"); + + migrationBuilder.DropTable( + name: "AbpFeatures"); + + migrationBuilder.DropTable( + name: "AbpFeatureValues"); + + migrationBuilder.DropTable( + name: "AbpLinkUsers"); + + migrationBuilder.DropTable( + name: "AbpOrganizationUnitRoles"); + + migrationBuilder.DropTable( + name: "AbpPermissionGrants"); + + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + + migrationBuilder.DropTable( + name: "AbpRoleClaims"); + + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + + migrationBuilder.DropTable( + name: "AbpSettings"); + + migrationBuilder.DropTable( + name: "AbpTenantConnectionStrings"); + + migrationBuilder.DropTable( + name: "AbpUserClaims"); + + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + + migrationBuilder.DropTable( + name: "AbpUserLogins"); + + migrationBuilder.DropTable( + name: "AbpUserOrganizationUnits"); + + migrationBuilder.DropTable( + name: "AbpUserRoles"); + + migrationBuilder.DropTable( + name: "AbpUserTokens"); + + migrationBuilder.DropTable( + name: "OpenIddictScopes"); + + migrationBuilder.DropTable( + name: "OpenIddictTokens"); + + migrationBuilder.DropTable( + name: "AbpEntityChanges"); + + migrationBuilder.DropTable( + name: "AbpTenants"); + + migrationBuilder.DropTable( + name: "AbpOrganizationUnits"); + + migrationBuilder.DropTable( + name: "AbpRoles"); + + migrationBuilder.DropTable( + name: "AbpUsers"); + + migrationBuilder.DropTable( + name: "OpenIddictAuthorizations"); + + migrationBuilder.DropTable( + name: "AbpAuditLogs"); + + migrationBuilder.DropTable( + name: "OpenIddictApplications"); + } + } +} diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs index b4acd389c1..3d693cc761 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -19,10 +19,10 @@ namespace MyCompanyName.MyProjectName.Host.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => { @@ -494,6 +494,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -680,6 +683,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasDefaultValue(false) .HasColumnName("EmailConfirmed"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -708,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -756,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -818,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Host.Migrations 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") @@ -958,6 +997,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("nvarchar(128)") .HasColumnName("DisplayName"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1536,6 +1578,9 @@ namespace MyCompanyName.MyProjectName.Host.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityVersion") + .HasColumnType("int"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20221220103129_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20230324070202_Initial.Designer.cs similarity index 98% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20221220103129_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20230324070202_Initial.Designer.cs index e062627c6a..1f2dc7a5fb 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20221220103129_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20230324070202_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Mvc.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20221220103129_Initial")] + [Migration("20230324070202_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -717,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -765,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -827,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations 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") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20221220103129_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20230324070202_Initial.cs similarity index 97% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20221220103129_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20230324070202_Initial.cs index cebd34749a..1bb1b884bd 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20221220103129_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20230324070202_Initial.cs @@ -292,6 +292,22 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations table.PrimaryKey("PK_AbpTenants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new @@ -315,7 +331,9 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -988,6 +1006,9 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations migrationBuilder.DropTable( name: "AbpUserClaims"); + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + migrationBuilder.DropTable( name: "AbpUserLogins"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs index 8498fc5efe..835bdad6be 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -714,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -762,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -824,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations 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") diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json index 724c102f7b..a45c2bc0b7 100644 --- a/templates/app/angular/package.json +++ b/templates/app/angular/package.json @@ -12,14 +12,14 @@ }, "private": true, "dependencies": { - "@abp/ng.account": "~7.1.1", - "@abp/ng.components": "~7.1.1", - "@abp/ng.core": "~7.1.1", - "@abp/ng.oauth": "~7.1.1", - "@abp/ng.identity": "~7.1.1", - "@abp/ng.setting-management": "~7.1.1", - "@abp/ng.tenant-management": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.account": "~7.2.0-rc.1", + "@abp/ng.components": "~7.2.0-rc.1", + "@abp/ng.core": "~7.2.0-rc.1", + "@abp/ng.oauth": "~7.2.0-rc.1", + "@abp/ng.identity": "~7.2.0-rc.1", + "@abp/ng.setting-management": "~7.2.0-rc.1", + "@abp/ng.tenant-management": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "@abp/ng.theme.lepton-x": "~2.1.0", "@angular/animations": "^15.0.1", "@angular/common": "^15.0.1", @@ -36,7 +36,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@abp/ng.schematics": "~7.1.1", + "@abp/ng.schematics": "~7.2.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/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs index 1033c73a57..fa55b7d44f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs @@ -4,6 +4,7 @@ using Blazorise.Bootstrap5; using Blazorise.Icons.FontAwesome; using Medallion.Threading; using Medallion.Threading.Redis; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; @@ -163,6 +164,7 @@ public class MyProjectNameBlazorModule : AbpModule .AddCookie("Cookies", options => { options.ExpireTimeSpan = TimeSpan.FromDays(365); + options.IntrospectAccessToken(); }) .AddAbpOpenIdConnect("oidc", options => { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameDbContext.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameDbContext.cs index 46f1217ffa..e1afd1a339 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameDbContext.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameDbContext.cs @@ -45,6 +45,7 @@ public class MyProjectNameDbContext : public DbSet OrganizationUnits { get; set; } public DbSet SecurityLogs { get; set; } public DbSet LinkUsers { get; set; } + public DbSet UserDelegations { get; set; } // Tenant Management public DbSet Tenants { get; set; } diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20221220102812_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20230324065930_Initial.Designer.cs similarity index 98% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20221220102812_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20230324065930_Initial.Designer.cs index dc2a86c8b6..effdc6d3ee 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20221220102812_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20230324065930_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20221220102812_Initial")] + [Migration("20230324065930_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -770,6 +770,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -818,6 +821,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -880,6 +886,32 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpUserClaims", (string)null); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .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") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20221220102812_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20230324065930_Initial.cs similarity index 98% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20221220102812_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20230324065930_Initial.cs index 42ecfe8c2c..ccf3e9776c 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20221220102812_Initial.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20230324065930_Initial.cs @@ -313,6 +313,22 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpTenants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new @@ -336,7 +352,9 @@ namespace MyCompanyName.MyProjectName.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -1017,6 +1035,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpUserClaims"); + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + migrationBuilder.DropTable( name: "AbpUserLogins"); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs index 674c8c4fc3..3805a9ee89 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -767,6 +767,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -815,6 +818,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -877,6 +883,32 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpUserClaims", (string)null); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b => + { + b.Property("Id") + .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") diff --git a/templates/module/angular/package.json b/templates/module/angular/package.json index a5738b7b9a..5a7a077e2a 100644 --- a/templates/module/angular/package.json +++ b/templates/module/angular/package.json @@ -15,15 +15,15 @@ }, "private": true, "dependencies": { - "@abp/ng.account": "~7.1.1", - "@abp/ng.components": "~7.1.1", - "@abp/ng.core": "~7.1.1", - "@abp/ng.oauth": "~7.1.1", - "@abp/ng.identity": "~7.1.1", - "@abp/ng.setting-management": "~7.1.1", - "@abp/ng.tenant-management": "~7.1.1", - "@abp/ng.theme.basic": "~7.1.1", - "@abp/ng.theme.shared": "~7.1.1", + "@abp/ng.account": "~7.2.0-rc.1", + "@abp/ng.components": "~7.2.0-rc.1", + "@abp/ng.core": "~7.2.0-rc.1", + "@abp/ng.oauth": "~7.2.0-rc.1", + "@abp/ng.identity": "~7.2.0-rc.1", + "@abp/ng.setting-management": "~7.2.0-rc.1", + "@abp/ng.tenant-management": "~7.2.0-rc.1", + "@abp/ng.theme.basic": "~7.2.0-rc.1", + "@abp/ng.theme.shared": "~7.2.0-rc.1", "@angular/animations": "^15.0.1", "@angular/common": "^15.0.1", "@angular/compiler": "^15.0.1", @@ -38,7 +38,7 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@abp/ng.schematics": "~7.1.1", + "@abp/ng.schematics": "~7.2.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/templates/module/angular/projects/my-project-name/package.json b/templates/module/angular/projects/my-project-name/package.json index 2b6ab9742a..7d2758556a 100644 --- a/templates/module/angular/projects/my-project-name/package.json +++ b/templates/module/angular/projects/my-project-name/package.json @@ -4,8 +4,8 @@ "peerDependencies": { "@angular/common": ">=14", "@angular/core": ">=14", - "@abp/ng.core": ">=7.1.1", - "@abp/ng.theme.shared": ">=7.1.1" + "@abp/ng.core": ">=7.2.0-rc.1", + "@abp/ng.theme.shared": ">=7.2.0-rc.1" }, "dependencies": { "tslib": "^2.1.0" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20221220114625_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20230324070230_Initial.Designer.cs similarity index 98% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20221220114625_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20230324070230_Initial.Designer.cs index 88bcfda8b0..4c20a44d53 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20221220114625_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20230324070230_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(AuthServerDbContext))] - [Migration("20221220114625_Initial")] + [Migration("20230324070230_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -717,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -765,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -827,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Migrations 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") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20230324070230_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20230324070230_Initial.cs new file mode 100644 index 0000000000..3c62b40bf4 --- /dev/null +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20230324070230_Initial.cs @@ -0,0 +1,1055 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyCompanyName.MyProjectName.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpAuditLogs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + UserId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ImpersonatorUserId = table.Column(type: "uniqueidentifier", nullable: true), + ImpersonatorUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ImpersonatorTenantId = table.Column(type: "uniqueidentifier", nullable: true), + ImpersonatorTenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ExecutionTime = table.Column(type: "datetime2", nullable: false), + ExecutionDuration = table.Column(type: "int", nullable: false), + ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ClientName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + HttpMethod = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), + Url = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + Exceptions = table.Column(type: "nvarchar(max)", nullable: true), + Comments = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + HttpStatusCode = table.Column(type: "int", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpClaimTypes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Required = table.Column(type: "bit", nullable: false), + IsStatic = table.Column(type: "bit", nullable: false), + Regex = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + RegexDescription = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ValueType = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpFeatureGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatureGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpFeatures", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Description = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + DefaultValue = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + IsVisibleToClients = table.Column(type: "bit", nullable: false), + IsAvailableToHost = table.Column(type: "bit", nullable: false), + AllowedProviders = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ValueType = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatures", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpFeatureValues", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Value = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpLinkUsers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + SourceTenantId = table.Column(type: "uniqueidentifier", nullable: true), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetTenantId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpLinkUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpOrganizationUnits", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ParentId = table.Column(type: "uniqueidentifier", nullable: true), + Code = table.Column(type: "nvarchar(95)", maxLength: 95, nullable: false), + DisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpOrganizationUnits", x => x.Id); + table.ForeignKey( + name: "FK_AbpOrganizationUnits_AbpOrganizationUnits_ParentId", + column: x => x.ParentId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissionGrants", + 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), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpRoles", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsDefault = table.Column(type: "bit", nullable: false), + IsStatic = table.Column(type: "bit", nullable: false), + IsPublic = table.Column(type: "bit", nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + Identity = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + Action = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), + UserId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + TenantName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpSettings", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Value = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: false), + ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSettings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpTenants", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpTenants", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpUsers", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + Surname = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), + Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + EmailConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), + PasswordHash = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + SecurityStamp = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsExternal = table.Column(type: "bit", nullable: false, defaultValue: false), + PhoneNumber = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), + PhoneNumberConfirmed = table.Column(type: "bit", nullable: false, defaultValue: false), + IsActive = table.Column(type: "bit", nullable: false), + TwoFactorEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), + LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), + LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), + AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), + EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictApplications", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ClientId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + ClientSecret = table.Column(type: "nvarchar(max)", nullable: true), + ConsentType = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + DisplayName = table.Column(type: "nvarchar(max)", nullable: true), + DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), + Permissions = table.Column(type: "nvarchar(max)", nullable: true), + PostLogoutRedirectUris = table.Column(type: "nvarchar(max)", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + RedirectUris = table.Column(type: "nvarchar(max)", nullable: true), + Requirements = table.Column(type: "nvarchar(max)", nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ClientUri = table.Column(type: "nvarchar(max)", nullable: true), + LogoUri = table.Column(type: "nvarchar(max)", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictApplications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictScopes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Description = table.Column(type: "nvarchar(max)", nullable: true), + Descriptions = table.Column(type: "nvarchar(max)", nullable: true), + DisplayName = table.Column(type: "nvarchar(max)", nullable: true), + DisplayNames = table.Column(type: "nvarchar(max)", nullable: true), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + Resources = table.Column(type: "nvarchar(max)", nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictScopes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpAuditLogActions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), + ServiceName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + MethodName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + Parameters = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), + ExecutionTime = table.Column(type: "datetime2", nullable: false), + ExecutionDuration = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuditLogActions", x => x.Id); + table.ForeignKey( + name: "FK_AbpAuditLogActions_AbpAuditLogs_AuditLogId", + column: x => x.AuditLogId, + principalTable: "AbpAuditLogs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpEntityChanges", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ChangeTime = table.Column(type: "datetime2", nullable: false), + ChangeType = table.Column(type: "tinyint", nullable: false), + EntityTenantId = table.Column(type: "uniqueidentifier", nullable: true), + EntityId = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + EntityTypeFullName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); + table.ForeignKey( + name: "FK_AbpEntityChanges_AbpAuditLogs_AuditLogId", + column: x => x.AuditLogId, + principalTable: "AbpAuditLogs", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpOrganizationUnitRoles", + columns: table => new + { + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpOrganizationUnitRoles", x => new { x.OrganizationUnitId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpOrganizationUnitRoles_AbpOrganizationUnits_OrganizationUnitId", + column: x => x.OrganizationUnitId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpOrganizationUnitRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpRoleClaims", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpRoleClaims_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpTenantConnectionStrings", + columns: table => new + { + TenantId = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + Value = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpTenantConnectionStrings", x => new { x.TenantId, x.Name }); + table.ForeignKey( + name: "FK_AbpTenantConnectionStrings_AbpTenants_TenantId", + column: x => x.TenantId, + principalTable: "AbpTenants", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserClaims", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ClaimType = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ClaimValue = table.Column(type: "nvarchar(1024)", maxLength: 1024, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpUserClaims_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserLogins", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + ProviderKey = table.Column(type: "nvarchar(196)", maxLength: 196, nullable: false), + ProviderDisplayName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserLogins", x => new { x.UserId, x.LoginProvider }); + table.ForeignKey( + name: "FK_AbpUserLogins_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserOrganizationUnits", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + OrganizationUnitId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserOrganizationUnits", x => new { x.OrganizationUnitId, x.UserId }); + table.ForeignKey( + name: "FK_AbpUserOrganizationUnits_AbpOrganizationUnits_OrganizationUnitId", + column: x => x.OrganizationUnitId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserOrganizationUnits_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserRoles", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + RoleId = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserTokens", + columns: table => new + { + UserId = table.Column(type: "uniqueidentifier", nullable: false), + LoginProvider = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + Value = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AbpUserTokens_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictAuthorizations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + Scopes = table.Column(type: "nvarchar(max)", nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictAuthorizations", x => x.Id); + table.ForeignKey( + name: "FK_OpenIddictAuthorizations_OpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "OpenIddictApplications", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "AbpEntityPropertyChanges", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + EntityChangeId = table.Column(type: "uniqueidentifier", nullable: false), + NewValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + OriginalValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), + PropertyName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + PropertyTypeFullName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); + table.ForeignKey( + name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", + column: x => x.EntityChangeId, + principalTable: "AbpEntityChanges", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "OpenIddictTokens", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + ApplicationId = table.Column(type: "uniqueidentifier", nullable: true), + AuthorizationId = table.Column(type: "uniqueidentifier", nullable: true), + CreationDate = table.Column(type: "datetime2", nullable: true), + ExpirationDate = table.Column(type: "datetime2", nullable: true), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + Properties = table.Column(type: "nvarchar(max)", nullable: true), + RedemptionDate = table.Column(type: "datetime2", nullable: true), + ReferenceId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + Status = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + Subject = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: true), + Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true), + LastModificationTime = table.Column(type: "datetime2", nullable: true), + LastModifierId = table.Column(type: "uniqueidentifier", nullable: true), + IsDeleted = table.Column(type: "bit", nullable: false, defaultValue: false), + DeleterId = table.Column(type: "uniqueidentifier", nullable: true), + DeletionTime = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OpenIddictTokens", x => x.Id); + table.ForeignKey( + name: "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId", + column: x => x.ApplicationId, + principalTable: "OpenIddictApplications", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId", + column: x => x.AuthorizationId, + principalTable: "OpenIddictAuthorizations", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogActions_AuditLogId", + table: "AbpAuditLogActions", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogActions_TenantId_ServiceName_MethodName_ExecutionTime", + table: "AbpAuditLogActions", + columns: new[] { "TenantId", "ServiceName", "MethodName", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogs_TenantId_ExecutionTime", + table: "AbpAuditLogs", + columns: new[] { "TenantId", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuditLogs_TenantId_UserId_ExecutionTime", + table: "AbpAuditLogs", + columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityChanges_AuditLogId", + table: "AbpEntityChanges", + column: "AuditLogId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityChanges_TenantId_EntityTypeFullName_EntityId", + table: "AbpEntityChanges", + columns: new[] { "TenantId", "EntityTypeFullName", "EntityId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpEntityPropertyChanges_EntityChangeId", + table: "AbpEntityPropertyChanges", + column: "EntityChangeId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatureGroups_Name", + table: "AbpFeatureGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatures_GroupName", + table: "AbpFeatures", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatures_Name", + table: "AbpFeatures", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", + table: "AbpFeatureValues", + columns: new[] { "Name", "ProviderName", "ProviderKey" }, + unique: true, + filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpLinkUsers_SourceUserId_SourceTenantId_TargetUserId_TargetTenantId", + table: "AbpLinkUsers", + columns: new[] { "SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId" }, + unique: true, + filter: "[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", + table: "AbpOrganizationUnitRoles", + columns: new[] { "RoleId", "OrganizationUnitId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnits_Code", + table: "AbpOrganizationUnits", + column: "Code"); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnits_ParentId", + table: "AbpOrganizationUnits", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGrants_TenantId_Name_ProviderName_ProviderKey", + table: "AbpPermissionGrants", + columns: new[] { "TenantId", "Name", "ProviderName", "ProviderKey" }, + unique: true, + filter: "[TenantId] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoleClaims_RoleId", + table: "AbpRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoles_NormalizedName", + table: "AbpRoles", + column: "NormalizedName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSettings_Name_ProviderName_ProviderKey", + table: "AbpSettings", + columns: new[] { "Name", "ProviderName", "ProviderKey" }, + unique: true, + filter: "[ProviderName] IS NOT NULL AND [ProviderKey] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AbpTenants_Name", + table: "AbpTenants", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserClaims_UserId", + table: "AbpUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserLogins_LoginProvider_ProviderKey", + table: "AbpUserLogins", + columns: new[] { "LoginProvider", "ProviderKey" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserOrganizationUnits_UserId_OrganizationUnitId", + table: "AbpUserOrganizationUnits", + columns: new[] { "UserId", "OrganizationUnitId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserRoles_RoleId_UserId", + table: "AbpUserRoles", + columns: new[] { "RoleId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_Email", + table: "AbpUsers", + column: "Email"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedEmail", + table: "AbpUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedUserName", + table: "AbpUsers", + column: "NormalizedUserName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_UserName", + table: "AbpUsers", + column: "UserName"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictApplications_ClientId", + table: "OpenIddictApplications", + column: "ClientId"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type", + table: "OpenIddictAuthorizations", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictScopes_Name", + table: "OpenIddictScopes", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type", + table: "OpenIddictTokens", + columns: new[] { "ApplicationId", "Status", "Subject", "Type" }); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictTokens_AuthorizationId", + table: "OpenIddictTokens", + column: "AuthorizationId"); + + migrationBuilder.CreateIndex( + name: "IX_OpenIddictTokens_ReferenceId", + table: "OpenIddictTokens", + column: "ReferenceId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpAuditLogActions"); + + migrationBuilder.DropTable( + name: "AbpClaimTypes"); + + migrationBuilder.DropTable( + name: "AbpEntityPropertyChanges"); + + migrationBuilder.DropTable( + name: "AbpFeatureGroups"); + + migrationBuilder.DropTable( + name: "AbpFeatures"); + + migrationBuilder.DropTable( + name: "AbpFeatureValues"); + + migrationBuilder.DropTable( + name: "AbpLinkUsers"); + + migrationBuilder.DropTable( + name: "AbpOrganizationUnitRoles"); + + migrationBuilder.DropTable( + name: "AbpPermissionGrants"); + + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + + migrationBuilder.DropTable( + name: "AbpRoleClaims"); + + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + + migrationBuilder.DropTable( + name: "AbpSettings"); + + migrationBuilder.DropTable( + name: "AbpTenantConnectionStrings"); + + migrationBuilder.DropTable( + name: "AbpUserClaims"); + + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + + migrationBuilder.DropTable( + name: "AbpUserLogins"); + + migrationBuilder.DropTable( + name: "AbpUserOrganizationUnits"); + + migrationBuilder.DropTable( + name: "AbpUserRoles"); + + migrationBuilder.DropTable( + name: "AbpUserTokens"); + + migrationBuilder.DropTable( + name: "OpenIddictScopes"); + + migrationBuilder.DropTable( + name: "OpenIddictTokens"); + + migrationBuilder.DropTable( + name: "AbpEntityChanges"); + + migrationBuilder.DropTable( + name: "AbpTenants"); + + migrationBuilder.DropTable( + name: "AbpOrganizationUnits"); + + migrationBuilder.DropTable( + name: "AbpRoles"); + + migrationBuilder.DropTable( + name: "AbpUsers"); + + migrationBuilder.DropTable( + name: "OpenIddictAuthorizations"); + + migrationBuilder.DropTable( + name: "AbpAuditLogs"); + + migrationBuilder.DropTable( + name: "OpenIddictApplications"); + } + } +} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs index 1f8fc82b42..931645fcd4 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -714,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -762,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -824,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Migrations 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") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/package.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/package.json index c0e313eb4f..e760e7c624 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/package.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/package.json @@ -3,6 +3,6 @@ "name": "my-app-authserver", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.0-rc.1" } } diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20221220103713_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20230324070306_Initial.Designer.cs similarity index 97% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20221220103713_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20230324070306_Initial.Designer.cs index 452252dbbf..ec67c21814 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20221220103713_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20230324070306_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20221220103713_Initial")] + [Migration("20230324070306_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -717,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -765,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -827,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations 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") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20221220103713_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20230324070306_Initial.cs similarity index 97% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20221220103713_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20230324070306_Initial.cs index a0e5f0dcf1..bb45390890 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20221220103713_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20230324070306_Initial.cs @@ -292,6 +292,22 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations table.PrimaryKey("PK_AbpTenants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new @@ -315,7 +331,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -825,6 +843,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations migrationBuilder.DropTable( name: "AbpUserClaims"); + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + migrationBuilder.DropTable( name: "AbpUserLogins"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs index 54362b1b03..82640002ba 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -714,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -762,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -824,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations 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") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/package.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/package.json index 779dbcbdb6..9028d8ddd8 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/package.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/package.json @@ -3,7 +3,7 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~7.1.1", - "@abp/aspnetcore.components.server.basictheme": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.0-rc.1", + "@abp/aspnetcore.components.server.basictheme": "^7.2.0-rc.1" } } diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/package.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/package.json index d598fa29ec..af0f56e16b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/package.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/package.json @@ -3,6 +3,6 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.0-rc.1" } } diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20221220103825_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20230324070335_Initial.Designer.cs similarity index 97% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20221220103825_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20230324070335_Initial.Designer.cs index 20c70b78e1..4f740ff8a5 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20221220103825_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20230324070335_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20221220103825_Initial")] + [Migration("20230324070335_Initial")] partial class Initial { /// @@ -22,7 +22,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -717,6 +717,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -765,6 +768,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -827,6 +833,33 @@ namespace MyCompanyName.MyProjectName.Migrations 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") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20221220103825_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20230324070335_Initial.cs similarity index 97% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20221220103825_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20230324070335_Initial.cs index 88f25f62c6..fddce44b7d 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20221220103825_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20230324070335_Initial.cs @@ -292,6 +292,22 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpTenants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpUserDelegations", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + TenantId = table.Column(type: "uniqueidentifier", nullable: true), + SourceUserId = table.Column(type: "uniqueidentifier", nullable: false), + TargetUserId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + EndTime = table.Column(type: "datetime2", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserDelegations", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpUsers", columns: table => new @@ -315,7 +331,9 @@ namespace MyCompanyName.MyProjectName.Migrations LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), LockoutEnabled = table.Column(type: "bit", nullable: false, defaultValue: false), AccessFailedCount = table.Column(type: "int", nullable: false, defaultValue: 0), + ShouldChangePasswordOnNextLogin = table.Column(type: "bit", nullable: false), EntityVersion = table.Column(type: "int", nullable: false), + LastPasswordChangeTime = table.Column(type: "datetimeoffset", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -825,6 +843,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpUserClaims"); + migrationBuilder.DropTable( + name: "AbpUserDelegations"); + migrationBuilder.DropTable( name: "AbpUserLogins"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 52bc3189e8..02398bbd56 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("ProductVersion", "7.0.1") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -714,6 +714,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("uniqueidentifier") .HasColumnName("LastModifierId"); + b.Property("LastPasswordChangeTime") + .HasColumnType("datetimeoffset"); + b.Property("LockoutEnabled") .ValueGeneratedOnAdd() .HasColumnType("bit") @@ -762,6 +765,9 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("nvarchar(256)") .HasColumnName("SecurityStamp"); + b.Property("ShouldChangePasswordOnNextLogin") + .HasColumnType("bit"); + b.Property("Surname") .HasMaxLength(64) .HasColumnType("nvarchar(64)") @@ -824,6 +830,33 @@ namespace MyCompanyName.MyProjectName.Migrations 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") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/package.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/package.json index d598fa29ec..af0f56e16b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/package.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/package.json @@ -3,6 +3,6 @@ "name": "my-app", "private": true, "dependencies": { - "@abp/aspnetcore.mvc.ui.theme.basic": "~7.1.1" + "@abp/aspnetcore.mvc.ui.theme.basic": "^7.2.0-rc.1" } } diff --git a/tools/localization-key-synchronizer/LocalizationKeySynchronizer.exe b/tools/localization-key-synchronizer/LocalizationKeySynchronizer.exe new file mode 100644 index 0000000000..c8675a0a67 Binary files /dev/null and b/tools/localization-key-synchronizer/LocalizationKeySynchronizer.exe differ diff --git a/tools/localization-key-synchronizer/LocalizationKeySynchronizer.sln b/tools/localization-key-synchronizer/LocalizationKeySynchronizer.sln new file mode 100644 index 0000000000..a9a9ba0988 --- /dev/null +++ b/tools/localization-key-synchronizer/LocalizationKeySynchronizer.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LocalizationKeySynchronizer", "src\LocalizationKeySynchronizer.csproj", "{FFD8DF5E-2724-4D15-9C84-7ACFEEF6F270}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FFD8DF5E-2724-4D15-9C84-7ACFEEF6F270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFD8DF5E-2724-4D15-9C84-7ACFEEF6F270}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFD8DF5E-2724-4D15-9C84-7ACFEEF6F270}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFD8DF5E-2724-4D15-9C84-7ACFEEF6F270}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/tools/localization-key-synchronizer/README.md b/tools/localization-key-synchronizer/README.md new file mode 100644 index 0000000000..f2b9401a30 --- /dev/null +++ b/tools/localization-key-synchronizer/README.md @@ -0,0 +1,27 @@ +# Streamline Localization in Your ABP Project with this Console Tool + +Are you tired of manually managing your localization files for your software projects? Look no further than our new console application designed to streamline your localization workflow! + +![image](https://user-images.githubusercontent.com/58659931/218817197-827d1934-4378-4ccb-87d3-a9118cb5203d.png) + +The application's main menu provides three options: find asynchronous keys, apply changes in the exported file, or replace keys. Let's take a look at each option in more details. + +![image](https://user-images.githubusercontent.com/58659931/218817488-0ba34e67-3039-4162-8291-5eb4669a8868.png) +![image](https://user-images.githubusercontent.com/58659931/218818263-d8d2d8c5-fc77-40a6-ba5c-e1fb7a0180be.png) +![image](https://user-images.githubusercontent.com/58659931/218818359-79a65d48-4895-4ed8-9d34-b6282939ca48.png) + +If you choose to find asynchronous keys, you will be prompted to enter the default language path. Once entered, a multi-select menu will appear with all the JSON files in that folder. You can choose to find keys that do not match the number of arguments, missing keys, or both. If you choose to find the missing keys, you will be prompted to enter the absolute path to export the missing keys. Once entered, the export process will begin, and the application will close. + +![image](https://user-images.githubusercontent.com/58659931/218818963-747766a5-b1c0-420f-95d2-7017a5f63925.png) + +If you choose to find the keys that do not match the number of arguments, you can choose to delete, export, or both. If you choose to delete, the process will complete, and the application will close. If you choose to export, you will be prompted to enter the export path. Once entered, the export process will begin, and the application will close. If you choose to do both, both processes will complete, and the application will close. + +![image](https://user-images.githubusercontent.com/58659931/218820012-e1596f88-5916-4f4f-a482-402c692ed207.png) + +If you choose to apply changes in the exported file, you will be prompted to import the file, and the process will complete. + +![image](https://user-images.githubusercontent.com/58659931/218820350-bfc0ccae-06e8-46d6-853d-7a2d1df3b156.png) + + If you choose to replace keys, you will be prompted to enter the localization folder path, the old key, the new key, and select the JSON files where you want the changes to be made. Once all information is entered, the application will begin the replacement process, and it will close. + +Overall, our console application offers a simple and effective solution to manage your localization files. Try it out yourself today! diff --git a/tools/localization-key-synchronizer/src/AbpAsyncKey.cs b/tools/localization-key-synchronizer/src/AbpAsyncKey.cs new file mode 100644 index 0000000000..e46bb2d7be --- /dev/null +++ b/tools/localization-key-synchronizer/src/AbpAsyncKey.cs @@ -0,0 +1,16 @@ +namespace LocalizationKeySynchronizer; + +public class AbpAsyncKey +{ + public string NewValue = string.Empty; + + public AbpAsyncKey(string key, string reference) + { + Key = key; + Reference = reference; + } + + public virtual string Type => GetType().Name; + public string Key { get; set; } + public string Reference { get; set; } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/AbpAsyncLocalization.cs b/tools/localization-key-synchronizer/src/AbpAsyncLocalization.cs new file mode 100644 index 0000000000..396975f5b7 --- /dev/null +++ b/tools/localization-key-synchronizer/src/AbpAsyncLocalization.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace LocalizationKeySynchronizer; + +public class AbpAsyncLocalization +{ + public AbpAsyncLocalization(AbpLocalization localization, AbpLocalization reference, List asyncKeys) + { + Localization = localization; + Reference = reference; + AsyncKeys = asyncKeys; + } + + public AbpLocalization Localization { get; set; } + public AbpLocalization Reference { get; set; } + + public List AsyncKeys { get; set; } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/AbpAsyncLocalizationViewModel.cs b/tools/localization-key-synchronizer/src/AbpAsyncLocalizationViewModel.cs new file mode 100644 index 0000000000..c2a17ae378 --- /dev/null +++ b/tools/localization-key-synchronizer/src/AbpAsyncLocalizationViewModel.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace LocalizationKeySynchronizer; + +public class AbpAsyncLocalizationViewModel +{ + public AbpAsyncLocalizationViewModel(string referenceCulture, string culture, string path, List asyncKeys) + { + ReferenceCulture = referenceCulture; + Culture = culture; + Path = path; + AsyncKeys = asyncKeys; + } + + public string ReferenceCulture { get; set; } + public string Culture { get; set; } + public string Path { get; set; } + + public List AsyncKeys { get; set; } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/AbpLocalization.cs b/tools/localization-key-synchronizer/src/AbpLocalization.cs new file mode 100644 index 0000000000..78d82d556a --- /dev/null +++ b/tools/localization-key-synchronizer/src/AbpLocalization.cs @@ -0,0 +1,14 @@ +namespace LocalizationKeySynchronizer; + +public class AbpLocalization +{ + public AbpLocalization(string filePath, AbpLocalizationInfo localizationInfo) + { + FilePath = filePath; + LocalizationInfo = localizationInfo; + } + + public string FilePath { get; set; } + + public AbpLocalizationInfo LocalizationInfo { get; set; } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/AbpLocalizationInfo.cs b/tools/localization-key-synchronizer/src/AbpLocalizationInfo.cs new file mode 100644 index 0000000000..d8db3b4b1b --- /dev/null +++ b/tools/localization-key-synchronizer/src/AbpLocalizationInfo.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace LocalizationKeySynchronizer; + +// This class is used to deserialize the JSON string from culture file. +public class AbpLocalizationInfo +{ + public AbpLocalizationInfo(string culture, Dictionary texts) + { + Culture = culture; + Texts = texts; + } + + public string Culture { get; set; } + public Dictionary Texts { get; set; } + + public static bool TryDeserialize(string json, out AbpLocalizationInfo? localizationInfo) + { + return JsonHelper.TryDeserialize(json, out localizationInfo); + } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/ArgumentCountMismatch.cs b/tools/localization-key-synchronizer/src/ArgumentCountMismatch.cs new file mode 100644 index 0000000000..1b3630f116 --- /dev/null +++ b/tools/localization-key-synchronizer/src/ArgumentCountMismatch.cs @@ -0,0 +1,15 @@ +namespace LocalizationKeySynchronizer; + +public class ArgumentCountMismatch : AbpAsyncKey +{ + public ArgumentCountMismatch(string key, string reference, int referenceArgumentCount, int argumentCount, string value) : base(key, reference) + { + ReferenceArgumentCount = referenceArgumentCount; + ArgumentCount = argumentCount; + Value = value; + } + + public int ReferenceArgumentCount { get; } + public int ArgumentCount { get; } + public string Value { get; } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/JsonHelper.cs b/tools/localization-key-synchronizer/src/JsonHelper.cs new file mode 100644 index 0000000000..2f284d5839 --- /dev/null +++ b/tools/localization-key-synchronizer/src/JsonHelper.cs @@ -0,0 +1,26 @@ +using System; +using Newtonsoft.Json; + +namespace LocalizationKeySynchronizer; + +public static class JsonHelper +{ + public static bool TryDeserialize(string json, out T? result) + { + try + { + result = JsonConvert.DeserializeObject(json); + return true; + } + catch (Exception) + { + result = default; + return false; + } + } + + public static string Serialize(T value) + { + return JsonConvert.SerializeObject(value, Formatting.Indented); + } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/LocalizationHelper.cs b/tools/localization-key-synchronizer/src/LocalizationHelper.cs new file mode 100644 index 0000000000..fbdb8a1aef --- /dev/null +++ b/tools/localization-key-synchronizer/src/LocalizationHelper.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +namespace LocalizationKeySynchronizer; + +public static partial class LocalizationHelper +{ + public static bool TryGetLocalization(string path, out AbpLocalizationInfo? localizationInfo) + { + if (File.Exists(path) == false) + { + localizationInfo = default; + return false; + } + + var json = File.ReadAllTextAsync(path).GetAwaiter().GetResult(); + return AbpLocalizationInfo.TryDeserialize(json, out localizationInfo); + } + + public static List GetLocalizations(IEnumerable paths) + { + var results = new List(); + foreach (var path in paths) + { + if (TryGetLocalization(path, out var localizationInfo)) + { + results.Add(new AbpLocalization(path, localizationInfo!)); + } + } + + return results; + } + + private static Dictionary GetKeysAndArgCount(this AbpLocalizationInfo localizationInfo) + { + return localizationInfo.Texts.ToDictionary(k => k.Key, v => GetArgCount(v.Value)); + } + + private static int GetArgCount(string value) + { + var matches = MyRegex().Matches(value); + return matches.Count; + } + + public static List GetAsynchronousLocalizations(this AbpLocalization defaultLocalization, + IEnumerable otherLocalizations) + { + var results = new List(); + var defaultCultureKeysAndArgCount = defaultLocalization.LocalizationInfo.GetKeysAndArgCount(); + foreach (var localization in otherLocalizations) + { + var keysAndArgCount = localization.LocalizationInfo.GetKeysAndArgCount(); + var asynchronousResource = + new AbpAsyncLocalization(localization, defaultLocalization, new List()); + foreach (var (key, defaultCultureArgCount) in defaultCultureKeysAndArgCount) + { + if (keysAndArgCount.TryGetValue(key, out var value)) + { + if (value != defaultCultureArgCount) + { + asynchronousResource.AsyncKeys.Add(new ArgumentCountMismatch(key, + defaultLocalization.LocalizationInfo.Texts[key], defaultCultureArgCount, value, + localization.LocalizationInfo.Texts[key])); + } + } + else + { + asynchronousResource.AsyncKeys.Add(new MissingKey(key, + defaultLocalization.LocalizationInfo.Texts[key])); + } + } + + if (asynchronousResource.AsyncKeys.Any()) + { + results.Add(asynchronousResource); + } + } + + return results; + } + + public static void DeleteKeysThatDoNotMatchTheNumberOfArguments( + IEnumerable asynchronousResources) + { + foreach (var resource in asynchronousResources) + { + foreach (var key in resource.AsyncKeys.Select(x => x.Key)) + { + resource.Localization.LocalizationInfo.Texts.Remove(key); + } + + File.WriteAllTextAsync(resource.Localization.FilePath, + JsonHelper.Serialize(resource.Localization.LocalizationInfo)).GetAwaiter().GetResult(); + } + } + + public static void ExportKeysThatDoNotMatchTheNumberOfArguments( + IEnumerable asynchronousResources, string? exportPath) + { + Export(asynchronousResources, exportPath); + } + + public static void Export(IEnumerable asynchronousResources, string? exportPath) + where T : AbpAsyncKey + { + var asyncLocalizationViewModels = asynchronousResources.Select(x => + new AbpAsyncLocalizationViewModel(x.Reference.LocalizationInfo.Culture, + x.Localization.LocalizationInfo.Culture, x.Localization.FilePath, + x.AsyncKeys.Where(k => k is T).ToList())).ToList(); + + if (exportPath != null) + { + File.WriteAllTextAsync(exportPath, + JsonHelper.Serialize(asyncLocalizationViewModels)) + .GetAwaiter().GetResult(); + } + } + + public static void ExportMissingKeys(IEnumerable asyncLocalizations, string? exportPath) + { + Export(asyncLocalizations, exportPath); + } + + public static bool ApplyChanges(string path) + { + var json = File.ReadAllTextAsync(path).GetAwaiter().GetResult(); + + if (JsonHelper.TryDeserialize(json, out List? asyncLocalizationViewModels) == + false) + { + return false; + } + + foreach (var asyncLocalizationViewModel in asyncLocalizationViewModels!) + { + if (TryGetLocalization(asyncLocalizationViewModel.Path, out var localizationInfo) == false) + { + return false; + } + + foreach (var asyncKey in asyncLocalizationViewModel.AsyncKeys.Where(asyncKey => + !string.IsNullOrWhiteSpace(asyncKey.NewValue))) + { + localizationInfo!.Texts[asyncKey.Key] = asyncKey.NewValue; + } + + File.WriteAllTextAsync(asyncLocalizationViewModel.Path, + JsonHelper.Serialize(localizationInfo)).GetAwaiter().GetResult(); + } + + return true; + } + + public static void ReplaceKey(string oldKey, string newKey, List localizations) + { + foreach (var localization in localizations) + { + if (!localization.LocalizationInfo.Texts.TryGetValue(oldKey, out var value)) + { + continue; + } + + localization.LocalizationInfo.Texts.Remove(oldKey); + localization.LocalizationInfo.Texts.Add(newKey, value); + File.WriteAllTextAsync(localization.FilePath, + JsonHelper.Serialize(localization.LocalizationInfo)).GetAwaiter().GetResult(); + } + } + + [GeneratedRegex("{(\\d+)}")] + private static partial Regex MyRegex(); +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/LocalizationKeySynchronizer.csproj b/tools/localization-key-synchronizer/src/LocalizationKeySynchronizer.csproj new file mode 100644 index 0000000000..8f566bc239 --- /dev/null +++ b/tools/localization-key-synchronizer/src/LocalizationKeySynchronizer.csproj @@ -0,0 +1,15 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + diff --git a/tools/localization-key-synchronizer/src/MissingKey.cs b/tools/localization-key-synchronizer/src/MissingKey.cs new file mode 100644 index 0000000000..0463f3dd16 --- /dev/null +++ b/tools/localization-key-synchronizer/src/MissingKey.cs @@ -0,0 +1,8 @@ +namespace LocalizationKeySynchronizer; + +public class MissingKey : AbpAsyncKey +{ + public MissingKey(string key, string reference) : base(key, reference) + { + } +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/Program.cs b/tools/localization-key-synchronizer/src/Program.cs new file mode 100644 index 0000000000..42c97f0754 --- /dev/null +++ b/tools/localization-key-synchronizer/src/Program.cs @@ -0,0 +1,173 @@ +using System; +using System.IO; +using System.Linq; +using LocalizationKeySynchronizer; +using Spectre.Console; +using static LocalizationKeySynchronizer.Questions; + +try +{ + // Do you want to find asynchronous keys, apply changes in the exported file or replace the keys? + var option = AnsiConsole.Prompt( + new SelectionPrompt() + .Title(_1.Question) + .AddChoices(_1.Options.Find, _1.Options.Apply, _1.Options.Replace)); + + switch (option) + { + case _1.Options.Apply: + { + // Enter the absolute path to the exported file: + var path = AnsiConsole.Ask(_2); + + if (!File.Exists(path)) + { + AnsiConsole.MarkupLine("[red]The file does not exist![/]"); + Exit(); + } + + if (LocalizationHelper.ApplyChanges(path)) + { + AnsiConsole.MarkupLine("[green]The changes have been applied successfully![/]"); + Exit(); + } + + AnsiConsole.MarkupLine("[red]An error occurred while applying changes![/]"); + Exit(); + break; + } + case _1.Options.Find: + { + // The default language path + var path = AnsiConsole.Ask(_3); + + if (!LocalizationHelper.TryGetLocalization(path, out var defaultLocalizationInfo)) + { + AnsiConsole.MarkupLine("[red]The default language path is invalid![/]"); + Exit(); + } + + var defaultCulture = new AbpLocalization(path, defaultLocalizationInfo!); + +// Get others cultures + var paths = Directory.GetFiles(Path.GetDirectoryName(path)!, "*.json", + SearchOption.TopDirectoryOnly); + + var otherCulturePaths = paths.Select(Path.GetFileNameWithoutExtension).Where(x=>!string.IsNullOrWhiteSpace(x)).Select(x=>x!).ToList(); + // select other cultures + paths = AnsiConsole.Prompt( + new MultiSelectionPrompt() + .Title("Select other cultures") + .PageSize(10).AddChoiceGroup("All", otherCulturePaths)) + .Select(x => Path.Combine(Path.GetDirectoryName(path)!, x + ".json")) + .ToArray(); + + var otherCultures = LocalizationHelper.GetLocalizations(paths); + var asyncLocalizations = defaultCulture.GetAsynchronousLocalizations(otherCultures); + +// Find keys that do not match the number of arguments, find missing keys, or both + + var options = AnsiConsole.Prompt( + new MultiSelectionPrompt() + .Title(_4.Question) + .PageSize(10) + .AddChoiceGroup("All", _4.Options.ArgumentsCount, _4.Options.MissingKeys)); + +// For arguments +// Find keys that do not match the number of arguments + + string? exportPath = null; + if (options.Contains(_4.Options.ArgumentsCount)) + { + // Should the keys that do not match the number of arguments be deleted, exported or both? + + var options2 = AnsiConsole.Prompt( + new MultiSelectionPrompt() + .Title(_5.Question) + .PageSize(10) + .AddChoiceGroup("All", _5.Options.Delete, _5.Options.Export)); + + // Delete the keys that do not match the number of arguments + if (options2.Contains(_5.Options.Delete)) + { + LocalizationHelper.DeleteKeysThatDoNotMatchTheNumberOfArguments(asyncLocalizations); + } + + // Ask for the export path and export it + if (options2.Contains(_5.Options.Export)) + { + if (options.Contains(_4.Options.MissingKeys)) + { + exportPath = AnsiConsole.Ask(_8); + LocalizationHelper.Export(asyncLocalizations, exportPath); + } + else + { + exportPath = AnsiConsole.Ask(_6); + LocalizationHelper.ExportKeysThatDoNotMatchTheNumberOfArguments(asyncLocalizations, exportPath); + } + } + } + +// For missing keys +// Export missing keys + if (options.Contains(_4.Options.MissingKeys)) + { + if (string.IsNullOrEmpty(exportPath)) + { + exportPath = AnsiConsole.Ask(_7); + LocalizationHelper.ExportMissingKeys(asyncLocalizations, exportPath); + } + } + + break; + } + case _1.Options.Replace: + { + // The localization folder path + var path = AnsiConsole.Ask(_9); + + // Old key + var oldKey = AnsiConsole.Ask(_10); + + // New key + var newKey = AnsiConsole.Ask(_11); + + // Localization paths + var paths = Directory.GetFiles(path, "*.json", + SearchOption.TopDirectoryOnly); + + // Select localizations + + var localizationPaths = paths.Select(Path.GetFileNameWithoutExtension).Where(x=>!string.IsNullOrWhiteSpace(x)).Select(x=>x!).ToList(); + paths = AnsiConsole.Prompt( + new MultiSelectionPrompt() + .Title("Select localizations") + .PageSize(10) + .AddChoiceGroup("All", localizationPaths)) + .Select(x => Path.Combine(path, x + ".json")) + .ToArray(); + + var cultures = LocalizationHelper.GetLocalizations(paths); + + // Replace keys + LocalizationHelper.ReplaceKey(oldKey, newKey, cultures); + + AnsiConsole.MarkupLine("[green]The keys have been replaced successfully![/]"); + break; + } + } +} +catch (Exception e) +{ + Console.WriteLine(e); + AnsiConsole.MarkupLine($"[red]{e.Message}[/]"); + Exit(); +} + +void Exit() +{ + AnsiConsole.MarkupLine("[red]Press any key to exit...[/]"); + Console.ReadKey(); + Environment.Exit(0); +} \ No newline at end of file diff --git a/tools/localization-key-synchronizer/src/Questions.cs b/tools/localization-key-synchronizer/src/Questions.cs new file mode 100644 index 0000000000..a284fbaf9b --- /dev/null +++ b/tools/localization-key-synchronizer/src/Questions.cs @@ -0,0 +1,57 @@ +namespace LocalizationKeySynchronizer; + +public static class Questions +{ + public const string _2 = "Enter the absolute path to the exported file:"; + + public const string _3 = "Enter the default language path:"; + + public const string _6 = "Enter the absolute path to export the keys that do not match the number of arguments:"; + + public const string _7 = "Enter the absolute path to export the missing keys:"; + + public const string _8 = "Enter the export path:"; + + public const string _9 = "Enter the localization folder path:"; + + public const string _10 = "Enter the old key:"; + + public const string _11 = "Enter the new key:"; + + public static class _1 + { + public const string Question = + "Do you want to find asynchronous keys, apply changes in the exported file or replace the keys?"; + + public static class Options + { + public const string Find = "Find asynchronous keys"; + public const string Apply = "Apply changes in the exported file"; + public const string Replace = "Replace keys"; + } + } + + public static class _4 + { + public const string Question = + "Find keys that do not match the number of arguments, find missing keys, or both?"; + + public static class Options + { + public const string ArgumentsCount = "Not matching arguments count"; + public const string MissingKeys = "Missing keys"; + } + } + + public static class _5 + { + public const string Question = + "Should the keys that do not match the number of arguments be deleted, exported or both?"; + + public static class Options + { + public const string Delete = "Delete"; + public const string Export = "Export"; + } + } +} \ No newline at end of file