feat(plugin-multi-tenant): allow custom tenant field per collection (#13553)

This commit is contained in:
Jarrod Flesch
2025-08-27 13:31:20 -04:00
committed by GitHub
parent 13c24afa63
commit 6db07f0c03
7 changed files with 84 additions and 74 deletions

View File

@@ -80,13 +80,18 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
* @default false
*/
isGlobal?: boolean
/**
* Opt out of adding the tenant field and place
* it manually using the `tenantField` export from the plugin
*/
customTenantField?: boolean
/**
* Overrides for the tenant field, will override the entire tenantField configuration
*/
tenantFieldOverrides?: CollectionTenantFieldConfigOverrides
/**
* Set to `false` if you want to manually apply
* the baseFilter
* Set to `false` if you want to manually apply the baseListFilter
* Set to `false` if you want to manually apply the baseFilter
*
* @default true
*/

View File

@@ -53,7 +53,7 @@ export const TenantField = (args: Props) => {
}
}, [args.unique, options, selectedTenantID, setTenant, value, setEntityType, entityType])
if (options.length > 1) {
if (options.length > 1 && !args.field.admin?.hidden && !args.field.hidden) {
return (
<>
<div className={baseClass}>
@@ -64,7 +64,7 @@ export const TenantField = (args: Props) => {
...args.field,
required: true,
}}
readOnly={args.readOnly || args.unique}
readOnly={args.readOnly || args.field.admin?.readOnly || args.unique}
/>
</div>
</div>

View File

@@ -1 +1,2 @@
export { tenantField } from '../fields/tenantField/index.js'
export { tenantsArrayField } from '../fields/tenantsArrayField/index.js'

View File

@@ -1,3 +1,4 @@
export { defaults } from '../defaults.js'
export { filterDocumentsByTenants as getTenantListFilter } from '../filters/filterDocumentsByTenants.js'
export { getGlobalViewRedirect } from '../utilities/getGlobalViewRedirect.js'
export { getTenantAccess } from '../utilities/getTenantAccess.js'

View File

@@ -178,24 +178,24 @@ export const multiTenantPlugin =
tenantsCollectionSlug,
})
const overrides = pluginConfig.collections[collection.slug]?.tenantFieldOverrides
? pluginConfig.collections[collection.slug]?.tenantFieldOverrides
: pluginConfig.tenantField || {}
/**
* Add tenant field to enabled collections
*/
collection.fields.unshift(
tenantField({
name: tenantFieldName,
debug: pluginConfig.debug,
overrides,
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
unique: false,
}),
)
if (pluginConfig.collections[foldersSlug]?.customTenantField !== true) {
/**
* Add tenant field to enabled collections
*/
collection.fields.unshift(
tenantField({
name: tenantFieldName,
debug: pluginConfig.debug,
overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides
? pluginConfig.collections[collection.slug]?.tenantFieldOverrides
: pluginConfig.tenantField || {},
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
unique: false,
}),
)
}
const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {}
if (useBaseFilter ?? useBaseListFilter ?? true) {
@@ -348,24 +348,24 @@ export const multiTenantPlugin =
tenantsCollectionSlug,
})
const overrides = pluginConfig.collections[collection.slug]?.tenantFieldOverrides
? pluginConfig.collections[collection.slug]?.tenantFieldOverrides
: pluginConfig.tenantField || {}
/**
* Add tenant field to enabled collections
*/
collection.fields.unshift(
tenantField({
name: tenantFieldName,
debug: pluginConfig.debug,
overrides,
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
unique: isGlobal,
}),
)
if (pluginConfig.collections[collection.slug]?.customTenantField !== true) {
/**
* Add tenant field to enabled collections
*/
collection.fields.unshift(
tenantField({
name: tenantFieldName,
debug: pluginConfig.debug,
overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides
? pluginConfig.collections[collection.slug]?.tenantFieldOverrides
: pluginConfig.tenantField || {},
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
unique: isGlobal,
}),
)
}
const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {}
if (useBaseFilter ?? useBaseListFilter ?? true) {

View File

@@ -30,6 +30,11 @@ export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
*/
collections: {
[key in CollectionSlug]?: {
/**
* Opt out of adding the tenant field and place
* it manually using the `tenantField` export from the plugin
*/
customTenantField?: boolean
/**
* Set to `true` if you want the collection to behave as a global
*

View File

@@ -102,39 +102,37 @@ export const FolderTypeField = ({
const styles = React.useMemo(() => mergeFieldStyles(field), [field])
return (
<div>
<SelectInput
AfterInput={AfterInput}
BeforeInput={BeforeInput}
className={className}
Description={Description}
description={t('folder:folderTypeDescription')}
Error={Error}
filterOption={
selectFilterOptions
? ({ value }) =>
selectFilterOptions?.some(
(option) => (typeof option === 'string' ? option : option.value) === value,
)
: undefined
}
hasMany={hasMany}
isClearable={isClearable}
isSortable={isSortable}
Label={Label}
label={label}
localized={localized}
name={name}
onChange={onChange}
options={options}
path={path}
placeholder={placeholder}
readOnly={readOnly || disabled}
required={required || (Array.isArray(folderType) && folderType.length > 0)}
showError={showError}
style={styles}
value={value as string | string[]}
/>
</div>
<SelectInput
AfterInput={AfterInput}
BeforeInput={BeforeInput}
className={className}
Description={Description}
description={t('folder:folderTypeDescription')}
Error={Error}
filterOption={
selectFilterOptions
? ({ value }) =>
selectFilterOptions?.some(
(option) => (typeof option === 'string' ? option : option.value) === value,
)
: undefined
}
hasMany={hasMany}
isClearable={isClearable}
isSortable={isSortable}
Label={Label}
label={label}
localized={localized}
name={name}
onChange={onChange}
options={options}
path={path}
placeholder={placeholder}
readOnly={readOnly || disabled}
required={required || (Array.isArray(folderType) && folderType.length > 0)}
showError={showError}
style={styles}
value={value as string | string[]}
/>
)
}