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:
Jarrod Flesch
2025-02-26 22:39:51 -05:00
committed by GitHub
parent 45cee23add
commit 958e195017
9 changed files with 69 additions and 6 deletions

View File

@@ -158,6 +158,16 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
rowFields?: 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
*

View File

@@ -78,6 +78,7 @@
},
"devDependencies": {
"@payloadcms/eslint-config": "workspace:*",
"@payloadcms/translations": "workspace:*",
"@payloadcms/ui": "workspace:*",
"payload": "workspace:*"
},

View File

@@ -2,17 +2,17 @@
import type { ReactSelectOption } from '@payloadcms/ui'
import type { ViewTypes } from 'payload'
import { SelectInput } from '@payloadcms/ui'
import './index.scss'
import { SelectInput, useTranslation } from '@payloadcms/ui'
import React from 'react'
import { SELECT_ALL } from '../../constants.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 { t } = useTranslation()
const handleChange = React.useCallback(
(option: ReactSelectOption | ReactSelectOption[]) => {
@@ -33,7 +33,7 @@ export const TenantSelector = ({ viewType }: { viewType?: ViewTypes }) => {
<div className="tenant-selector">
<SelectInput
isClearable={viewType === 'list'}
label="Tenant"
label={t(label as any)}
name="setTenant"
onChange={handleChange}
options={options}

View File

@@ -3,4 +3,5 @@ export const defaults = {
tenantFieldName: 'tenant',
tenantsArrayFieldName: 'tenants',
tenantsArrayTenantFieldName: 'tenant',
tenantSelectorLabel: 'Tenant',
}

View File

@@ -1,3 +1,4 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import type { CollectionConfig, Config } from 'payload'
import type { MultiTenantPluginConfig } from './types.js'
@@ -36,6 +37,7 @@ export const multiTenantPlugin =
pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName
const tenantsArrayTenantFieldName =
pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName
let tenantSelectorLabel = pluginConfig.tenantSelectorLabel || defaults.tenantSelectorLabel
/**
* Add defaults for admin properties
@@ -63,6 +65,36 @@ export const multiTenantPlugin =
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
*/
@@ -229,7 +261,8 @@ export const multiTenantPlugin =
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) {
collection.admin = {}
@@ -295,6 +328,9 @@ export const multiTenantPlugin =
* Add tenant selector to admin UI
*/
incomingConfig.admin.components.beforeNavLinks.push({
clientProps: {
label: tenantSelectorLabel,
},
path: '@payloadcms/plugin-multi-tenant/client#TenantSelector',
})

View File

@@ -1,3 +1,4 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import type { ArrayField, CollectionSlug, Field, RelationshipField, User } from 'payload'
export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
@@ -107,6 +108,16 @@ export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
rowFields?: 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
*

View File

@@ -1,4 +1,4 @@
{
"extends": "../../tsconfig.base.json",
"references": [{ "path": "../payload" }, { "path": "../ui"}]
"references": [{ "path": "../payload" }, { "path": "../ui"}, { "path": "../translations"}]
}

3
pnpm-lock.yaml generated
View File

@@ -1031,6 +1031,9 @@ importers:
'@payloadcms/eslint-config':
specifier: workspace:*
version: link:../eslint-config
'@payloadcms/translations':
specifier: workspace:*
version: link:../translations
'@payloadcms/ui':
specifier: workspace:*
version: link:../ui

View File

@@ -41,6 +41,7 @@ export default buildConfigWithDefaults({
isGlobal: true,
},
},
tenantSelectorLabel: 'Sites',
}),
],
typescript: {