diff --git a/.gitignore b/.gitignore
index 6e767c8f76..5b8dfe9c11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -305,3 +305,6 @@ modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Logs/
/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package-lock.json
abp-build-config.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/Pages/Test/
+
+# Identity Server temp signature file
+tempkey.jwk
\ 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 adc808ed7e..0d66f1288d 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json
@@ -8,6 +8,7 @@
"FrameworkDocumentation": "框架文档",
"OfficialBlog": "官方博客",
"CommercialHomePage": "商业版首页",
- "CommercialSupportWebSite": "商业版支持网站"
+ "CommercialSupportWebSite": "商业版支持网站",
+ "CommunityWebSite": "ABP社区网站"
}
}
\ No newline at end of file
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 bc78a54119..f5cbeb0213 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json
@@ -3,6 +3,12 @@
"texts": {
"Permission:Organizations": "组织",
"Permission:Manage": "管理组织",
+ "Permission:DiscountRequests": "折扣请求",
+ "Permission:DiscountManage": "管理折扣请求",
+ "Permission:Disable": "禁用",
+ "Permission:Enable": "启动",
+ "Permission:EnableSendEmail": "启用发送邮件",
+ "Permission:SendEmail": "发送邮件",
"Permission:NpmPackages": "NPM包",
"Permission:NugetPackages": "Nuget包",
"Permission:Maintenance": "维护",
@@ -13,8 +19,13 @@
"Permission:Edit": "编辑",
"Permission:Delete": "删除",
"Permission:Create": "创建",
+ "Permission:Accounting": "账单",
+ "Permission:Accounting:Quotation": "报价",
+ "Permission:Accounting:Invoice": "发票",
"Menu:Organizations": "组织",
+ "Menu:Accounting": "账单",
"Menu:Packages": "包",
+ "Menu:DiscountRequests": "折扣请求",
"NpmPackageDeletionWarningMessage": "该NPM包将会被删除. 你确定吗?",
"NugetPackageDeletionWarningMessage": "该Nuget包将会被删除. 你确定吗?",
"ModuleDeletionWarningMessage": "该模块将会被删除. 你确定吗?",
@@ -24,6 +35,7 @@
"NameFilter": "名称",
"CreationTime": "创建时间",
"IsPro": "是否为专业版",
+ "ShowOnModuleList": "展示模块列表",
"EfCoreConfigureMethodName": "配置方法法",
"IsProFilter": "是否为专业版",
"ApplicationType": "应用程序类型",
@@ -53,6 +65,7 @@
"CreateANugetPackage": "创建Nuget包",
"AddNew": "新建",
"PackageAlreadyExist{0}": "\"{0}\"已经被添加.",
+ "ModuleAlreadyExist{0}": "\"{0}\" 模块已经添加.",
"ClearCache": "清除缓存",
"SuccessfullyCleared": "清除成功",
"Menu:NpmPackages": "NPM包",
@@ -63,6 +76,7 @@
"Organizations": "组织",
"LongName": "完整名称",
"LicenseType": "授权类型",
+ "MissingLicenseTypeField": "许可证类型字段是必需的!",
"LicenseStartTime": "授权开始时间",
"LicenseEndTime": "授权结束时间",
"AllowedDeveloperCount": "允许的开发人员数量",
@@ -74,14 +88,112 @@
"AddDeveloper": "添加开发者",
"Create": "创建",
"UserNotFound": "用户不存在",
- "{0}WillBeRemovedFromMembers": "{0} 将从成员中删除",
+ "{0}WillBeRemovedFromDevelopers": "{0} 将从开发者中移除, 你确定吗?",
+ "{0}WillBeRemovedFromOwners": "{0} 将从所有者中移除, 你确定吗?",
"Computers": "计算机",
"UniqueComputerId": "计算机唯一ID",
"LastSeenDate": "上次查看日期",
"{0}Computer{1}WillBeRemovedFromRecords": "计算机 {0} ({1}) 将从记录中删除",
"OrganizationDeletionWarningMessage": "组织将被删除",
+ "DeletingLastOwnerWarningMessage": "一个组织必须至少有一个所有者!因此你不能删除此所有者",
"This{0}AlreadyExistInThisOrganization": "该组织中已经存在此 {0}",
"AreYouSureYouWantToDeleteAllComputers": "您确定要删除所有计算机吗?",
- "DeleteAll": "删除所有"
+ "DeleteAll": "删除所有",
+ "DoYouWantToCreateNewUser": "你想要创建一个新用户吗",
+ "MasterModules": "主模块",
+ "OrganizationName": "组织名称",
+ "CreationDate": "创建时间",
+ "LicenseStartDate": "许可开始时间",
+ "LicenseEndDate": "许可结束时间",
+ "OrganizationNamePlaceholder": "组织名称...",
+ "TotalQuestionCountPlaceholder": "问题总数...",
+ "RemainingQuestionCountPlaceholder": "剩下的问题数...",
+ "LicenseTypePlaceholder": "许可类型...",
+ "CreationDatePlaceholder": "创建时间...",
+ "LicenseStartDatePlaceholder": "许可开始时间...",
+ "LicenseEndDatePlaceholder": "许可结束时间...",
+ "UsernameOrEmail": "用户名或邮箱",
+ "UsernameOrEmailPlaceholder": "用户名或邮箱...",
+ "Member": "成员",
+ "PurchaseOrderNo": "订单编号",
+ "QuotationDate": "报价日期",
+ "CompanyName": "公司名称",
+ "CompanyAddress": "公司地址",
+ "Price": "价格",
+ "DiscountText": "折扣文字",
+ "DiscountQuantity": "折扣数量",
+ "DiscountPrice": "折扣价格",
+ "Quotation": "报价单",
+ "ExtraText": "额外文字",
+ "ExtraAmount": "额外金额",
+ "DownloadQuotation": "下载报价单",
+ "Invoice": "发票",
+ "TaxNumber": "税号",
+ "InvoiceNumber": "发票数字",
+ "InvoiceDate": "发票日期",
+ "InvoiceNote": "发票说明",
+ "Quantity": "数量",
+ "AddProduct": "添加产品",
+ "AddProductWarning": "你需要添加产品",
+ "TotalPrice": "总价",
+ "Generate": "生成",
+ "MissingQuantityField": "数量字段为必填项!",
+ "MissingPriceField": "价格字段为必填项!",
+ "CodeUsageStatus": "状态",
+ "Country": "国家",
+ "DeveloperCount": "开发者数量",
+ "RequestCode": "请求码",
+ "WebSite": "网站",
+ "GithubUsername": "Github用户名",
+ "PhoneNumber": "手机号",
+ "ProjectDescription": "产品描述",
+ "Referrer": "推荐人",
+ "DiscountRequests": "折扣请求",
+ "Copylink": "拷贝链接",
+ "Disable": "禁用",
+ "Enable": "启用",
+ "EnableSendEmail": "启用发送邮件",
+ "SendEmail": "发送邮件",
+ "SuccessfullyDisabled": "禁用成功",
+ "SuccessfullyEnabled": "启用成功",
+ "EmailSent": "邮件发送",
+ "SuccessfullySent": "发送成功",
+ "SuccessfullyDeleted": "删除成功",
+ "DiscountRequestDeletionWarningMessage": "折扣成功将被删除",
+ "BusinessType": "商业类型",
+ "TotalQuestionCount": "问题总数",
+ "RemainingQuestionCount": "剩余问题数",
+ "TotalQuestionMustBeGreaterWarningMessage": "TotalQuestionCount必须大于RemainingQuestionCount!",
+ "QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount和RemainingQuestionCount必须为0或大于0",
+ "UnlimitedQuestionCount": "无限的问题计数",
+ "Notes": "笔记",
+ "Menu:Community": "社区",
+ "Menu:Articles": "文章",
+ "Wait": "等待",
+ "Approve": "批准",
+ "Reject": "拒绝",
+ "Details": "详情",
+ "Url": "Url",
+ "Title": "标题",
+ "ContentSource": "内容源",
+ "Status": "状态",
+ "ReadArticle": "阅读文章",
+ "ArticleHasBeenWaiting": "文章还在等待",
+ "ArticleHasBeenApproved": "文章已被批准",
+ "ArticleHasBeenRejected": "文章已被拒绝",
+ "Permission:Community": "社区",
+ "Permission:CommunityArticle": "文字",
+ "Link": "链接",
+ "Enum:ContentSource:0": "Github",
+ "Enum:ContentSource:1": "外部",
+ "Enum:Status:0": "等待中",
+ "Enum:Status:1": "已拒绝",
+ "Enum:Status:2": "已批准",
+ "Summary": "概要",
+ "AuthorName": "作者名称",
+ "CoverImage": "封面图片",
+ "RemoveCacheConfirmationMessage": "你确定要删除\"{0}\" 文章缓存?",
+ "SuccessfullyRemoved": "清除成功",
+ "RemoveCache": "删除缓存"
}
}
\ 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 d6f334f7cd..a916cd82d9 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
@@ -27,6 +27,7 @@
"Blog": "Blog",
"Commercial": "Commercial",
"MyAccount": "My account",
- "SeeDocuments": "See Documents"
+ "SeeDocuments": "See Documents",
+ "Samples": "Samples"
}
}
\ 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 986d1fdc2c..79493b537e 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 @@
"ContributionGuide": "贡献指南",
"Blog": "博客",
"Commercial": "商业版",
- "SeeDocuments": "查看文档"
+ "MyAccount": "我的账户",
+ "SeeDocuments": "查看文档",
+ "Samples": "示例"
}
}
\ No newline at end of file
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 e80457377f..0147e71a05 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
@@ -6,6 +6,8 @@
"Volo.AbpIo.Commercial:010003": "你不是该组织的所有者!",
"OrganizationNotFoundMessage": "找不到任何组织!",
"DeveloperCount": "开发者数量",
+ "QuestionCount": "剩余 / 问题总数",
+ "Unlimited": "无限制",
"Owners": "所有者",
"AddMember": "添加成员",
"AddOwner": "添加所有者",
@@ -25,6 +27,9 @@
"Volo.AbpIo.Commercial:010004": "不能找到指定的用户! 用户必须已经注册.",
"MyOrganizations": "我的组织",
"ApiKey": "API key",
- "UserNameNotFound": "没有用户名为{0}的用户"
+ "UserNameNotFound": "没有用户名为{0}的用户",
+ "SuccessfullyAddedToNewsletter": "感谢你订阅我们的新闻通讯!",
+ "MyProfile": "我的资料",
+ "EmailNotValid": "请输入有效的电子邮件地址"
}
}
\ 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 307ff066a7..fa793c91a0 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
@@ -1,64 +1,89 @@
{
- "culture": "zh-Hans",
- "texts": {
- "Permission:CommunityArticle": "社区文章",
- "Permission:Edit": "修改",
- "Waiting": "等待中",
- "Approved": "已批准",
- "Rejected": "已拒绝",
- "Wait": "等待",
- "Approve": "批准",
- "Reject": "拒绝",
- "ReadArticle": "阅读文章",
- "Status": "状态",
- "ContentSource": "内容来源",
- "Details": "详情",
- "Url": "url",
- "Title": "标题",
- "CreationTime": "创建时间",
- "Save": "保存",
- "SameUrlAlreadyExist": "url已存在,如果你想要添加这篇文章,你需要更改url!",
- "UrlIsNotValid": "Url无效.",
- "UrlNotFound" : "Url未找到.",
- "UrlContentNotFound": "Url内容未找到.",
- "Summary": "摘要",
- "MostRead": "阅读最多",
- "Latest": "最新",
- "ContributeAbpCommunity": "为ABP社区做贡献",
- "SubmitYourArticle": "提交你的文章",
- "ContributionGuide": "贡献指南",
- "BugReport": "Bug报告",
- "SeeAllArticles": "查看所有的文章",
- "WelcomeToABPCommunity!": "欢迎来到ABP社区!",
- "MyProfile": "我的资料",
- "MyOrganizations": "我的组织",
- "EmailNotValid": "请输入有效的电子邮箱地址.",
- "FeatureRequest": "功能请求",
- "CreateArticleTitleInfo": "文章标题显示在文章列表中.",
- "CreateArticleUrlInfo": "文章的原始GitHub/外部URL.",
- "CreateArticleSummaryInfo": "文章的简短摘要将显示在文章列表中.",
- "CreateArticleCoverInfo": "为了创建有效的文章,请添加封面图. 仅支持16:9的图片!",
- "ThisExtensionIsNotAllowed": "不允许此扩展名.",
- "TheFileIsTooLarge": "文件过大.",
- "GoToTheArticle": "转到文章",
- "Contribute": "贡献",
- "OverallProgress": "总体流程",
- "Done": "完成",
- "Open": "打开",
- "Closed": "关闭",
- "LatestQuestionOnThe": "有关的最新问题",
- "Stackoverflow": "Stackoverflow",
- "Votes": "票数",
- "Answer": "回答",
- "Views": "观看次数",
- "Answered": "已回答",
- "WaitingForYourAnswer": "等待你的回答",
- "Asked": "提问",
- "AllQuestions": "所有的问题",
- "NextVersion": "下一个版本",
- "MilestoneErrorMessage": "无法从Github获取当前的里程碑详细信息.",
- "QuestionItemErrorMessage": "无法从Stackoverflow获取最新的问题详细信息.",
- "Oops": "哎呀!"
- }
+ "culture": "zh-Hans",
+ "texts": {
+ "Permission:CommunityArticle": "社区文章",
+ "Permission:Edit": "修改",
+ "Waiting": "等待中",
+ "Approved": "已批准",
+ "Rejected": "已拒绝",
+ "Wait": "等待",
+ "Approve": "批准",
+ "Reject": "拒绝",
+ "ReadArticle": "阅读文章",
+ "Status": "状态",
+ "ContentSource": "内容来源",
+ "Details": "详情",
+ "Url": "url",
+ "Title": "标题",
+ "CreationTime": "创建时间",
+ "Save": "保存",
+ "SameUrlAlreadyExist": "url已存在,如果你想要添加这篇文章,你需要更改url!",
+ "UrlIsNotValid": "Url无效.",
+ "UrlNotFound": "Url未找到.",
+ "UrlContentNotFound": "Url内容未找到.",
+ "Summary": "摘要",
+ "MostRead": "阅读最多",
+ "Latest": "最新",
+ "ContributeAbpCommunity": "为ABP社区做贡献",
+ "SubmitYourArticle": "提交你的文章",
+ "ContributionGuide": "贡献指南",
+ "BugReport": "Bug报告",
+ "SeeAllArticles": "查看所有的文章",
+ "WelcomeToABPCommunity!": "欢迎来到ABP社区!",
+ "MyProfile": "我的资料",
+ "MyOrganizations": "我的组织",
+ "EmailNotValid": "请输入有效的电子邮箱地址.",
+ "FeatureRequest": "功能请求",
+ "CreateArticleTitleInfo": "文章标题显示在文章列表中.",
+ "CreateArticleUrlInfo": "文章的原始GitHub/外部URL.",
+ "CreateArticleSummaryInfo": "文章的简短摘要将显示在文章列表中.",
+ "CreateArticleCoverInfo": "为了创建有效的文章,请添加封面图. 仅支持16:9的图片!",
+ "ThisExtensionIsNotAllowed": "不允许此扩展名.",
+ "TheFileIsTooLarge": "文件过大.",
+ "GoToTheArticle": "转到文章",
+ "Contribute": "贡献",
+ "OverallProgress": "总体流程",
+ "Done": "完成",
+ "Open": "打开",
+ "Closed": "关闭",
+ "LatestQuestionOnThe": "有关的最新问题",
+ "Stackoverflow": "Stackoverflow",
+ "Votes": "票数",
+ "Answer": "回答",
+ "Views": "观看次数",
+ "Answered": "已回答",
+ "WaitingForYourAnswer": "等待你的回答",
+ "Asked": "提问",
+ "AllQuestions": "所有的问题",
+ "NextVersion": "下一个版本",
+ "MilestoneErrorMessage": "无法从Github获取当前的里程碑详细信息.",
+ "QuestionItemErrorMessage": "无法从Stackoverflow获取最新的问题详细信息.",
+ "Oops": "哎呀!",
+ "CreateArticleSuccessMessage": "文章提交成功. 网站管理员审核通过后将被发布.",
+ "ChooseCoverImage": "选项一张封面图片",
+ "CoverImage": "封面图片",
+ "ShareYourExperiencesWithTheABPFramework": "分享你的ABP Framework经验!",
+ "Optional": "可选的",
+ "UpdateUserWebSiteInfo": "示例: https://johndoe.com",
+ "UpdateUserTwitterInfo": "示例: johndoe",
+ "UpdateUserGithubInfo": "示例: johndoe",
+ "UpdateUserLinkedinInfo": "示例: https://www.linkedin.com/...",
+ "UpdateUserCompanyInfo": "示例v: Volosoft",
+ "UpdateUserJobTitleInfo": "示例: Software Developer",
+ "UserName": "用户名",
+ "Company": "公司",
+ "PersonalWebsite": "个人网站",
+ "RegistrationDate": "注册时间",
+ "Social": "社交",
+ "Biography": "传记",
+ "HasNoPublishedArticlesYet": "尚未发表文章",
+ "Author": "作者",
+ "LatestGithubAnnouncements": "最新的Github公告",
+ "SeeAllAnnouncements": "查看所有公告",
+ "LatestBlogPost": "最新博客文章",
+ "Edit": "修改",
+ "ProfileImageChange": "更改资料图片",
+ "BlogItemErrorMessage": "无法从ABP获取最新的博客文章详细信息.",
+ "PlannedReleaseDate": "计划发布日期"
}
-
\ No newline at end of file
+}
\ 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 fa7b216bd0..cb4a8d076c 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
@@ -93,6 +93,7 @@
"DynamicForms": "Dynamic Forms",
"BundlingMinification": "Bundling & Minification",
"BackgroundJobs": "Background Jobs",
+ "BackgroundJobsExplanation": "Define simple classes to execute jobs in background as queued. Use built-in job manager or integrate your own. Hangfire & RabbitMQ integrations are already available.",
"DDDInfrastructure": "DDD Infrastructure",
"DomainDrivenDesignInfrastructure": "Domain Driven Design Infrastructure",
"AutoRESTAPIs": "Auto REST APIs",
@@ -102,6 +103,7 @@
"TestInfrastructure": "Test Infrastructure",
"AuditLoggingEntityHistories": "Audit Logging & Entity Histories",
"ObjectToObjectMapping": "Object to Object Mapping",
+ "ObjectToObjectMappingExplanation": "Object to object mapping abstraction with AutoMapper integration.",
"EmailSMSAbstractions": "Email & SMS Abstractions",
"EmailSMSAbstractionsWithTemplatingSupport": "Email & SMS Abstractions with Templating Support",
"Localization": "Localization",
@@ -156,6 +158,32 @@
"UiFramework": "UI Framework",
"EmailAddress": "Email address",
"Mobile": "Mobile",
- "ReactNative": "React Native"
+ "ReactNative": "React Native",
+ "Strong": "Strong",
+ "Complete": "Complete",
+ "BasedLayeringModel": "Based Layering Model",
+ "Microservice": "Microservice",
+ "Compatible": "Compatible",
+ "MeeTTheABPCommunityInfo": "Our mission is to create an environment where developers can help each other with articles, tutorials, case studies, etc. and meet like-minded people.",
+ "JoinTheABPCommunityInfo": "Get involved with a vibrant community and become a contributor to the ABP Framework!",
+ "AllArticles": "All Articles",
+ "SubmitYourArticle": "Submit Your Article",
+ "DynamicClientProxyDocument": "See the dynamic client proxy documentations for JavaScript & C#.",
+ "EmailSMSAbstractionsDocument": "See the emailing and SMS sending documents for more information.",
+ "CreateProjectWizard": "This wizard creates a new project from the startup template which is properly configured to jump start to your project.",
+ "TieredOption": "Creates a tiered solution where Web and Http API layers are physically separated. If not checked, creates a layered solution which is less complex and suitable for most scenarios.",
+ "SeparateIdentityServerOption": "Separates server side into two applications: First one is for the identity server and the second one is for your server side HTTP API.",
+ "UseslatestPreVersion": "Uses latest pre-release version",
+ "ReadTheDocumentation": "ReadThe Documentation",
+ "Documentation": "Documentation",
+ "GettingStartedTutorial": "Getting Started Tutorial",
+ "ApplicationDevelopmentTutorial": "Application Development Tutorial",
+ "TheStartupTemplate": "The Startup Template",
+ "InstallABPCLIInfo": "ABP CLI is the fastest way to start a new solution with the ABP framework. Install the ABP CLI using a command line window:",
+ "DifferentLevelOfNamespaces": "You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.",
+ "ABPCLIExamplesInfo": "new command creates a layered MVC application with Entity Framework Core as the database provider. However, it has additional options. Examples:",
+ "SeeCliDocumentForMoreInformation": "See the ABP CLI document for more options or select the \"Direct Download\" tab above.",
+ "Optional": "Optional",
+ "LocalFrameworkRef": "Keep local project reference for the framework packages."
}
}
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 7bd02b44ac..4dcb0cad51 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
@@ -89,10 +89,11 @@
"Features": "功能",
"ABPCLI": "ABP CLI",
"Modularity": "模块化",
- "BootstrapTagHelpers": "Bootstrap Tag Helpers",
+ "BootstrapTagHelpers": "Bootstrap 标签助手",
"DynamicForms": "动态表单",
"BundlingMinification": "Bundling & Minification",
"BackgroundJobs": "后台作业",
+ "BackgroundJobsExplanation": "定义简单的类以在队列中在后台执行作业. 使用内置的作业管理器或集成你自己的作业管理器. Hangfire & RabbitMQ集成已经可用.",
"DDDInfrastructure": "DDD基础设施",
"DomainDrivenDesignInfrastructure": "Domain Driven Design基础设施",
"AutoRESTAPIs": "自动REST APIs",
@@ -102,6 +103,7 @@
"TestInfrastructure": "测试基础设施",
"AuditLoggingEntityHistories": "审计日志和实体历史",
"ObjectToObjectMapping": "对象映射",
+ "ObjectToObjectMappingExplanation": "对象到对象映射 抽象AutoMapper集成.",
"EmailSMSAbstractions": "电子邮件和短信抽象",
"EmailSMSAbstractionsWithTemplatingSupport": "具有模板支持的电子邮件和短信抽象",
"Localization": "本土化",
@@ -112,7 +114,7 @@
"DependencyInjection": "依赖注入",
"DependencyInjectionByConventions": "依据约定的依赖注入",
"ABPCLIExplanation": "ABP CLI(命令行界面)是用于对ABP解决方案执行常见操作的命令行工具.",
- "ModularityExplanation": "ABP提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块可能具有实体,服务,数据库集成,API,UI组件等.", //TODO: strong "your own application modules",-
+ "ModularityExplanation": "ABP提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块可能具有实体,服务,数据库集成,API,UI组件等.",
"MultiTenancyExplanation": "ABP框架不仅支持开发多租户应用程序,而且使你的代码几乎无需知道多租户.",
"MultiTenancyExplanation2": "可以自动确定当前租户,将不同租户的数据相互隔离.",
"MultiTenancyExplanation3": "支持单一数据库,或每个租户单独数据库或者混合方式.",
@@ -154,6 +156,34 @@
"SeeTheDocumentForMoreInformation": "查看{0} 文档获得更多信息",
"IndexPageHeroSection": "asp.net core的开源Web应用程序 框架 ",
"UiFramework": "UI框架",
- "EmailAddress": "电子邮件地址"
+ "EmailAddress": "电子邮件地址",
+ "Mobile": "移动",
+ "ReactNative": "React Native",
+ "Strong": "强大的",
+ "Complete": "完整的",
+ "BasedLayeringModel": "基于分层模型",
+ "Microservice": "微服务",
+ "Compatible": "兼容",
+ "MeeTTheABPCommunityInfo": "我们的使命是创建一个环境使开发人员可以在文章,教程,案例研究等方面互相帮助并结识志趣相投的人.",
+ "JoinTheABPCommunityInfo": "参与充满活力的社区并成为ABP框架的贡献者",
+ "AllArticles": "所有的文章",
+ "SubmitYourArticle": "提交你的文章",
+ "DynamicClientProxyDocument": "参阅JavaScript & C#的动态客户端代理文档.",
+ "EmailSMSAbstractionsDocument": "参阅emailing 和 SMS sending 文档获得更多信息.",
+ "CreateProjectWizard": "此向导让你从启动模板创建一个新项目,该启动模板已正确配置为可以快速启动你的项目.",
+ "TieredOption": "创建一个分层解决方案,其中Web和Http API层在物理上是分离的. 如果没有选中则创建一个不那么复杂且适合大多数场景的分层解决方案.",
+ "SeparateIdentityServerOption": "将服务器端分离为两个应用程序:第一个应用程序用于身份服务器,第二个应用程序用于服务器端HTTP API.",
+ "UseslatestPreVersion": "使用最新的预发布版本",
+ "ReadTheDocumentation": "阅读文档",
+ "Documentation": "文档",
+ "GettingStartedTutorial": "入门教程",
+ "ApplicationDevelopmentTutorial": "应用程序开发教程",
+ "TheStartupTemplate": "启动模板",
+ "InstallABPCLIInfo": "ABP CLI是使用ABP框架启动新解决方案的最快方式. 使用命令行窗口安装ABP CLI:",
+ "DifferentLevelOfNamespaces": "你可以使用不同级别的名称空间. 例如 BookStore, Acme.BookStore 或 Acme.Retail.BookStore",
+ "ABPCLIExamplesInfo": "new命令创建一个 分层的MVC应用程序 使用 Entity Framework Core 做为数据库提供程序. 它还有其他选项. 示例:",
+ "SeeCliDocumentForMoreInformation": "参阅 ABP CLI 文档 获得更多选项或选择上方的 \"直接下载\" 标签.",
+ "Optional": "可选的",
+ "LocalFrameworkRef": "保留框架包的本地项目引用."
}
}
\ No newline at end of file
diff --git a/docs/en/Application-Services.md b/docs/en/Application-Services.md
index 9cfec614cb..f48ff9cb5b 100644
--- a/docs/en/Application-Services.md
+++ b/docs/en/Application-Services.md
@@ -445,6 +445,68 @@ These methods are used to convert Entities to DTOs and vice verse. They uses the
* `MapToEntityAsync(TCreateInput)` is used to create an entity from `TCreateInput`.
* `MapToEntityAsync(TUpdateInput, TEntity)` is used to update an existing entity from `TUpdateInput`.
+## Miscellaneous
+
+### Working with Streams
+
+`Stream` object itself is not serializable. So, you may have problems if you directly use `Stream` as the parameter or the return value for your application service. ABP Framework provides a special type, `IRemoteStreamContent` to be used to get or return streams in the application services.
+
+**Example: Application Service Interface that can be used to get and return streams**
+
+````csharp
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Content;
+
+namespace MyProject.Test
+{
+ public interface ITestAppService : IApplicationService
+ {
+ Task Upload(Guid id, IRemoteStreamContent streamContent);
+ Task Download(Guid id);
+ }
+}
+````
+
+**Example: Application Service Implementation that can be used to get and return streams**
+
+````csharp
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Content;
+
+namespace MyProject.Test
+{
+ public class TestAppService : ApplicationService, ITestAppService
+ {
+ public Task Download(Guid id)
+ {
+ var fs = new FileStream("C:\\Temp\\" + id + ".blob", FileMode.OpenOrCreate);
+ return Task.FromResult(
+ (IRemoteStreamContent) new RemoteStreamContent(fs) {
+ ContentType = "application/octet-stream"
+ }
+ );
+ }
+
+ public async Task Upload(Guid id, IRemoteStreamContent streamContent)
+ {
+ using (var fs = new FileStream("C:\\Temp\\" + id + ".blob", FileMode.Create))
+ {
+ await streamContent.GetStream().CopyToAsync(fs);
+ await fs.FlushAsync();
+ }
+ }
+ }
+}
+````
+
+`IRemoteStreamContent` is compatible with the [Auto API Controller](API/Auto-API-Controllers.md) and [Dynamic C# HTTP Proxy](API/Dynamic-CSharp-API-Clients.md) systems.
+
## Lifetime
Lifetime of application services are [transient](Dependency-Injection.md) and they are automatically registered to the dependency injection system.
diff --git a/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md b/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
index 2ae2fe1ce2..4e19a294c1 100644
--- a/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
+++ b/docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
@@ -208,6 +208,13 @@ There are still missing features and modules. However, we are working on it to h
There are some breaking changes with the Blazor UI. If you've built an application and upgrade it, your application might not properly work. See the [ABP Commercial Blazor UI v 3.3 Migration Guide](https://docs.abp.io/en/commercial/3.3/migration-guides/blazor-ui-3_3) for the changes you need to do after upgrading your application.
+#### Known Issues
+
+When you create a new project, profile management doesn't work, you get an exception because it can't find the `/libs/cropperjs/css/cropper.min.css` file. To fix the issue;
+
+* Add `"@volo/account": "^3.3.0-rc.1"` to the `package.json` in the `.Host` project.
+* Run `yarn` (or `npm install`), then `gulp` on a command line terminal in the root folder of the `.Host` project.
+
### Multi-Tenant Social Logins
[Account module](https://commercial.abp.io/modules/Volo.Account.Pro) now supports to manage the social/external logins in the UI. You can **enable/disable** and **set options** in the settings page. It also supports to use **different credentials for the tenants** and it is also **configured on the runtime**.
diff --git a/docs/en/Migration-Guides/Abp-4_0.md b/docs/en/Migration-Guides/Abp-4_0.md
new file mode 100644
index 0000000000..a94b3027a6
--- /dev/null
+++ b/docs/en/Migration-Guides/Abp-4_0.md
@@ -0,0 +1,54 @@
+# ABP Framework 3.3 to 4.0 Migration Guide
+
+## Identity Server Changes
+
+ABP Framework upgrades the [IdentityServer4](https://www.nuget.org/packages/IdentityServer4) library from 3.x to 4.x with the ABP Framework version 4.0. IdentityServer 4.x has a lot of changes, some of them are **breaking changes in the data structure**.
+
+### Database Changes
+
+**So, if you are upgrading from 3.x, then there are some change should be done in your database.**
+
+#### ApiScope
+
+As the **most important breaking change**, Identity Server 4.x places the `ApiScope` as an independent aggregate root. Previously it was a part of the to `ApiResource` aggregate. This requires manual operation. See the *Database Migration* section.
+
+Also, added `Enabled(string)` and `Description(bool,true)` properties.
+
+#### Client
+
+* Added `RequireRequestObject (bool)` and `AllowedIdentityTokenSigningAlgorithms (string)` properties.
+* Changed default value of `RequireConsent` from `true` to `false`.
+* Changed default value of `RequirePkce` from `false` to `true`.
+
+#### DeviceFlowCodes
+
+* Added `SessionId (string)` and `Description (string)` properties.
+
+#### PersistedGrant
+
+* Added `SessionId (string)` and `ShowInDiscoveryDocument (bool, default: true)` properties
+
+#### ApiResource
+
+* Added `AllowedAccessTokenSigningAlgorithms (string)` and `Description (string)` and `ConsumedTime (DateTime?)` properties
+
+#### ApiScope
+
+* Before it was a property of `ApiResource`, now it becomes an independent aggregate root.
+
+## Migrating the Database
+
+> Attention: **Please backup your database** before the migration!
+
+If you are using **Entity Framework Core**, you need to add a new database migration, using the `Add-Migration` command, and apply changes to the database. Please **review the migration** script to understand if it effects your existing data. Otherwise, you may **loose some of your configuration**.
+
+If you haven't customize the `IdentityServerDataSeedContributor` and haven't customized the initial data inside the `IdentityServer*` tables;
+
+1. Update `IdentityServerDataSeedContributor` class by comparing to [the latest code](https://github.com/abpframework/abp/blob/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/IdentityServer/IdentityServerDataSeedContributor.cs). You probably only need to add the `CreateApiScopesAsync` method and the code related to it.
+2. Then you can simply clear all the **table data** in these tables then execute the `DbMigrator` application again to fill it with the new configuration.
+
+If you've customize your IdentityServer configuration in the database or in the seed data, you should understand the changes and upgrade your code/data accordingly.
+
+### Related Resources
+* https://leastprivilege.com/2020/06/19/announcing-identityserver4-v4-0/
+* https://github.com/IdentityServer/IdentityServer4/issues/4592
\ No newline at end of file
diff --git a/docs/en/Repositories.md b/docs/en/Repositories.md
index a222b9d803..0fc80984e7 100644
--- a/docs/en/Repositories.md
+++ b/docs/en/Repositories.md
@@ -142,7 +142,7 @@ var people = _personRepository
You normally want to use `.ToListAsync()`, `.CountAsync()`... instead, to be able to write a **truly async code**.
-However, you see that you can't use these async extension methods in your application or domain layer when you create a new project using the standard [application startup template](Startup-Templates/Application.md), because;
+However, you see that you can't use all the async extension methods in your application or domain layer when you create a new project using the standard [application startup template](Startup-Templates/Application.md), because;
* These async methods **are not standard LINQ methods** and they are defined in the [Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) NuGet package.
* The standard template **doesn't have a reference** to the EF Core package from the domain and application layers, to be independent from the database provider.
@@ -151,9 +151,9 @@ Based on your requirements and development model, you have the following options
> Using async methods is strongly suggested! Don't use sync LINQ methods while executing database queries to be able to develop a scalable application.
-### Option-1: Reference to the EF Core
+### Option-1: Reference to the Database Provider Package
-The easiest solution is to directly add the EF Core package from the project you want to use these async methods.
+**The easiest solution** is to directly add the EF Core package from the project you want to use these async methods.
> Add the [Volo.Abp.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore) NuGet package to your project, which indirectly reference to the EF Core package. This ensures that you use the correct version of the EF Core compatible to the rest of your application.
@@ -183,14 +183,34 @@ var people = ((IMongoQueryable)_personRepository
.ToListAsync();
````
-### Option-2: Custom Repository Methods
+### Option-2: Use the IRepository Async Extension Methods
-You can always create custom repository methods and use the database provider specific APIs, like async extension methods here. See [EF Core](Entity-Framework-Core.md) or [MongoDb](MongoDB.md) document for more info about the custom repositories.
+ABP Framework provides async extension methods for the repositories, just similar to async LINQ extension methods.
-This method is suggested;
+**Example: Use `CountAsync` and `FirstOrDefaultAsync` methods on the repositories**
-* If you want to **completely isolate** your domain & application layers from the database provider.
-* If you develop a **reusable [application module](Modules/Index.md)** and don't want to force to a specific database provider, which should be done as a [best practice](Best-Practices/Index.md).
+````csharp
+var countAll = await _personRepository
+ .CountAsync();
+
+var count = await _personRepository
+ .CountAsync(x => x.Name.StartsWith("A"));
+
+var book1984 = await _bookRepository
+ .FirstOrDefaultAsync(x => x.Name == "John");
+````
+
+The standard LINQ extension methods are supported: *AllAsync, AnyAsync, AverageAsync, ContainsAsync, CountAsync, FirstAsync, FirstOrDefaultAsync, LastAsync, LastOrDefaultAsync, LongCountAsync, MaxAsync, MinAsync, SingleAsync, SingleOrDefaultAsync, SumAsync, ToArrayAsync, ToListAsync*.
+
+This approach still **has a limitation**. You need to call the extension method directly on the repository object. For example, the below usage is **not supported**:
+
+```csharp
+var count = await _bookRepository.Where(x => x.Name.Contains("A")).CountAsync();
+```
+
+This is because the object returned from the `Where` method is not a repository object, it is a standard `IQueryable` interface. See the other options for such cases.
+
+This method is suggested **wherever possible**.
### Option-3: IAsyncQueryableExecuter
@@ -245,6 +265,17 @@ ABP Framework executes the query asynchronously using the actual database provid
This method is suggested;
+* If you want to develop your application code **without depending** on the database provider.
* If you are building a **reusable library** that doesn't have a database provider integration package, but needs to execute an `IQueryable` object in some case.
-For example, ABP Framework uses the `IAsyncQueryableExecuter` in the `CrudAppService` base class (see the [application services](Application-Services.md) document).
\ No newline at end of file
+For example, ABP Framework uses the `IAsyncQueryableExecuter` in the `CrudAppService` base class (see the [application services](Application-Services.md) document).
+
+### Option-4: Custom Repository Methods
+
+You can always create custom repository methods and use the database provider specific APIs, like async extension methods here. See [EF Core](Entity-Framework-Core.md) or [MongoDb](MongoDB.md) document for more info about the custom repositories.
+
+This method is suggested;
+
+* If you want to **completely isolate** your domain & application layers from the database provider.
+* If you develop a **reusable [application module](Modules/Index.md)** and don't want to force to a specific database provider, which should be done as a [best practice](Best-Practices/Index.md).
+
diff --git a/docs/en/Tutorials/Part-10.md b/docs/en/Tutorials/Part-10.md
index 2e0b1c4939..53f19d93dd 100644
--- a/docs/en/Tutorials/Part-10.md
+++ b/docs/en/Tutorials/Part-10.md
@@ -38,7 +38,7 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
We have created `Book` and `Author` functionalities for the book store application. However, currently there is no relation between these entities.
-In this tutorial, we will establish a **1 to N** relation between the `Book` and the `Author`.
+In this tutorial, we will establish a **1 to N** relation between the `Author` and the `Book` entities.
## Add Relation to The Book Entity
diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md
index e52fe7a46d..f4fcf61e25 100644
--- a/docs/en/Tutorials/Part-2.md
+++ b/docs/en/Tutorials/Part-2.md
@@ -583,7 +583,7 @@ When you click to the Books menu item under the Book Store parent, you are being
We will use the [Blazorise library](https://blazorise.com/) as the UI component kit. It is a very powerful library that supports major HTML/CSS frameworks, including the Bootstrap.
-ABP Framework provides a generic base class, `BlazoriseCrudPageBase<...>`, to create CRUD style pages. This base class is compatible to the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `BlazoriseCrudPageBase` to automate the standard CRUD stuff.
+ABP Framework provides a generic base class, `AbpCrudPageBase<...>`, to create CRUD style pages. This base class is compatible to the `ICrudAppService` that was used to build the `IBookAppService`. So, we can inherit from the `AbpCrudPageBase` to automate the code behind for the standard CRUD stuff.
Open the `Books.razor` and replace the content as the following:
@@ -595,7 +595,7 @@ Open the `Books.razor` and replace the content as the following:
@using Acme.BookStore.Localization
@using Microsoft.Extensions.Localization
@inject IStringLocalizer L
-@inherits BlazoriseCrudPageBase
+@inherits AbpCrudPageBase
@@ -645,15 +645,15 @@ Open the `Books.razor` and replace the content as the following:
> If you see some syntax errors, you can ignore them if your application properly built and run. Visual Studio still has some bugs with Blazor.
-* Inherited from the `BlazoriseCrudPageBase` which implements all the CRUD details for us.
+* Inherited from the `AbpCrudPageBase` which implements all the CRUD details for us.
* `Entities`, `TotalCount`, `PageSize`, `OnDataGridReadAsync` are defined in the base blass.
* Injected `IStringLocalizer` (as `L` object) and used for localization.
While the code above pretty easy to understand, you can check the Blazorise [Card](https://blazorise.com/docs/components/card/) and [DataGrid](https://blazorise.com/docs/extensions/datagrid/) documents to understand them better.
-#### About the BlazoriseCrudPageBase
+#### About the AbpCrudPageBase
-We will continue to benefit from the `BlazoriseCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call server side HTTP APIs in your Blazor applications.
+We will continue to benefit from the `AbpCrudPageBase` for the books page. You could just inject the `IBookAppService` and perform all the server side calls yourself (thanks to the [Dynamic C# HTTP API Client Proxy](../API/Dynamic-CSharp-API-Clients.md) system of the ABP Framework). We will do it manually for the authors page to demonstrate how to call server side HTTP APIs in your Blazor applications.
## Run the Final Application
diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md
index 079b9e7cf8..dae7e4bfdb 100644
--- a/docs/en/Tutorials/Part-3.md
+++ b/docs/en/Tutorials/Part-3.md
@@ -1163,7 +1163,7 @@ Clicking the "Delete" action calls the `delete` method which then shows a confir
## Creating a New Book
-In this section, you will learn how to create a new modal dialog form to create a new book. Since we've inherited from the `BlazoriseCrudPage`, we only need to develop the view part.
+In this section, you will learn how to create a new modal dialog form to create a new book. Since we've inherited from the `AbpCrudPageBase`, we only need to develop the view part.
### Add "New Button" Button
@@ -1328,7 +1328,7 @@ We can now define a modal to edit the book. Add the following code to the end of
### AutoMapper Configuration
-The base `BlazoriseCrudPage` uses the [object to object mapping](../Object-To-Object-Mapping.md) system to convert an incoming `BookDto` object to a `CreateUpdateBookDto` object. So, we need to define the mapping.
+The base `AbpCrudPageBase` uses the [object to object mapping](../Object-To-Object-Mapping.md) system to convert an incoming `BookDto` object to a `CreateUpdateBookDto` object. So, we need to define the mapping.
Open the `BookStoreBlazorAutoMapperProfile` inside the `Acme.BookStore.Blazor` project and change the content as the following:
@@ -1382,7 +1382,7 @@ Here the complete code to create the book management CRUD page, that has been de
@using Acme.BookStore.Localization
@using Microsoft.Extensions.Localization
@inject IStringLocalizer L
-@inherits BlazoriseCrudPageBase
+@inherits AbpCrudPageBase
@@ -1392,8 +1392,10 @@ Here the complete code to create the book management CRUD page, that has been de
-
+
@@ -1406,10 +1408,10 @@ Here the complete code to create the book management CRUD page, that has been de
ShowPager="true"
PageSize="PageSize">
-
@@ -1434,7 +1436,7 @@ Here the complete code to create the book management CRUD page, that has been de
Field="@nameof(BookDto.Type)"
Caption="@L["Type"]">
- @L[$"Enum:BookType:{(int) context.Type}"]
+ @L[$"Enum:BookType:{(int)context.Type}"]
@L["NewBook"]
+ Clicked="OpenCreateModalAsync">
+ @L["NewBook"]
+
}
````
@@ -545,7 +547,7 @@ As similar to the *New Book* button, we can use `if` blocks to conditionally sho
You can run and test the permissions. Remove a book related permission from the admin role to see the related button/action disappears from the UI.
-However, ABP Framework caches the permissions of the current user in the client side. So, when you change a permission for yourself, you need to manually **refresh the page** to take the effect. If you don't refresh and try to use the prohibited action you get an HTTP 403 (forbidden) response from the server.
+**ABP Framework caches the permissions** of the current user in the client side. So, when you change a permission for yourself, you need to manually **refresh the page** to take the effect. If you don't refresh and try to use the prohibited action you get an HTTP 403 (forbidden) response from the server.
> Changing a permission for a role or user immediately available on the server side. So, this cache system doesn't cause any security problem.
diff --git a/docs/en/Tutorials/Part-7.md b/docs/en/Tutorials/Part-7.md
index 32c9f6b9a4..5cae52a4b1 100644
--- a/docs/en/Tutorials/Part-7.md
+++ b/docs/en/Tutorials/Part-7.md
@@ -74,6 +74,10 @@ Open the **Package Manager Console** on Visual Studio and ensure that the **Defa
Run the following command to create a new database migration:
+````bash
+Add-Migration "Added_Authors"
+````
+

This will create a new migration class. Then run the `Update-Database` command to create the table on the database.
diff --git a/docs/en/Tutorials/Part-9.md b/docs/en/Tutorials/Part-9.md
index 841d2fb3cb..374efff2b4 100644
--- a/docs/en/Tutorials/Part-9.md
+++ b/docs/en/Tutorials/Part-9.md
@@ -1177,6 +1177,20 @@ We should complete the localizations we've used above. Open the `en.json` file u
"NewAuthor": "New author"
````
+### Run the Application
+
+Run and login to the application. **If you don't see the Authors menu item under the Book Store menu, that means you don't have the permission yet.** Go to the `identity/roles` page, click to the *Actions* button and select the *Permissions* action for the **admin role**:
+
+
+
+As you see, the admin role has no *Author Management* permissions yet. Click to the checkboxes and save the modal to grant the necessary permissions. You will see the *Authors* menu item under the *Book Store* in the main menu, after **refreshing the page**:
+
+
+
+That's all! This is a fully working CRUD page, you can create, edit and delete the authors.
+
+> **Tip**: If you run the `.DbMigrator` console application after defining a new permission, it automatically grants these new permissions to the admin role and you don't need to manually grant the permissions yourself.
+
{{end}}
## The Next Part
diff --git a/docs/en/Tutorials/images/bookstore-authors-blazor-ui.png b/docs/en/Tutorials/images/bookstore-authors-blazor-ui.png
new file mode 100644
index 0000000000..5b9480957d
Binary files /dev/null and b/docs/en/Tutorials/images/bookstore-authors-blazor-ui.png differ
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Auth.md b/docs/en/UI/AspNetCore/JavaScript-API/Auth.md
new file mode 100644
index 0000000000..45af8c4b3e
--- /dev/null
+++ b/docs/en/UI/AspNetCore/JavaScript-API/Auth.md
@@ -0,0 +1,24 @@
+# ASP.NET Core MVC / Razor Pages UI: JavaScript Auth API
+
+Auth API allows you to check permissions (policies) for the current user in the client side. In this way, you can conditionally show/hide UI parts or perform your client side logic based on the current permissions.
+
+> This document only explains the JavaScript API. See the [authorization document](../../../Authorization.md) to understand the ABP authorization & permission system.
+
+## Basic Usage
+
+`abp.auth.isGranted(...)` function is used to check if a permission/policy has granted or not:
+
+````js
+if (abp.auth.isGranted('DeleteUsers')) {
+ //TODO: Delete the user
+} else {
+ alert("You don't have permission to delete a user!");
+}
+````
+
+## Other Fields & Functions
+
+* ` abp.auth.isAnyGranted(...)`: Gets one or more permission/policy names and returns `true` if at least one of them has granted.
+* `abp.auth.areAllGranted(...)`: Gets one or more permission/policy names and returns `true` if all of them of them have granted.
+* `abp.auth.policies`: This is an object where its keys are the permission/policy names. You can find all permission/policy names here.
+* `abp.auth.grantedPolicies`: This is an object where its keys are the permission/policy names. You can find the granted permission/policy names here.
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Block-Busy.md b/docs/en/UI/AspNetCore/JavaScript-API/Block-Busy.md
new file mode 100644
index 0000000000..943a651432
--- /dev/null
+++ b/docs/en/UI/AspNetCore/JavaScript-API/Block-Busy.md
@@ -0,0 +1,56 @@
+# ASP.NET Core MVC / Razor Pages UI: JavaScript UI Block/Busy API
+
+UI Block API disables (blocks) the page or a part of the page.
+
+## Basic Usage
+
+**Example: Block (disable) the complete page**
+
+````js
+abp.ui.block();
+````
+
+**Example: Block (disable) an HTML element**
+
+````js
+abp.ui.block('#MyContainer');
+````
+
+**Example: Enables the previously blocked element or page:**
+
+````js
+abp.ui.unblock();
+````
+
+## Options
+
+`abp.ui.block()` method can get an options object which may contain the following fields:
+
+* `elm`: An optional selector to find the element to be blocked (e.g. `#MyContainerId`). If not provided, the entire page is blocked. The selector can also be directly passed to the `block()` method as shown above.
+* `busy`: Set to `true` to show a progress indicator on the blocked area.
+* `promise`: A promise object with `always` or `finally` callbacks. This can be helpful if you want to automatically unblock the blocked area when a deferred operation completes.
+
+**Example: Block an element with busy indicator**
+
+````js
+abp.ui.block({
+ elm: '#MySection',
+ busy: true
+});
+````
+
+The resulting UI will look like below:
+
+
+
+## setBusy
+
+`abp.ui.setBusy(...)` and `abp.ui.clearBusy()` are shortcut functions if you want to use the block with `busy` option.
+
+**Example: Block with busy**
+
+````js
+abp.ui.setBusy('#MySection');
+````
+
+Then you can use `abp.ui.clearBusy();` to re-enable the busy area/page.
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/CurrentUser.md b/docs/en/UI/AspNetCore/JavaScript-API/CurrentUser.md
new file mode 100644
index 0000000000..038bb9dff1
--- /dev/null
+++ b/docs/en/UI/AspNetCore/JavaScript-API/CurrentUser.md
@@ -0,0 +1,49 @@
+# ASP.NET Core MVC / Razor Pages UI: JavaScript CurrentUser API
+
+`abp.currentUser` is an object that contains information about the current user of the application.
+
+> This document only explains the JavaScript API. See the [CurrentUser document](../../../CurrentUser.md) to get information about the current user in the server side.
+
+## Authenticated User
+
+If the user was authenticated, this object will be something like below:
+
+````js
+{
+ isAuthenticated: true,
+ id: "34f1f4a7-13cc-4b91-84d1-b91c87afa95f",
+ tenantId: null,
+ userName: "john",
+ name: "John",
+ surName: "Nash",
+ email: "john.nash@abp.io",
+ emailVerified: true,
+ phoneNumber: null,
+ phoneNumberVerified: false,
+ roles: ["moderator","supporter"]
+}
+````
+
+So, `abp.currentUser.userName` returns `john` in this case.
+
+## Anonymous User
+
+If the user was not authenticated, this object will be something like below:
+
+````js
+{
+ isAuthenticated: false,
+ id: null,
+ tenantId: null,
+ userName: null,
+ name: null,
+ surName: null,
+ email: null,
+ emailVerified: false,
+ phoneNumber: null,
+ phoneNumberVerified: false,
+ roles: []
+}
+````
+
+You can check `abp.currentUser.isAuthenticated` to understand if the use was authenticated or not.
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/DOM.md b/docs/en/UI/AspNetCore/JavaScript-API/DOM.md
new file mode 100644
index 0000000000..cdd4cef9db
--- /dev/null
+++ b/docs/en/UI/AspNetCore/JavaScript-API/DOM.md
@@ -0,0 +1,117 @@
+# ASP.NET Core MVC / Razor Pages UI: JavaScript DOM API
+
+`abp.dom` (Document Object Model) provides events that you can subscribe to get notified when elements dynamically added to and removed from the page (DOM).
+
+It is especially helpful if you want to initialize the new loaded elements. This is generally needed when you dynamically add elements to DOM (for example, get some HTML elements via AJAX) after page initialization.
+
+> ABP uses the [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to observe the changes made on the DOM.
+
+## Node Events
+
+### onNodeAdded
+
+This event is triggered when an element is added to the DOM. Example:
+
+````js
+abp.dom.onNodeAdded(function(args){
+ console.log(args.$el);
+});
+````
+
+`args` object has the following fields;
+
+* `$el`: The JQuery selection to get the new element inserted to the DOM.
+
+### onNodeRemoved
+
+This event is triggered when an element is removed from the DOM. Example:
+
+````js
+abp.dom.onNodeRemoved(function(args){
+ console.log(args.$el);
+});
+````
+
+`args` object has the following fields;
+
+* `$el`: The JQuery selection to get the element removed from the DOM.
+
+## Pre-Build Initializers
+
+ABP Framework is using the DOM events to initialize some kind of HTML elements when they are added to the DOM after than the page was already initialized.
+
+> Note that the same initializers also work if these elements were already included in the initial DOM. So, whether they are initially or lazy loaded, they work as expected.
+
+### Form Initializer
+
+The Form initializer (defined as `abp.dom.initializers.initializeForms`) initializes the lazy loaded forms;
+
+* Automatically enabled the `unobtrusive` validation on the form.
+* Can automatically show a confirmation message when you submit the form. To enable this feature, just add `data-confirm` attribute with a message (like `data-confirm="Are you sure?"`) to the `form` element.
+* If the `form` element has `data-ajaxForm="true"` attribute, then automatically calls the `.abpAjaxForm()` on the `form` element, to make the form posted via AJAX.
+
+See the [Forms & Validation](../Forms-Validation.md) document for more.
+
+### Script Initializer
+
+Script initializer (`abp.dom.initializers.initializeScript`) can execute a JavaScript code for a DOM element.
+
+**Example: Lazy load a component and execute some code when the element has loaded**
+
+Assume that you've a container to load the element inside:
+
+````html
+
+````
+
+And this is the component that will be loaded via AJAX from the server and inserted into the container:
+
+````html
+
+
Sample message
+
+````
+
+`data-script-class="MyCustomClass"` indicates the JavaScript class that will be used to perform some logic on this element:
+
+`MyCustomClass` is a global object defined as shown below:
+
+````js
+MyCustomClass = function(){
+
+ function initDom($el){
+ $el.css('color', 'red');
+ }
+
+ return {
+ initDom: initDom
+ }
+};
+````
+
+`initDom` is the function that is called by the ABP Framework. The `$el` argument is the loaded HTML element as a JQuery selection.
+
+Finally, you can load the component inside the container after an AJAX call:
+
+````js
+$(function () {
+ setTimeout(function(){
+ $.get('/get-my-element').then(function(response){
+ $('#LazyComponent').html(response);
+ });
+ }, 2000);
+});
+````
+
+Script Initialization system is especially helpful if you don't know how and when the component will be loaded into the DOM. This can be possible if you've developed a reusable UI component in a library and you want the application developer shouldn't care how to initialize the component in different use cases.
+
+> Script initialization doesn't work if the component was loaded in the initial DOM. In this case, you are responsible to initialize it.
+
+### Other Initializers
+
+The following Bootstrap components and libraries are automatically initialized when they are added to the DOM:
+
+* Tooltip
+* Popover
+* Timeage
+
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Features.md b/docs/en/UI/AspNetCore/JavaScript-API/Features.md
new file mode 100644
index 0000000000..e3cd2be445
--- /dev/null
+++ b/docs/en/UI/AspNetCore/JavaScript-API/Features.md
@@ -0,0 +1,15 @@
+# ASP.NET Core MVC / Razor Pages UI: JavaScript Features API
+
+`abp.features` API allows you to check features or get the values of the features on the client side. You can read the current value of a feature in the client side only if it is allowed by the feature definition (on the server side).
+
+> This document only explains the JavaScript API. See the [Features](../../../Features.md) document to understand the ABP Features system.
+
+## Basic Usage
+
+`abp.features.values` can be used to access to the all feature values.
+
+````js
+var excelExportFeatureValue = abp.features.values["ExportingToExcel"];
+````
+
+Then you can check the value of the feature to perform your logic.
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Index.md b/docs/en/UI/AspNetCore/JavaScript-API/Index.md
index dc87739641..3473140392 100644
--- a/docs/en/UI/AspNetCore/JavaScript-API/Index.md
+++ b/docs/en/UI/AspNetCore/JavaScript-API/Index.md
@@ -4,18 +4,16 @@ ABP provides a set of JavaScript APIs for ASP.NET Core MVC / Razor Pages applica
## APIs
-* [abp.ajax](Ajax.md)
-* abp.auth
-* abp.currentUser
-* abp.dom
-* [abp.event](Events.md)
-* abp.features
-* [abp.localization](Localization.md)
-* abp.log
-* [abp.message](Message.md)
-* [abp.notify](Notify.md)
-* abp.security
-* [abp.setting](Settings.md)
-* abp.ui
-* abp.utils
-* abp.ResourceLoader
\ No newline at end of file
+* [AJAX](Ajax.md)
+* [Auth](Auth.md)
+* [CurrentUser](CurrentUser.md)
+* [DOM](DOM.md)
+* [Events](Events.md)
+* [Features](Features.md)
+* [Localization](Localization.md)
+* [Logging](Logging.md)
+* [ResourceLoader](ResourceLoader.md)
+* [Settings](Settings.md)
+* [UI Block/Busy](Block-Busy.md)
+* [UI Message](Message.md)
+* [UI Notification](Notify.md)
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Logging.md b/docs/en/UI/AspNetCore/JavaScript-API/Logging.md
index 9fe48f22da..a46203b019 100644
--- a/docs/en/UI/AspNetCore/JavaScript-API/Logging.md
+++ b/docs/en/UI/AspNetCore/JavaScript-API/Logging.md
@@ -1,3 +1,50 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Logging API
-TODO
\ No newline at end of file
+`abp.log` API is used to write simple logs in the client side.
+
+> The logs are written to console, using the `console.log`, by default.
+
+> This document is for simple client side logging. See the [Logging](../../../Logging.md) document for server side logging system.
+
+## Basic Usage
+
+Use one of the `abp.log.xxx(...)` methods based on the severity of your log message.
+
+````js
+abp.log.debug("Some debug log here..."); //Logging a simple debug message
+abp.log.info({ name: "john", age: 42 }); //Logging an object as an information log
+abp.log.warn("A warning message"); //Logging a warning message
+abp.log.error('An error happens...'); //Error message
+abp.log.fatal('Network connection has gone away!'); //Fatal error
+````
+
+## Log Levels
+
+There are 5 levels for a log message:
+
+* DEBUG = 1
+* INFO = 2
+* WARN = 3
+* ERROR = 4
+* FATAL = 5
+
+These are defined in the `abp.log.levels` object (like `abp.log.levels.WARN`).
+
+### Changing the Current Log Level
+
+You can control the log level as shown below:
+
+````js
+abp.log.level = abp.log.levels.WARN;
+````
+
+Default log level is `DEBUG`.
+
+### Logging with Specifying the Level
+
+Instead of calling `abp.log.info(...)` function, you can use the `abp.log.log` by specifying the log level as a parameter:
+
+````js
+abp.log.log("log message...", abp.log.levels.INFO);
+````
+
diff --git a/docs/en/UI/AspNetCore/JavaScript-API/ResourceLoader.md b/docs/en/UI/AspNetCore/JavaScript-API/ResourceLoader.md
new file mode 100644
index 0000000000..10b8c36f59
--- /dev/null
+++ b/docs/en/UI/AspNetCore/JavaScript-API/ResourceLoader.md
@@ -0,0 +1,40 @@
+# ASP.NET Core MVC / Razor Pages UI: JavaScript Resource Loader API
+
+`abp.ResourceLoader` is a service that can load a JavaScript or CSS file on demand. It guarantees to load the file only once even if you request multiple times.
+
+## Loading Script Files
+
+`abp.ResourceLoader.loadScript(...)` function **loads** a JavaScript file from the server and **executes** it.
+
+**Example: Load a JavaScript file**
+
+````js
+abp.ResourceLoader.loadScript('/Pages/my-script.js');
+````
+
+### Parameters
+
+`loadScript` function can get three parameters;
+
+* `url` (required, `string`): The URL of the script file to be loaded.
+* `loadCallback` (optional, `function`): A callback function that is called once the script is loaded & executed. In this callback you can safely use the code in the script file. This callback is called even if the file was loaded before.
+* `failCallback` (optional, `function`): A callback function that is called if loading the script fails.
+
+**Example: Provide the `loadCallback` argument**
+
+````js
+abp.ResourceLoader.loadScript('/Pages/my-script.js', function() {
+ console.log('successfully loaded :)');
+});
+````
+
+## Loading Style Files
+
+`abp.ResourceLoader.loadStyle(...)` function adds a `link` element to the `head` of the document for the given URL, so the CSS file is automatically loaded by the browser.
+
+**Example: Load a CSS file**
+
+````js
+abp.ResourceLoader.loadStyle('/Pages/my-styles.css');
+````
+
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index 96a5d40475..2409bbc4fc 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -463,10 +463,22 @@
"text": "Localization",
"path": "UI/AspNetCore/JavaScript-API/Localization.md"
},
+ {
+ "text": "Auth",
+ "path": "UI/AspNetCore/JavaScript-API/Auth.md"
+ },
+ {
+ "text": "Current User",
+ "path": "UI/AspNetCore/JavaScript-API/CurrentUser.md"
+ },
{
"text": "Settings",
"path": "UI/AspNetCore/JavaScript-API/Settings.md"
},
+ {
+ "text": "Features",
+ "path": "UI/AspNetCore/JavaScript-API/Features.md"
+ },
{
"text": "AJAX",
"path": "UI/AspNetCore/JavaScript-API/Ajax.md"
@@ -479,9 +491,25 @@
"text": "Notify",
"path": "UI/AspNetCore/JavaScript-API/Notify.md"
},
+ {
+ "text": "Block/Busy",
+ "path": "UI/AspNetCore/JavaScript-API/Block-Busy.md"
+ },
{
"text": "Events",
"path": "UI/AspNetCore/JavaScript-API/Events.md"
+ },
+ {
+ "text": "DOM",
+ "path": "UI/AspNetCore/JavaScript-API/DOM.md"
+ },
+ {
+ "text": "Logging",
+ "path": "UI/AspNetCore/JavaScript-API/Logging.md"
+ },
+ {
+ "text": "Resource Loader",
+ "path": "UI/AspNetCore/JavaScript-API/ResourceLoader.md"
}
]
},
diff --git a/docs/en/images/ui-busy.png b/docs/en/images/ui-busy.png
new file mode 100644
index 0000000000..63a1d7d74a
Binary files /dev/null and b/docs/en/images/ui-busy.png differ
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
index 3d3dd26fae..e4767cc031 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
@@ -1,13 +1,22 @@
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Volo.Abp.Users
+@using Volo.Abp.MultiTenancy
@inject ICurrentUser CurrentUser
+@inject ICurrentTenant CurrentTenant
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
- @CurrentUser.UserName
+ @if (CurrentTenant.Name != null)
+ {
+ @CurrentTenant.Name\@CurrentUser.UserName
+ }
+ else
+ {
+ @CurrentUser.UserName
+ }
@if (Menu != null)
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/wwwroot/theme.js b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/wwwroot/theme.js
deleted file mode 100644
index 8a5b94c7c6..0000000000
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/wwwroot/theme.js
+++ /dev/null
@@ -1,16 +0,0 @@
-$(function () {
- $('.dropdown-menu a.dropdown-toggle').on('click', function (e) {
- if (!$(this).next().hasClass('show')) {
- $(this).parents('.dropdown-menu').first().find('.show').removeClass("show");
- }
-
- var $subMenu = $(this).next(".dropdown-menu");
- $subMenu.toggleClass('show');
-
- $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function (e) {
- $('.dropdown-submenu .show').removeClass("show");
- });
-
- return false;
- });
-});
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
index 8723209c53..ffbb62ba04 100644
--- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
+++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
@@ -184,6 +184,7 @@ namespace Volo.Abp.BlazoriseUI
protected TUpdateViewModel EditingEntity;
protected Modal CreateModal;
protected Modal EditModal;
+ protected List BreadcrumbItems = new List(2);
protected string CreatePolicyName { get; set; }
protected string UpdatePolicyName { get; set; }
@@ -239,6 +240,7 @@ namespace Volo.Abp.BlazoriseUI
protected override async Task OnInitializedAsync()
{
+ await SetBreadcrumbItemsAsync();
await SetPermissionsAsync();
await GetEntitiesAsync();
}
@@ -438,5 +440,10 @@ namespace Volo.Abp.BlazoriseUI
await AuthorizationService.CheckAsync(policyName);
}
+
+ protected virtual ValueTask SetBreadcrumbItemsAsync()
+ {
+ return ValueTask.CompletedTask;
+ }
}
}
diff --git a/framework/src/Volo.Abp.BlazoriseUI/BreadcrumbItem.cs b/framework/src/Volo.Abp.BlazoriseUI/BreadcrumbItem.cs
new file mode 100644
index 0000000000..36417e122a
--- /dev/null
+++ b/framework/src/Volo.Abp.BlazoriseUI/BreadcrumbItem.cs
@@ -0,0 +1,20 @@
+using Blazorise;
+
+namespace Volo.Abp.BlazoriseUI
+{
+ public class BreadcrumbItem
+ {
+ public string Text { get; set; }
+
+ public object Icon { get; set; }
+
+ public string Url { get; set; }
+
+ public BreadcrumbItem(string text, string url = null, object icon = null)
+ {
+ Text = text;
+ Url = url;
+ Icon = icon;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor b/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor
new file mode 100644
index 0000000000..4a569cfe95
--- /dev/null
+++ b/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor
@@ -0,0 +1,37 @@
+
+
+
@Title
+
+ @if (BreadcrumbItems.Any())
+ {
+
+
+ @if (BreadcrumbShowHome)
+ {
+
+
+
+
+
+ }
+ @foreach (var item in BreadcrumbItems)
+ {
+
+
+ @if (item.Icon != null)
+ {
+
+ }
+ @item.Text
+
+
+ }
+
+
+ }
+
+
+ @ChildContent
+
+
+
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs
new file mode 100644
index 0000000000..90e4b0f0c7
--- /dev/null
+++ b/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using Blazorise;
+using Microsoft.AspNetCore.Components;
+
+namespace Volo.Abp.BlazoriseUI.Components
+{
+ public partial class PageHeader : ComponentBase
+ {
+ [Parameter]
+ public string Title { get; set; }
+
+ [Parameter]
+ public bool BreadcrumbShowHome { get; set; } = true;
+
+ [Parameter]
+ public bool BreadcrumbShowCurrent { get; set; } = true;
+
+ [Parameter]
+ public RenderFragment ChildContent { get; set; }
+
+ [Parameter]
+ public List BreadcrumbItems { get; set; }
+
+ public PageHeader()
+ {
+ BreadcrumbItems = new List();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json
index 0e2d25bff1..5f7343e771 100644
--- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json
+++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/zh-Hans.json
@@ -18,6 +18,8 @@
"Description:Abp.Mailing.Smtp.Password": "凭据关联的用户名的密码.",
"Description:Abp.Mailing.Smtp.Domain": "验证凭据的域名或计算机名.",
"Description:Abp.Mailing.Smtp.EnableSsl": "指定 SmtpClient 是否使用安全套接字层 (SSL) 加密连接.",
- "Description:Abp.Mailing.Smtp.UseDefaultCredentials": "控制默认凭据是否随请求一起发送."
+ "Description:Abp.Mailing.Smtp.UseDefaultCredentials": "控制默认凭据是否随请求一起发送.",
+ "TextTemplate:StandardEmailTemplates.Layout": "默认电子邮件模板",
+ "TextTemplate:StandardEmailTemplates.Message": "电子邮件的简单消息模板"
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingDefinitionContext.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingDefinitionContext.cs
index 220e40fe59..59d7acda98 100644
--- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingDefinitionContext.cs
+++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingDefinitionContext.cs
@@ -1,9 +1,13 @@
-namespace Volo.Abp.Settings
+using System.Collections.Generic;
+
+namespace Volo.Abp.Settings
{
public interface ISettingDefinitionContext
{
SettingDefinition GetOrNull(string name);
+
+ IReadOnlyList GetAll();
void Add(params SettingDefinition[] definitions);
}
-}
\ 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 ec85d90ac9..59a680bb81 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
@@ -4,8 +4,10 @@
"Languages": "语言",
"AreYouSure": "你确定吗?",
"Cancel": "取消",
+ "Clear": "清楚",
"Yes": "是",
"No": "否",
+ "Ok": "Ok",
"Close": "关闭",
"Save": "保存",
"SavingWithThreeDot": "保存中...",
@@ -13,6 +15,8 @@
"Delete": "删除",
"Edit": "编辑",
"Refresh": "刷新",
+ "Language": "语言",
+ "LoadMore": "加载更多",
"ProcessingWithThreeDot": "处理中...",
"LoadingWithThreeDot": "加载中...",
"Welcome": "欢迎",
@@ -31,6 +35,8 @@
"PagerInfoEmpty": "显示0个条目中的0到0",
"PagerInfoFiltered": "(从 _MAX_ 总条目中过滤掉)",
"NoDataAvailableInDatatable": "表中没有数据",
+ "Total": "总计",
+ "Selected": "已选",
"PagerShowMenuEntries": "显示 _MENU_ 条数据",
"DatatableActionDropdownDefaultText": "操作",
"ChangePassword": "修改密码",
@@ -38,6 +44,9 @@
"AreYouSureYouWantToCancelEditingWarningMessage": "你有未保存的更改.",
"GoHomePage": "返回主页",
"GoBack": "返回",
- "Search" : "搜索"
+ "Search": "搜索",
+ "ItemWillBeDeletedMessageWithFormat": "{0} 将被删除!",
+ "ItemWillBeDeletedMessage": "此项将被删除!",
+ "ManageYourAccount": "管理你的账户"
}
-}
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hans.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hans.json
new file mode 100644
index 0000000000..f2dfc1f43f
--- /dev/null
+++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "hello": "你好"
+ }
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Localization/zh-Hans.json b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Localization/zh-Hans.json
new file mode 100644
index 0000000000..e34ff86e0b
--- /dev/null
+++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Localization/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "Volo.Abp.Http.DynamicProxying:10001": "业务异常: {0}"
+ }
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/zh-Hans.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/zh-Hans.json
new file mode 100644
index 0000000000..653f0bf803
--- /dev/null
+++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "SeeYou": "再见"
+ }
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/zh-Hans.json b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/zh-Hans.json
new file mode 100644
index 0000000000..e142d8c2c4
--- /dev/null
+++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/zh-Hans.json
@@ -0,0 +1,7 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "HelloText": "你好 {0}",
+ "HowAreYou": "你好吗?"
+ }
+}
\ No newline at end of file
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 93174b979d..cfe4fbaa27 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
@@ -44,6 +44,7 @@
"LoggedOutTitle": "注销",
"LoggedOutText": "你已成功注销并将马上返回.",
"ReturnToText": "点击此处返回到 {0}",
+ "OrLoginWith": "或登录",
"ForgotPassword": "忘记密码?",
"SendPasswordResetLink_Information": "密码重置链接将发送到您的电子邮件以重置密码. 如果您在几分钟内没有收到电子邮件,请重试.",
"PasswordResetMailSentMessage": "帐户恢复电子邮件已发送到您的电子邮件地址. 如果您在15分钟内未在收件箱中看到此电子邮件,请检查垃圾邮件,并标记为非垃圾邮件.",
@@ -56,8 +57,6 @@
"ProfileTab:Password": "更改密码",
"ProfileTab:PersonalInfo": "个人信息",
"ReturnToApplication": "返回到应用程序",
- "Volo.Account:InvalidEmailAddress": "找不到给定的电子邮件地址:{0}",
- "Volo.Account:SelfRegistrationDisabled": "自我注册已禁用!",
-
+ "Volo.Account:InvalidEmailAddress": "找不到给定的电子邮件地址:{0}"
}
-}
+}
\ No newline at end of file
diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs
index 7ed98c0d78..df6eb0e1ae 100644
--- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs
+++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs
@@ -76,9 +76,9 @@ namespace Volo.Abp.Account.Web.Pages.Account
EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin);
- if (context?.ClientId != null)
+ if (context?.Client?.ClientId != null)
{
- var client = await ClientStore.FindEnabledClientByIdAsync(context.ClientId);
+ var client = await ClientStore.FindEnabledClientByIdAsync(context?.Client?.ClientId);
if (client != null)
{
EnableLocalLogin = client.EnableLocalLogin;
@@ -108,7 +108,10 @@ namespace Volo.Abp.Account.Web.Pages.Account
return Redirect("~/");
}
- await Interaction.GrantConsentAsync(context, ConsentResponse.Denied);
+ await Interaction.GrantConsentAsync(context, new ConsentResponse()
+ {
+ Error = AuthorizationError.AccessDenied
+ });
return Redirect(ReturnUrl);
}
diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml
index b61ad00152..8fb7e918e1 100644
--- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml
+++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Consent.cshtml
@@ -96,8 +96,8 @@
}