feat(plugin-multi-tenant): allow customization of selector label (#11418)
### What? Allows for custom labeling of the tenant selector shown in the sidebar. Fixes https://github.com/payloadcms/payload/issues/11262
This commit is contained in:
@@ -158,6 +158,16 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
|
|||||||
rowFields?: never
|
rowFields?: never
|
||||||
tenantFieldAccess?: never
|
tenantFieldAccess?: never
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Customize tenant selector label
|
||||||
|
*
|
||||||
|
* Either a string or an object where the keys are locales and the values are the string labels
|
||||||
|
*/
|
||||||
|
tenantSelectorLabel?:
|
||||||
|
| Partial<{
|
||||||
|
[key in AcceptedLanguages]?: string
|
||||||
|
}>
|
||||||
|
| string
|
||||||
/**
|
/**
|
||||||
* The slug for the tenant collection
|
* The slug for the tenant collection
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@payloadcms/eslint-config": "workspace:*",
|
"@payloadcms/eslint-config": "workspace:*",
|
||||||
|
"@payloadcms/translations": "workspace:*",
|
||||||
"@payloadcms/ui": "workspace:*",
|
"@payloadcms/ui": "workspace:*",
|
||||||
"payload": "workspace:*"
|
"payload": "workspace:*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
import type { ReactSelectOption } from '@payloadcms/ui'
|
import type { ReactSelectOption } from '@payloadcms/ui'
|
||||||
import type { ViewTypes } from 'payload'
|
import type { ViewTypes } from 'payload'
|
||||||
|
|
||||||
import { SelectInput } from '@payloadcms/ui'
|
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
|
import { SelectInput, useTranslation } from '@payloadcms/ui'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { SELECT_ALL } from '../../constants.js'
|
import { SELECT_ALL } from '../../constants.js'
|
||||||
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
||||||
|
|
||||||
export const TenantSelector = ({ viewType }: { viewType?: ViewTypes }) => {
|
export const TenantSelector = ({ label, viewType }: { label: string; viewType?: ViewTypes }) => {
|
||||||
const { options, selectedTenantID, setTenant } = useTenantSelection()
|
const { options, selectedTenantID, setTenant } = useTenantSelection()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const handleChange = React.useCallback(
|
const handleChange = React.useCallback(
|
||||||
(option: ReactSelectOption | ReactSelectOption[]) => {
|
(option: ReactSelectOption | ReactSelectOption[]) => {
|
||||||
@@ -33,7 +33,7 @@ export const TenantSelector = ({ viewType }: { viewType?: ViewTypes }) => {
|
|||||||
<div className="tenant-selector">
|
<div className="tenant-selector">
|
||||||
<SelectInput
|
<SelectInput
|
||||||
isClearable={viewType === 'list'}
|
isClearable={viewType === 'list'}
|
||||||
label="Tenant"
|
label={t(label as any)}
|
||||||
name="setTenant"
|
name="setTenant"
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
options={options}
|
options={options}
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ export const defaults = {
|
|||||||
tenantFieldName: 'tenant',
|
tenantFieldName: 'tenant',
|
||||||
tenantsArrayFieldName: 'tenants',
|
tenantsArrayFieldName: 'tenants',
|
||||||
tenantsArrayTenantFieldName: 'tenant',
|
tenantsArrayTenantFieldName: 'tenant',
|
||||||
|
tenantSelectorLabel: 'Tenant',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { AcceptedLanguages } from '@payloadcms/translations'
|
||||||
import type { CollectionConfig, Config } from 'payload'
|
import type { CollectionConfig, Config } from 'payload'
|
||||||
|
|
||||||
import type { MultiTenantPluginConfig } from './types.js'
|
import type { MultiTenantPluginConfig } from './types.js'
|
||||||
@@ -36,6 +37,7 @@ export const multiTenantPlugin =
|
|||||||
pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName
|
pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName
|
||||||
const tenantsArrayTenantFieldName =
|
const tenantsArrayTenantFieldName =
|
||||||
pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName
|
pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName
|
||||||
|
let tenantSelectorLabel = pluginConfig.tenantSelectorLabel || defaults.tenantSelectorLabel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add defaults for admin properties
|
* Add defaults for admin properties
|
||||||
@@ -63,6 +65,36 @@ export const multiTenantPlugin =
|
|||||||
incomingConfig.collections = []
|
incomingConfig.collections = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tenant selector localized labels
|
||||||
|
*/
|
||||||
|
if (pluginConfig.tenantSelectorLabel && typeof pluginConfig.tenantSelectorLabel === 'object') {
|
||||||
|
if (!incomingConfig.i18n) {
|
||||||
|
incomingConfig.i18n = {}
|
||||||
|
}
|
||||||
|
Object.entries(pluginConfig.tenantSelectorLabel).forEach(([_locale, label]) => {
|
||||||
|
const locale = _locale as AcceptedLanguages
|
||||||
|
if (!incomingConfig.i18n) {
|
||||||
|
incomingConfig.i18n = {}
|
||||||
|
}
|
||||||
|
if (!incomingConfig.i18n.translations) {
|
||||||
|
incomingConfig.i18n.translations = {}
|
||||||
|
}
|
||||||
|
if (!incomingConfig.i18n.translations[locale]) {
|
||||||
|
incomingConfig.i18n.translations[locale] = {}
|
||||||
|
}
|
||||||
|
if (!('multiTenant' in incomingConfig.i18n.translations[locale])) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-expect-error
|
||||||
|
incomingConfig.i18n.translations[locale].multiTenant = {}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-expect-error
|
||||||
|
incomingConfig.i18n.translations[locale].multiTenant.selectorLabel = label
|
||||||
|
tenantSelectorLabel = 'multiTenant:selectorLabel'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add tenants array field to users collection
|
* Add tenants array field to users collection
|
||||||
*/
|
*/
|
||||||
@@ -229,7 +261,8 @@ export const multiTenantPlugin =
|
|||||||
|
|
||||||
if (pluginConfig.collections[collection.slug]?.useBaseListFilter !== false) {
|
if (pluginConfig.collections[collection.slug]?.useBaseListFilter !== false) {
|
||||||
/**
|
/**
|
||||||
* Collection baseListFilter with selected tenant constraint (if selected)
|
* Add list filter to enabled collections
|
||||||
|
* - filters results by selected tenant
|
||||||
*/
|
*/
|
||||||
if (!collection.admin) {
|
if (!collection.admin) {
|
||||||
collection.admin = {}
|
collection.admin = {}
|
||||||
@@ -295,6 +328,9 @@ export const multiTenantPlugin =
|
|||||||
* Add tenant selector to admin UI
|
* Add tenant selector to admin UI
|
||||||
*/
|
*/
|
||||||
incomingConfig.admin.components.beforeNavLinks.push({
|
incomingConfig.admin.components.beforeNavLinks.push({
|
||||||
|
clientProps: {
|
||||||
|
label: tenantSelectorLabel,
|
||||||
|
},
|
||||||
path: '@payloadcms/plugin-multi-tenant/client#TenantSelector',
|
path: '@payloadcms/plugin-multi-tenant/client#TenantSelector',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { AcceptedLanguages } from '@payloadcms/translations'
|
||||||
import type { ArrayField, CollectionSlug, Field, RelationshipField, User } from 'payload'
|
import type { ArrayField, CollectionSlug, Field, RelationshipField, User } from 'payload'
|
||||||
|
|
||||||
export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
|
export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
|
||||||
@@ -107,6 +108,16 @@ export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
|
|||||||
rowFields?: never
|
rowFields?: never
|
||||||
tenantFieldAccess?: never
|
tenantFieldAccess?: never
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Customize tenant selector label
|
||||||
|
*
|
||||||
|
* Either a string or an object where the keys are locales and the values are the string labels
|
||||||
|
*/
|
||||||
|
tenantSelectorLabel?:
|
||||||
|
| Partial<{
|
||||||
|
[key in AcceptedLanguages]?: string
|
||||||
|
}>
|
||||||
|
| string
|
||||||
/**
|
/**
|
||||||
* The slug for the tenant collection
|
* The slug for the tenant collection
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"references": [{ "path": "../payload" }, { "path": "../ui"}]
|
"references": [{ "path": "../payload" }, { "path": "../ui"}, { "path": "../translations"}]
|
||||||
}
|
}
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -1031,6 +1031,9 @@ importers:
|
|||||||
'@payloadcms/eslint-config':
|
'@payloadcms/eslint-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../eslint-config
|
version: link:../eslint-config
|
||||||
|
'@payloadcms/translations':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../translations
|
||||||
'@payloadcms/ui':
|
'@payloadcms/ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../ui
|
version: link:../ui
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default buildConfigWithDefaults({
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
tenantSelectorLabel: 'Sites',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
typescript: {
|
typescript: {
|
||||||
|
|||||||
Reference in New Issue
Block a user