diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 77ca49961b..901a5c5cff 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -355,7 +355,7 @@ namespace MyCompany.MyProject } ```` -{0} is the the placeholder to determine current tenant's unique name. +{0} is the placeholder to determine current tenant's unique name. Instead of ``options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com"));`` you can use this shortcut: diff --git a/docs/en/UI/Angular/Multi-Tenancy.md b/docs/en/UI/Angular/Multi-Tenancy.md new file mode 100644 index 0000000000..c71d26adc4 --- /dev/null +++ b/docs/en/UI/Angular/Multi-Tenancy.md @@ -0,0 +1,139 @@ +# Multi Tenancy in Angular UI + +ABP Angular UI supports the multi-tenancy. The following features related to multi-tenancy are available in the startup templates. + + +

+ +

+

Tenants page

+ +On the page above, you can; + +- See the all tenants. +- Create a new tenant. +- Edit an existing tenant. +- Delete a tenant. + + +

+ +

+

Tenant Switching Component

+ +You can switch between existing tenants by using the tenant switching component in the child pages of the `AccountLayoutComponent` (like Login page). Angular UI sends the selected tenant id sends to the backend as `__tenant` header on each request. + + +## Domain Tenant Resolver + +Angular UI can get the tenant name from the app running URL. You can determine the current tenant by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). To do this, you need to set the `application.baseUrl` property in the environment: + +Subdomain resolver: + +```js +// environment.prod.ts + +export const environment = { + //... + application: { + baseUrl: 'https://{0}.mydomain.com/' + }, + //... +} +``` + +**{0}** is the placeholder to determine current tenant's unique name. + +After the configuration above, if your app runs on the `mytenant1.mydomain.com`, the app will get the tenant name as **mytenant1**. Then, the app will call the `/api/abp/multi-tenancy/tenants/by-name/mytenant1` endpoint to check if the tenant exists. If the tenant (mytenant1) exists, the app will keep this tenant data and send its `id` as `__tenant` header to the backend on each request. If the tenant does not exist, the app will not send `__tenant` header to the backend. + +> **Important Note:** If you define the `baseUrl` with the placeholder (**{0}**), the tenant switching component in the child pages of the `AccountLayoutComponent` (like Login page) will be hidden. + + +Domain resolver: + +```js +// environment.prod.ts + +export const environment = { + //... + application: { + baseUrl: 'https://{0}.com/' + }, + //... +} +``` + +After the configuration above, if your app runs on the `mytenant.com`, the app will get the tenant name as **mytenant**. + +### Tenant Specific Remote Endpoints + +The **{0}** placeholder can be put to the API URLs in the environment to determine tenant specific endpoints. + +```js +// environment.prod.ts + +export const environment = { + //... + application: { + baseUrl: 'https://{0}.mydomain.com/', + //... + }, + oAuthConfig: { + issuer: 'https://{0}.ids.mydomain.com', + //... + }, + apis: { + default: { + url: 'https://{0}.api.mydomain.com', + }, + AbpIdentity: { + url: 'https://{0}.identity.mydomain.com', + }, + }, +} +``` + +> **Important Note:** The `application.baseUrl` and the `{0}` placeholder in the value of the `baseUrl` property are required to be able to get tenant from running URL. Other placeholders in API URLs are optional. + +After the configuration above, if your app runs on the `mytenant1.mydomain.com`, the app will get tenant name as **mytenant1** and replace the environment object in `ConfigState` on app initialization as follows: + + +```js +// environment object in ConfigState + +{ + //... + application: { + baseUrl: 'https://mytenant1.mydomain.com/', + //... + }, + oAuthConfig: { + issuer: 'https://mytenant1.ids.mydomain.com', + //... + }, + apis: { + default: { + url: 'https://mytenant1.api.mydomain.com', + }, + AbpIdentity: { + url: 'https://mytenant1.identity.mydomain.com', + }, + }, +} +``` + +After this replacement, the app will use the following URLs: + +- `https://mytenant1.ids.mydomain.com` as IdentityServer URL. +- `https://mytenant1.api.mydomain.com` as default URL. +- `https://mytenant1.identity.mydomain.com` as `AbpIdentity` remote endpoint URL. + +The app sends the `__tenant` header that contains the current tenant id on each request. + +## See Also + +* [Multi Tenancy in ABP](../../Multi-Tenancy.md) + +## What's Next? + +- [Confirmation Popup](./Confirmation-Service.md) diff --git a/docs/en/UI/Angular/Permission-Management.md b/docs/en/UI/Angular/Permission-Management.md index 61169c85b8..8cc7325afd 100644 --- a/docs/en/UI/Angular/Permission-Management.md +++ b/docs/en/UI/Angular/Permission-Management.md @@ -78,4 +78,4 @@ Granted Policies are stored in the `auth` property of `ConfigState`. ## What's Next? -- [Confirmation Popup](./Confirmation-Service.md) \ No newline at end of file +* [Multi Tenancy](./Multi-Tenancy.md) \ No newline at end of file diff --git a/docs/en/UI/Angular/images/tenant-switching-box.png b/docs/en/UI/Angular/images/tenant-switching-box.png new file mode 100644 index 0000000000..ed4d299c55 Binary files /dev/null and b/docs/en/UI/Angular/images/tenant-switching-box.png differ diff --git a/docs/en/UI/Angular/images/tenants-page.png b/docs/en/UI/Angular/images/tenants-page.png new file mode 100644 index 0000000000..8882d58d2f Binary files /dev/null and b/docs/en/UI/Angular/images/tenants-page.png differ diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 09288e013b..421ecff9a9 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -253,7 +253,7 @@ "path": "Blob-Storing-Custom-Provider.md" } ] - } + } ] }, { @@ -426,6 +426,10 @@ "text": "Permission Management", "path": "UI/Angular/Permission-Management.md" }, + { + "text": "Multi Tenancy", + "path": "UI/Angular/Multi-Tenancy.md" + }, { "text": "Confirmation Popup", "path": "UI/Angular/Confirmation-Service.md"