feat(plugin-multi-tenant): improves tenant assignment flow (#13881)
### Improved tenant assignment flow This PR improves the tenant assignment flow. I know a lot of users liked the previous flow where the field was not injected into the document. But the original flow, confused many of users because the tenant filter (top left) was being used to set the tenant on the document _and_ filter the list view. This change shown below is aiming to solve both of those groups with a slightly different approach. As always, feedback is welcome while we try to really make this plugin work for everyone. https://github.com/user-attachments/assets/ceee8b3a-c5f5-40e9-8648-f583e2412199 Added 2 new localization strings: ``` // shown in the 3 dot menu 'assign-tenant-button-label': 'Assign Tenant', // shown when needing to assign a tenant to a NEW document 'assign-tenant-modal-title': 'Assign "{{title}}"', ``` Removed 2 localization strings: ``` 'confirm-modal-tenant-switch--body', 'confirm-modal-tenant-switch--heading' ```
This commit is contained in:
@@ -136,21 +136,27 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
|
|||||||
translations: {
|
translations: {
|
||||||
[key in AcceptedLanguages]?: {
|
[key in AcceptedLanguages]?: {
|
||||||
/**
|
/**
|
||||||
* @default 'You are about to change ownership from <0>{{fromTenant}}</0> to <0>{{toTenant}}</0>'
|
* Shown inside 3 dot menu on edit document view
|
||||||
*/
|
|
||||||
'confirm-modal-tenant-switch--body'?: string
|
|
||||||
/**
|
|
||||||
* `tenantLabel` defaults to the value of the `nav-tenantSelector-label` translation
|
|
||||||
*
|
*
|
||||||
* @default 'Confirm {{tenantLabel}} change'
|
* @default 'Assign Tenant'
|
||||||
*/
|
*/
|
||||||
'confirm-modal-tenant-switch--heading'?: string
|
'assign-tenant-button-label'?: string
|
||||||
/**
|
/**
|
||||||
|
* Shown as the title of the assign tenant modal
|
||||||
|
*
|
||||||
|
* @default 'Assign "{{title}}"'
|
||||||
|
*/
|
||||||
|
'assign-tenant-modal-title'?: string
|
||||||
|
/**
|
||||||
|
* Shown as the label for the assigned tenant field in the assign tenant modal
|
||||||
|
*
|
||||||
* @default 'Assigned Tenant'
|
* @default 'Assigned Tenant'
|
||||||
*/
|
*/
|
||||||
'field-assignedTenant-label'?: string
|
'field-assignedTenant-label'?: string
|
||||||
/**
|
/**
|
||||||
* @default 'Tenant'
|
* Shown as the label for the global tenant selector in the admin UI
|
||||||
|
*
|
||||||
|
* @default 'Filter by Tenant'
|
||||||
*/
|
*/
|
||||||
'nav-tenantSelector-label'?: string
|
'nav-tenantSelector-label'?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import type { ClientCollectionConfig } from 'payload'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Modal,
|
||||||
|
Pill,
|
||||||
|
PopupList,
|
||||||
|
useConfig,
|
||||||
|
useDocumentInfo,
|
||||||
|
useDocumentTitle,
|
||||||
|
useModal,
|
||||||
|
useTranslation,
|
||||||
|
} from '@payloadcms/ui'
|
||||||
|
import { drawerZBase, useDrawerDepth } from '@payloadcms/ui/elements/Drawer'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
PluginMultiTenantTranslationKeys,
|
||||||
|
PluginMultiTenantTranslations,
|
||||||
|
} from '../../translations/index.js'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
||||||
|
|
||||||
|
export const assignTenantModalSlug = 'assign-tenant-field-modal'
|
||||||
|
const baseClass = 'assign-tenant-field-modal'
|
||||||
|
|
||||||
|
export const AssignTenantFieldTrigger: React.FC = () => {
|
||||||
|
const { openModal } = useModal()
|
||||||
|
const { t } = useTranslation<PluginMultiTenantTranslations, PluginMultiTenantTranslationKeys>()
|
||||||
|
const { options } = useTenantSelection()
|
||||||
|
|
||||||
|
if (options.length <= 1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PopupList.Button onClick={() => openModal(assignTenantModalSlug)}>
|
||||||
|
{t('plugin-multi-tenant:assign-tenant-button-label')}
|
||||||
|
</PopupList.Button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AssignTenantFieldModal: React.FC<{
|
||||||
|
afterModalClose: () => void
|
||||||
|
afterModalOpen: () => void
|
||||||
|
children: React.ReactNode
|
||||||
|
onCancel?: () => void
|
||||||
|
onConfirm?: () => void
|
||||||
|
}> = ({ afterModalClose, afterModalOpen, children, onCancel, onConfirm }) => {
|
||||||
|
const editDepth = useDrawerDepth()
|
||||||
|
const { t } = useTranslation<PluginMultiTenantTranslations, PluginMultiTenantTranslationKeys>()
|
||||||
|
const { collectionSlug } = useDocumentInfo()
|
||||||
|
const { title } = useDocumentTitle()
|
||||||
|
const { getEntityConfig } = useConfig()
|
||||||
|
const collectionConfig = getEntityConfig({ collectionSlug }) as ClientCollectionConfig
|
||||||
|
const { closeModal, isModalOpen: isModalOpenFn } = useModal()
|
||||||
|
const isModalOpen = isModalOpenFn(assignTenantModalSlug)
|
||||||
|
const wasModalOpenRef = React.useRef<boolean>(isModalOpen)
|
||||||
|
|
||||||
|
const onModalConfirm = React.useCallback(() => {
|
||||||
|
if (typeof onConfirm === 'function') {
|
||||||
|
onConfirm()
|
||||||
|
}
|
||||||
|
closeModal(assignTenantModalSlug)
|
||||||
|
}, [onConfirm, closeModal])
|
||||||
|
|
||||||
|
const onModalCancel = React.useCallback(() => {
|
||||||
|
if (typeof onCancel === 'function') {
|
||||||
|
onCancel()
|
||||||
|
}
|
||||||
|
closeModal(assignTenantModalSlug)
|
||||||
|
}, [onCancel, closeModal])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (wasModalOpenRef.current && !isModalOpen) {
|
||||||
|
// modal was open, and now is closed
|
||||||
|
if (typeof afterModalClose === 'function') {
|
||||||
|
afterModalClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasModalOpenRef.current && isModalOpen) {
|
||||||
|
// modal was closed, and now is open
|
||||||
|
if (typeof afterModalOpen === 'function') {
|
||||||
|
afterModalOpen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wasModalOpenRef.current = isModalOpen
|
||||||
|
}, [isModalOpen, onCancel, afterModalClose, afterModalOpen])
|
||||||
|
|
||||||
|
if (!collectionConfig) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className={baseClass}
|
||||||
|
slug={assignTenantModalSlug}
|
||||||
|
style={{
|
||||||
|
zIndex: drawerZBase + editDepth,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={`${baseClass}__bg`} />
|
||||||
|
<div className={`${baseClass}__wrapper`}>
|
||||||
|
<div className={`${baseClass}__header`}>
|
||||||
|
<h3>
|
||||||
|
{t('plugin-multi-tenant:assign-tenant-modal-title', {
|
||||||
|
title,
|
||||||
|
})}
|
||||||
|
</h3>
|
||||||
|
<Pill className={`${baseClass}__collection-pill`} size="small">
|
||||||
|
<>{collectionConfig.labels.singular}</>
|
||||||
|
</Pill>
|
||||||
|
</div>
|
||||||
|
<div className={`${baseClass}__content`}>{children}</div>
|
||||||
|
<div className={`${baseClass}__actions`}>
|
||||||
|
<Button buttonStyle="secondary" margin={false} onClick={onModalCancel}>
|
||||||
|
{t('general:cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button margin={false} onClick={onModalConfirm}>
|
||||||
|
{t('general:confirm')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
@layer payload-default {
|
||||||
|
.assign-tenant-field-modal {
|
||||||
|
pointer-events: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&[open] {
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
.assign-tenant-field-modal__wrapper {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bg {
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: var(--theme-bg);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: calc(var(--base) * 30);
|
||||||
|
min-width: min(500px, calc(100% - (var(--base) * 2)));
|
||||||
|
border-radius: var(--style-radius-m);
|
||||||
|
border: 1px solid var(--theme-elevation-100);
|
||||||
|
background-color: var(--theme-bg);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
padding: calc(var(--base) * 0.75) var(--base);
|
||||||
|
border-bottom: 1px solid var(--theme-elevation-100);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: calc(var(--base) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__collection-pill {
|
||||||
|
align-self: flex-start;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(var(--base) * 0.5);
|
||||||
|
padding: var(--base) var(--base) 0 var(--base);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__controls {
|
||||||
|
display: flex;
|
||||||
|
gap: calc(var(--base) * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: calc(var(--base) * 0.4);
|
||||||
|
padding: var(--base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,24 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import type { RelationshipFieldClientProps, StaticLabel } from 'payload'
|
import type { RelationshipFieldClientProps } from 'payload'
|
||||||
|
|
||||||
import { getTranslation } from '@payloadcms/translations'
|
|
||||||
import {
|
import {
|
||||||
ConfirmationModal,
|
Pill,
|
||||||
RelationshipField,
|
RelationshipField,
|
||||||
Translation,
|
useDocumentInfo,
|
||||||
useField,
|
useField,
|
||||||
useForm,
|
useForm,
|
||||||
useFormModified,
|
useFormModified,
|
||||||
useModal,
|
useModal,
|
||||||
useTranslation,
|
|
||||||
} from '@payloadcms/ui'
|
} from '@payloadcms/ui'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import type {
|
|
||||||
PluginMultiTenantTranslationKeys,
|
|
||||||
PluginMultiTenantTranslations,
|
|
||||||
} from '../../translations/index.js'
|
|
||||||
|
|
||||||
import './index.scss'
|
|
||||||
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
||||||
|
import {
|
||||||
|
AssignTenantFieldModal,
|
||||||
|
assignTenantModalSlug,
|
||||||
|
} from '../AssignTenantFieldModal/index.client.js'
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
const baseClass = 'tenantField'
|
const baseClass = 'tenantField'
|
||||||
|
|
||||||
@@ -30,17 +27,74 @@ type Props = {
|
|||||||
unique?: boolean
|
unique?: boolean
|
||||||
} & RelationshipFieldClientProps
|
} & RelationshipFieldClientProps
|
||||||
|
|
||||||
export const TenantField = (args: Props) => {
|
export const TenantField = ({ debug, unique, ...fieldArgs }: Props) => {
|
||||||
const { entityType, options, selectedTenantID, setEntityType, setTenant } = useTenantSelection()
|
const { entityType, options, selectedTenantID, setEntityType, setTenant } = useTenantSelection()
|
||||||
const { value } = useField<number | string>()
|
const { setValue, showError, value } = useField<(number | string)[] | (number | string)>()
|
||||||
|
const modified = useFormModified()
|
||||||
|
const { isValid: isFormValid, setModified } = useForm()
|
||||||
|
const { id: docID } = useDocumentInfo()
|
||||||
|
const { openModal } = useModal()
|
||||||
|
const isConfirmingRef = React.useRef<boolean>(false)
|
||||||
|
const prevModified = React.useRef(modified)
|
||||||
|
const prevValue = React.useRef<typeof value>(value)
|
||||||
|
const showField =
|
||||||
|
(options.length > 1 && !fieldArgs.field.admin?.hidden && !fieldArgs.field.hidden) || debug
|
||||||
|
|
||||||
|
const onConfirm = React.useCallback(() => {
|
||||||
|
isConfirmingRef.current = true
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const afterModalOpen = React.useCallback(() => {
|
||||||
|
prevModified.current = modified
|
||||||
|
prevValue.current = value
|
||||||
|
}, [modified, value])
|
||||||
|
|
||||||
|
const afterModalClose = React.useCallback(() => {
|
||||||
|
let didChange = true
|
||||||
|
if (isConfirmingRef.current) {
|
||||||
|
// did the values actually change?
|
||||||
|
if (fieldArgs.field.hasMany) {
|
||||||
|
const prev = (prevValue.current || []) as (number | string)[]
|
||||||
|
const newValue = (value || []) as (number | string)[]
|
||||||
|
if (prev.length !== newValue.length) {
|
||||||
|
didChange = true
|
||||||
|
} else {
|
||||||
|
const allMatch = newValue.every((val) => prev.includes(val))
|
||||||
|
if (allMatch) {
|
||||||
|
didChange = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value === prevValue.current) {
|
||||||
|
didChange = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (didChange) {
|
||||||
|
prevModified.current = true
|
||||||
|
prevValue.current = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(prevValue.current, true)
|
||||||
|
setModified(prevModified.current)
|
||||||
|
|
||||||
|
isConfirmingRef.current = false
|
||||||
|
}, [setValue, setModified, value, fieldArgs.field.hasMany])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!entityType) {
|
if (!entityType) {
|
||||||
setEntityType(args.unique ? 'global' : 'document')
|
setEntityType(unique ? 'global' : 'document')
|
||||||
} else {
|
} else {
|
||||||
// unique documents are controlled from the global TenantSelector
|
// unique documents are controlled from the global TenantSelector
|
||||||
if (!args.unique && value) {
|
if (!unique && value) {
|
||||||
if (!selectedTenantID || value !== selectedTenantID) {
|
if (Array.isArray(value)) {
|
||||||
|
if (value.length) {
|
||||||
|
if (!selectedTenantID) {
|
||||||
|
setTenant({ id: value[0], refresh: false })
|
||||||
|
} else if (!value.includes(selectedTenantID)) {
|
||||||
|
setTenant({ id: value[0], refresh: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (selectedTenantID !== value) {
|
||||||
setTenant({ id: value, refresh: false })
|
setTenant({ id: value, refresh: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,137 +105,73 @@ export const TenantField = (args: Props) => {
|
|||||||
setEntityType(undefined)
|
setEntityType(undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [args.unique, options, selectedTenantID, setTenant, value, setEntityType, entityType])
|
}, [unique, options, selectedTenantID, setTenant, value, setEntityType, entityType])
|
||||||
|
|
||||||
if (options.length > 1 && !args.field.admin?.hidden && !args.field.hidden) {
|
React.useEffect(() => {
|
||||||
return (
|
if (unique) {
|
||||||
<>
|
return
|
||||||
<div className={baseClass}>
|
}
|
||||||
<div className={`${baseClass}__wrapper`}>
|
if ((!isFormValid && showError && showField) || (!value && !selectedTenantID)) {
|
||||||
<RelationshipField
|
openModal(assignTenantModalSlug)
|
||||||
{...args}
|
}
|
||||||
field={{
|
}, [isFormValid, showError, showField, openModal, value, docID, selectedTenantID, unique])
|
||||||
...args.field,
|
|
||||||
required: true,
|
if (showField) {
|
||||||
}}
|
if (debug) {
|
||||||
readOnly={args.readOnly || args.field.admin?.readOnly || args.unique}
|
return <TenantFieldInModal debug={debug} fieldArgs={fieldArgs} unique={unique} />
|
||||||
/>
|
}
|
||||||
</div>
|
|
||||||
</div>
|
if (!unique) {
|
||||||
{args.unique ? (
|
/** Editing a non-global tenant document */
|
||||||
<SyncFormModified />
|
return (
|
||||||
) : (
|
<AssignTenantFieldModal
|
||||||
<ConfirmTenantChange fieldLabel={args.field.label} fieldPath={args.path} />
|
afterModalClose={afterModalClose}
|
||||||
)}
|
afterModalOpen={afterModalOpen}
|
||||||
</>
|
onConfirm={onConfirm}
|
||||||
)
|
>
|
||||||
|
<TenantFieldInModal
|
||||||
|
debug={debug}
|
||||||
|
fieldArgs={{
|
||||||
|
...fieldArgs,
|
||||||
|
field: {
|
||||||
|
...fieldArgs.field,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
unique={unique}
|
||||||
|
/>
|
||||||
|
</AssignTenantFieldModal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SyncFormModified />
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmSwitchTenantSlug = 'confirm-switch-tenant'
|
const TenantFieldInModal: React.FC<{
|
||||||
|
debug?: boolean
|
||||||
const ConfirmTenantChange = ({
|
fieldArgs: RelationshipFieldClientProps
|
||||||
fieldLabel,
|
unique?: boolean
|
||||||
fieldPath,
|
}> = ({ debug, fieldArgs, unique }) => {
|
||||||
}: {
|
|
||||||
fieldLabel?: StaticLabel
|
|
||||||
fieldPath: string
|
|
||||||
}) => {
|
|
||||||
const { options, selectedTenantID, setTenant } = useTenantSelection()
|
|
||||||
const { setValue: setTenantFormValue, value: tenantFormValue } = useField<null | number | string>(
|
|
||||||
{ path: fieldPath },
|
|
||||||
)
|
|
||||||
const { setModified } = useForm()
|
|
||||||
const modified = useFormModified()
|
|
||||||
const { i18n, t } = useTranslation<
|
|
||||||
PluginMultiTenantTranslations,
|
|
||||||
PluginMultiTenantTranslationKeys
|
|
||||||
>()
|
|
||||||
const { isModalOpen, openModal } = useModal()
|
|
||||||
|
|
||||||
const prevTenantValueRef = React.useRef<null | number | string>(tenantFormValue || null)
|
|
||||||
const [tenantToConfirm, setTenantToConfirm] = React.useState<null | number | string>(
|
|
||||||
tenantFormValue || null,
|
|
||||||
)
|
|
||||||
|
|
||||||
const fromTenantOption = React.useMemo(() => {
|
|
||||||
if (tenantFormValue) {
|
|
||||||
return options.find((option) => option.value === tenantFormValue)
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}, [options, tenantFormValue])
|
|
||||||
|
|
||||||
const toTenantOption = React.useMemo(() => {
|
|
||||||
if (tenantToConfirm) {
|
|
||||||
return options.find((option) => option.value === tenantToConfirm)
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}, [options, tenantToConfirm])
|
|
||||||
|
|
||||||
const modalIsOpen = isModalOpen(confirmSwitchTenantSlug)
|
|
||||||
const testRef = React.useRef<boolean>(false)
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
// the form value changed
|
|
||||||
if (
|
|
||||||
!modalIsOpen &&
|
|
||||||
tenantFormValue &&
|
|
||||||
prevTenantValueRef.current &&
|
|
||||||
tenantFormValue !== prevTenantValueRef.current
|
|
||||||
) {
|
|
||||||
// revert the form value change temporarily
|
|
||||||
setTenantFormValue(prevTenantValueRef.current, true)
|
|
||||||
// save the tenant to confirm in modal
|
|
||||||
setTenantToConfirm(tenantFormValue)
|
|
||||||
// open confirmation modal
|
|
||||||
openModal(confirmSwitchTenantSlug)
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
tenantFormValue,
|
|
||||||
setTenantFormValue,
|
|
||||||
openModal,
|
|
||||||
setTenant,
|
|
||||||
selectedTenantID,
|
|
||||||
modalIsOpen,
|
|
||||||
modified,
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModal
|
<div className={baseClass}>
|
||||||
body={
|
<div className={`${baseClass}__wrapper`}>
|
||||||
<Translation
|
{debug && (
|
||||||
elements={{
|
<Pill className={`${baseClass}__debug-pill`} pillStyle="success" size="small">
|
||||||
0: ({ children }) => {
|
Multi-Tenant Debug Enabled
|
||||||
return <b>{children}</b>
|
</Pill>
|
||||||
},
|
)}
|
||||||
}}
|
<RelationshipField
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
{...fieldArgs}
|
||||||
// @ts-expect-error
|
field={{
|
||||||
i18nKey="plugin-multi-tenant:confirm-modal-tenant-switch--body"
|
...fieldArgs.field,
|
||||||
t={t}
|
required: true,
|
||||||
variables={{
|
|
||||||
fromTenant: fromTenantOption?.label,
|
|
||||||
toTenant: toTenantOption?.label,
|
|
||||||
}}
|
}}
|
||||||
|
readOnly={fieldArgs.readOnly || fieldArgs.field.admin?.readOnly || unique}
|
||||||
/>
|
/>
|
||||||
}
|
</div>
|
||||||
heading={t('plugin-multi-tenant:confirm-modal-tenant-switch--heading', {
|
</div>
|
||||||
tenantLabel: fieldLabel
|
|
||||||
? getTranslation(fieldLabel, i18n)
|
|
||||||
: t('plugin-multi-tenant:nav-tenantSelector-label'),
|
|
||||||
})}
|
|
||||||
modalSlug={confirmSwitchTenantSlug}
|
|
||||||
onCancel={() => {
|
|
||||||
setModified(testRef.current)
|
|
||||||
}}
|
|
||||||
onConfirm={() => {
|
|
||||||
// set the form value to the tenant to confirm
|
|
||||||
prevTenantValueRef.current = tenantToConfirm
|
|
||||||
setTenantFormValue(tenantToConfirm)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,10 @@
|
|||||||
margin-top: calc(var(--base) * -1.5);
|
margin-top: calc(var(--base) * -1.5);
|
||||||
padding-top: calc(var(--base) * 1.5);
|
padding-top: calc(var(--base) * 1.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__debug-pill {
|
||||||
|
margin-bottom: calc(var(--base) * 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export { AssignTenantFieldTrigger } from '../components/AssignTenantFieldModal/index.client.js'
|
||||||
export { TenantField } from '../components/TenantField/index.client.js'
|
export { TenantField } from '../components/TenantField/index.client.js'
|
||||||
export { WatchTenantCollection } from '../components/WatchTenantCollection/index.js'
|
export { WatchTenantCollection } from '../components/WatchTenantCollection/index.js'
|
||||||
export { useTenantSelection } from '../providers/TenantSelectionProvider/index.client.js'
|
export { useTenantSelection } from '../providers/TenantSelectionProvider/index.client.js'
|
||||||
|
|||||||
@@ -339,6 +339,16 @@ export const multiTenantPlugin =
|
|||||||
collection.disableDuplicate = true
|
collection.disableDuplicate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pluginConfig.debug && !isGlobal) {
|
||||||
|
collection.admin ??= {}
|
||||||
|
collection.admin.components ??= {}
|
||||||
|
collection.admin.components.edit ??= {}
|
||||||
|
collection.admin.components.edit.editMenuItems ??= []
|
||||||
|
collection.admin.components.edit.editMenuItems.push({
|
||||||
|
path: '@payloadcms/plugin-multi-tenant/client#AssignTenantFieldTrigger',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add filter options to all relationship fields
|
* Add filter options to all relationship fields
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const arTranslations: PluginDefaultTranslationsObject = {
|
export const arTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'تعيين المستأجر',
|
||||||
'أنت على وشك تغيير الملكية من <0>{{fromTenant}}</0> إلى <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'قم بتعيين "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'تأكيد تغيير {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'المستأجر المعين',
|
'field-assignedTenant-label': 'المستأجر المعين',
|
||||||
'nav-tenantSelector-label': 'المستأجر',
|
'nav-tenantSelector-label': 'المستأجر',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const azTranslations: PluginDefaultTranslationsObject = {
|
export const azTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Kirayəçiyə təyin et',
|
||||||
'Siz <0>{{fromTenant}}</0>-dən <0>{{toTenant}}</0>-a mülkiyyəti dəyişməyə hazırlaşırsınız',
|
'assign-tenant-modal-title': '"{{title}}" təyin edin',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}} dəyişikliyini təsdiqləyin',
|
|
||||||
'field-assignedTenant-label': 'Təyin edilmiş İcarəçi',
|
'field-assignedTenant-label': 'Təyin edilmiş İcarəçi',
|
||||||
'nav-tenantSelector-label': 'Kirayəçi',
|
'nav-tenantSelector-label': 'Kirayəçi',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const bgTranslations: PluginDefaultTranslationsObject = {
|
export const bgTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Назначаване на Tenant',
|
||||||
'Предстои да промените собствеността от <0>{{fromTenant}}</0> на <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Назначете "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Потвърждаване на промяна в {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Назначен наемател',
|
'field-assignedTenant-label': 'Назначен наемател',
|
||||||
'nav-tenantSelector-label': 'Потребител',
|
'nav-tenantSelector-label': 'Потребител',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const bnBdTranslations: PluginDefaultTranslationsObject = {
|
export const bnBdTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'টেনেন্ট নির্ধারণ করুন',
|
||||||
'আপনি <0>{{fromTenant}}</0> থেকে <0>{{toTenant}}</0> তে মালিকানা পরিবর্তন করতে চলেছেন।',
|
'assign-tenant-modal-title': '"{{title}}" নিয়োগ করুন',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}} পরিবর্তন নিশ্চিত করুন',
|
'field-assignedTenant-label': 'নিযুক্ত টেনেন্ট',
|
||||||
'field-assignedTenant-label': 'নির্ধারিত টেনেন্ট',
|
'nav-tenantSelector-label': 'টেনেন্ট অনুসারে ফিল্টার করুন',
|
||||||
'nav-tenantSelector-label': 'ভাড়াটিয়া',
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const bnInTranslations: PluginDefaultTranslationsObject = {
|
export const bnInTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'টেনেন্ট নিয়োগ করুন',
|
||||||
'আপনি স্বত্বাধিকার পরিবর্তন করতে চলেছেন <0>{{fromTenant}}</0> থেকে <0>{{toTenant}}</0> এ।',
|
'assign-tenant-modal-title': '"{{title}}" এর দায়িত্ব দিন',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}} পরিবর্তন নিশ্চিত করুন',
|
|
||||||
'field-assignedTenant-label': 'নির্ধারিত টেনেন্ট',
|
'field-assignedTenant-label': 'নির্ধারিত টেনেন্ট',
|
||||||
'nav-tenantSelector-label': 'ভাড়াটিয়া',
|
'nav-tenantSelector-label': 'টেনেন্ট অনুসারে ফিল্টার করুন',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const caTranslations: PluginDefaultTranslationsObject = {
|
export const caTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Assignar Tenant',
|
||||||
'Està a punt de canviar la propietat de <0>{{fromTenant}}</0> a <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Assigna "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirmeu el canvi de {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Llogater Assignat',
|
'field-assignedTenant-label': 'Llogater Assignat',
|
||||||
'nav-tenantSelector-label': 'Inquilí',
|
'nav-tenantSelector-label': 'Inquilí',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const csTranslations: PluginDefaultTranslationsObject = {
|
export const csTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Přiřadit nájemce',
|
||||||
'Chystáte se změnit vlastnictví z <0>{{fromTenant}}</0> na <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Přiřadit "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potvrďte změnu {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Přiřazený nájemce',
|
'field-assignedTenant-label': 'Přiřazený nájemce',
|
||||||
'nav-tenantSelector-label': 'Nájemce',
|
'nav-tenantSelector-label': 'Nájemce',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const daTranslations: PluginDefaultTranslationsObject = {
|
export const daTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Tildel Tenant',
|
||||||
'Du er ved at skifte ejerskab fra <0>{{fromTenant}}</0> til <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Tildel "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Bekræft ændring af {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Tildelt Lejer',
|
'field-assignedTenant-label': 'Tildelt Lejer',
|
||||||
'nav-tenantSelector-label': 'Lejer',
|
'nav-tenantSelector-label': 'Lejer',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const deTranslations: PluginDefaultTranslationsObject = {
|
export const deTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Mieter zuweisen',
|
||||||
'Sie sind dabei, den Besitz von <0>{{fromTenant}}</0> zu <0>{{toTenant}}</0> zu ändern.',
|
'assign-tenant-modal-title': 'Weisen Sie "{{title}}" zu',
|
||||||
'confirm-modal-tenant-switch--heading': 'Bestätigung der Änderung von {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Zugewiesener Mandant',
|
'field-assignedTenant-label': 'Zugewiesener Mandant',
|
||||||
'nav-tenantSelector-label': 'Mieter',
|
'nav-tenantSelector-label': 'Mieter',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import type { PluginLanguage } from '../types.js'
|
|||||||
|
|
||||||
export const enTranslations = {
|
export const enTranslations = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Assign Tenant',
|
||||||
'You are about to change ownership from <0>{{fromTenant}}</0> to <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Assign "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirm {{tenantLabel}} change',
|
|
||||||
'field-assignedTenant-label': 'Assigned Tenant',
|
'field-assignedTenant-label': 'Assigned Tenant',
|
||||||
'nav-tenantSelector-label': 'Tenant',
|
'nav-tenantSelector-label': 'Filter by Tenant',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const esTranslations: PluginDefaultTranslationsObject = {
|
export const esTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Asignar Inquilino',
|
||||||
'Está a punto de cambiar la propiedad de <0>{{fromTenant}}</0> a <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Asignar "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirme el cambio de {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Inquilino Asignado',
|
'field-assignedTenant-label': 'Inquilino Asignado',
|
||||||
'nav-tenantSelector-label': 'Inquilino',
|
'nav-tenantSelector-label': 'Inquilino',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const etTranslations: PluginDefaultTranslationsObject = {
|
export const etTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Määra Tenant',
|
||||||
'Te olete just muutmas omandiõigust <0>{{fromTenant}}</0> -lt <0>{{toTenant}}</0> -le.',
|
'assign-tenant-modal-title': 'Määra "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Kinnita {{tenantLabel}} muutus',
|
|
||||||
'field-assignedTenant-label': 'Määratud üürnik',
|
'field-assignedTenant-label': 'Määratud üürnik',
|
||||||
'nav-tenantSelector-label': 'Üürnik',
|
'nav-tenantSelector-label': 'Üürnik',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const faTranslations: PluginDefaultTranslationsObject = {
|
export const faTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'اختصاص Tenant',
|
||||||
'شما در حال تغییر مالکیت از <0>{{fromTenant}}</0> به <0>{{toTenant}}</0> هستید.',
|
'assign-tenant-modal-title': 'اختصاص "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'تأیید تغییر {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'مستاجر اختصاص یافته',
|
'field-assignedTenant-label': 'مستاجر اختصاص یافته',
|
||||||
'nav-tenantSelector-label': 'مستاجر',
|
'nav-tenantSelector-label': 'مستاجر',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const frTranslations: PluginDefaultTranslationsObject = {
|
export const frTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Attribuer un Locataire',
|
||||||
'Vous êtes sur le point de changer la propriété de <0>{{fromTenant}}</0> à <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Attribuer "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirmer le changement de {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Locataire Attribué',
|
'field-assignedTenant-label': 'Locataire Attribué',
|
||||||
'nav-tenantSelector-label': 'Locataire',
|
'nav-tenantSelector-label': 'Locataire',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const heTranslations: PluginDefaultTranslationsObject = {
|
export const heTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'הקצה Tenant',
|
||||||
'אתה עומד לשנות בעלות מ- <0>{{fromTenant}}</0> ל- <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'הקצה "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'אשר שינוי {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'דייר מוקצה',
|
'field-assignedTenant-label': 'דייר מוקצה',
|
||||||
'nav-tenantSelector-label': 'דייר',
|
'nav-tenantSelector-label': 'דייר',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const hrTranslations: PluginDefaultTranslationsObject = {
|
export const hrTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Dodijeli Najmoprimca',
|
||||||
'Na rubu ste promjene vlasništva iz <0>{{fromTenant}}</0> u <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Dodijeli "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potvrdite promjenu {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Dodijeljeni stanar',
|
'field-assignedTenant-label': 'Dodijeljeni stanar',
|
||||||
'nav-tenantSelector-label': 'Podstanar',
|
'nav-tenantSelector-label': 'Podstanar',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const huTranslations: PluginDefaultTranslationsObject = {
|
export const huTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Hozzárendelési bérlő',
|
||||||
'Közel áll ahhoz, hogy megváltoztassa a tulajdonságot <0>{{fromTenant}}</0> -ból <0>{{toTenant}}</0> -ba.',
|
'assign-tenant-modal-title': 'Rendelje hozzá a "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Erősítse meg a {{tenantLabel}} változást',
|
|
||||||
'field-assignedTenant-label': 'Kijelölt Bérlő',
|
'field-assignedTenant-label': 'Kijelölt Bérlő',
|
||||||
'nav-tenantSelector-label': 'Bérlő',
|
'nav-tenantSelector-label': 'Bérlő',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const hyTranslations: PluginDefaultTranslationsObject = {
|
export const hyTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Տեղադրել Tenant',
|
||||||
'Դուք պատրաստվում եք փոխել սեփականությունը <0>{{fromTenant}}</0>-ից <0>{{toTenant}}</0>-ին:',
|
'assign-tenant-modal-title': 'Հանձնել "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Հաստատեք {{tenantLabel}}֊ի փոփոխությունը',
|
|
||||||
'field-assignedTenant-label': 'Հանձնարարված վարձակալ',
|
'field-assignedTenant-label': 'Հանձնարարված վարձակալ',
|
||||||
'nav-tenantSelector-label': 'Տենանտ',
|
'nav-tenantSelector-label': 'Տենանտ',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const idTranslations: PluginDefaultTranslationsObject = {
|
export const idTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Tetapkan Tenant',
|
||||||
'Anda akan mengubah kepemilikan dari <0>{{fromTenant}}</0> ke <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Tetapkan "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Konfirmasi perubahan {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Penyewa yang Ditugaskan',
|
'field-assignedTenant-label': 'Penyewa yang Ditugaskan',
|
||||||
'nav-tenantSelector-label': 'Penyewa',
|
'nav-tenantSelector-label': 'Filter berdasarkan Tenant',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js'
|
||||||
|
|
||||||
|
export const isTranslations: PluginDefaultTranslationsObject = {
|
||||||
|
'plugin-multi-tenant': {
|
||||||
|
'assign-tenant-button-label': 'Úthluta leigjanda',
|
||||||
|
'assign-tenant-modal-title': 'Úthluta "{{title}}"',
|
||||||
|
'field-assignedTenant-label': 'Úthlutaður leigjandi',
|
||||||
|
'nav-tenantSelector-label': 'Síaðu eftir leigjanda',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const is: PluginLanguage = {
|
||||||
|
dateFNSKey: 'is',
|
||||||
|
translations: isTranslations,
|
||||||
|
}
|
||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const itTranslations: PluginDefaultTranslationsObject = {
|
export const itTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Assegna Tenant',
|
||||||
'Stai per cambiare il possesso da <0>{{fromTenant}}</0> a <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Assegna "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Conferma il cambiamento di {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Inquilino Assegnato',
|
'field-assignedTenant-label': 'Inquilino Assegnato',
|
||||||
'nav-tenantSelector-label': 'Inquilino',
|
'nav-tenantSelector-label': 'Inquilino',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const jaTranslations: PluginDefaultTranslationsObject = {
|
export const jaTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'テナントを割り当てる',
|
||||||
'あなたは、<0>{{fromTenant}}</0>から<0>{{toTenant}}</0>への所有権を変更しようとしています。',
|
'assign-tenant-modal-title': '"{{title}}"を割り当てる',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}}の変更を確認します',
|
|
||||||
'field-assignedTenant-label': '割り当てられたテナント',
|
'field-assignedTenant-label': '割り当てられたテナント',
|
||||||
'nav-tenantSelector-label': 'テナント',
|
'nav-tenantSelector-label': 'テナント',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const koTranslations: PluginDefaultTranslationsObject = {
|
export const koTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': '테넌트 지정',
|
||||||
'<0>{{fromTenant}}</0>에서 <0>{{toTenant}}</0>로 소유권을 변경하려고 합니다.',
|
'assign-tenant-modal-title': '"{{title}}"를 지정하십시오.',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}} 변경 확인',
|
|
||||||
'field-assignedTenant-label': '지정된 세입자',
|
'field-assignedTenant-label': '지정된 세입자',
|
||||||
'nav-tenantSelector-label': '세입자',
|
'nav-tenantSelector-label': '세입자',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const ltTranslations: PluginDefaultTranslationsObject = {
|
export const ltTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Priskirkite nuomininką',
|
||||||
'Jūs ketinate pakeisti nuosavybę iš <0>{{fromTenant}}</0> į <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Paskirkite "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Patvirtinkite {{tenantLabel}} pakeitimą',
|
|
||||||
'field-assignedTenant-label': 'Paskirtas nuomininkas',
|
'field-assignedTenant-label': 'Paskirtas nuomininkas',
|
||||||
'nav-tenantSelector-label': 'Nuomininkas',
|
'nav-tenantSelector-label': 'Nuomininkas',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const lvTranslations: PluginDefaultTranslationsObject = {
|
export const lvTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Piešķirt Tenant',
|
||||||
'Jūs gatavojaties mainīt īpašumtiesības no <0>{{fromTenant}}</0> uz <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Piešķirt "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Apstipriniet {{tenantLabel}} izmaiņu',
|
'field-assignedTenant-label': 'Piešķirtais tenants',
|
||||||
'field-assignedTenant-label': 'Piešķirts nomnieks',
|
'nav-tenantSelector-label': 'Filtrēt pēc Nomnieka',
|
||||||
'nav-tenantSelector-label': 'Nomnieks',
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const myTranslations: PluginDefaultTranslationsObject = {
|
export const myTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'အသစ်ထည့်သည့် Tenant',
|
||||||
'Anda akan menukar pemilikan dari <0>{{fromTenant}}</0> kepada <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Tetapkan "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Sahkan perubahan {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'ခွဲစိုက်ထားသော အငှားယူသူ',
|
'field-assignedTenant-label': 'ခွဲစိုက်ထားသော အငှားယူသူ',
|
||||||
'nav-tenantSelector-label': 'Penyewa',
|
'nav-tenantSelector-label': 'Penyewa',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const nbTranslations: PluginDefaultTranslationsObject = {
|
export const nbTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Tildel Leietaker',
|
||||||
'Du er i ferd med å endre eierskap fra <0>{{fromTenant}}</0> til <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Tildel "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Bekreft endring av {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Tildelt leietaker',
|
'field-assignedTenant-label': 'Tildelt leietaker',
|
||||||
'nav-tenantSelector-label': 'Leietaker',
|
'nav-tenantSelector-label': 'Leietaker',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const nlTranslations: PluginDefaultTranslationsObject = {
|
export const nlTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Toewijzen Tenant',
|
||||||
'U staat op het punt om eigenaarschap te wijzigen van <0>{{fromTenant}}</0> naar <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Wijs "{{title}}" toe',
|
||||||
'confirm-modal-tenant-switch--heading': 'Bevestig wijziging van {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Toegewezen Huurder',
|
'field-assignedTenant-label': 'Toegewezen Huurder',
|
||||||
'nav-tenantSelector-label': 'Huurder',
|
'nav-tenantSelector-label': 'Huurder',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const plTranslations: PluginDefaultTranslationsObject = {
|
export const plTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Przypisz Najemcę',
|
||||||
'Za chwilę nastąpi zmiana właściciela z <0>{{fromTenant}}</0> na <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Przypisz "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potwierdź zmianę {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Przypisany Najemca',
|
'field-assignedTenant-label': 'Przypisany Najemca',
|
||||||
'nav-tenantSelector-label': 'Najemca',
|
'nav-tenantSelector-label': 'Najemca',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const ptTranslations: PluginDefaultTranslationsObject = {
|
export const ptTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Atribuir Inquilino',
|
||||||
'Está prestes a mudar a propriedade de <0>{{fromTenant}}</0> para <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Atribuir "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirme a alteração do {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Inquilino Atribuído',
|
'field-assignedTenant-label': 'Inquilino Atribuído',
|
||||||
'nav-tenantSelector-label': 'Inquilino',
|
'nav-tenantSelector-label': 'Inquilino',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const roTranslations: PluginDefaultTranslationsObject = {
|
export const roTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Alocați Tenant',
|
||||||
'Sunteți pe cale să schimbați proprietatea de la <0>{{fromTenant}}</0> la <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Atribuiți "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirmați modificarea {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Locatar Atribuit',
|
'field-assignedTenant-label': 'Locatar Atribuit',
|
||||||
'nav-tenantSelector-label': 'Locatar',
|
'nav-tenantSelector-label': 'Locatar',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const rsTranslations: PluginDefaultTranslationsObject = {
|
export const rsTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Dodeli Tenant',
|
||||||
'Na putu ste da promenite vlasništvo od <0>{{fromTenant}}</0> do <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Dodelite "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potvrdite promenu {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Dodeljen stanar',
|
'field-assignedTenant-label': 'Dodeljen stanar',
|
||||||
'nav-tenantSelector-label': 'Podstanar',
|
'nav-tenantSelector-label': 'Podstanar',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const rsLatinTranslations: PluginDefaultTranslationsObject = {
|
export const rsLatinTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Dodeli Tenant',
|
||||||
'Uskoro ćete promeniti vlasništvo sa <0>{{fromTenant}}</0> na <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Dodeli "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potvrdite promenu {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Dodeljen stanar',
|
'field-assignedTenant-label': 'Dodeljen stanar',
|
||||||
'nav-tenantSelector-label': 'Podstanar',
|
'nav-tenantSelector-label': 'Podstanar',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const ruTranslations: PluginDefaultTranslationsObject = {
|
export const ruTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Назначить Арендатора',
|
||||||
'Вы собираетесь изменить владельца с <0>{{fromTenant}}</0> на <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Назначить "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Подтвердите изменение {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Назначенный Арендатор',
|
'field-assignedTenant-label': 'Назначенный Арендатор',
|
||||||
'nav-tenantSelector-label': 'Арендатор',
|
'nav-tenantSelector-label': 'Арендатор',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const skTranslations: PluginDefaultTranslationsObject = {
|
export const skTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Priradiť nájomcu',
|
||||||
'Chystáte sa zmeniť vlastníctvo z <0>{{fromTenant}}</0> na <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Priradiť "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potvrďte zmenu {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Pridelený nájomca',
|
'field-assignedTenant-label': 'Pridelený nájomca',
|
||||||
'nav-tenantSelector-label': 'Nájomca',
|
'nav-tenantSelector-label': 'Nájomca',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const slTranslations: PluginDefaultTranslationsObject = {
|
export const slTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Dodeli najemnika',
|
||||||
'Pravkar ste na točki, da spremenite lastništvo iz <0>{{fromTenant}}</0> v <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Dodeli "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Potrdite spremembo {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Dodeljen najemnik',
|
'field-assignedTenant-label': 'Dodeljen najemnik',
|
||||||
'nav-tenantSelector-label': 'Najemnik',
|
'nav-tenantSelector-label': 'Najemnik',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const svTranslations: PluginDefaultTranslationsObject = {
|
export const svTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Tilldela Hyresgäst',
|
||||||
'Du är på väg att ändra ägande från <0>{{fromTenant}}</0> till <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Tilldela "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Bekräfta ändring av {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Tilldelad hyresgäst',
|
'field-assignedTenant-label': 'Tilldelad hyresgäst',
|
||||||
'nav-tenantSelector-label': 'Hyresgäst',
|
'nav-tenantSelector-label': 'Hyresgäst',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const taTranslations: PluginDefaultTranslationsObject = {
|
export const taTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'டெனன்டை ஒதுக்குக',
|
||||||
'நீங்கள் உரிமையைக் <0>{{fromTenant}}</0> இலிருந்து <0>{{toTenant}}</0> க்கு மாற்ற உள்ளீர்கள்',
|
'assign-tenant-modal-title': '"{{title}}"ஐ ஒதுக்கி வைக்கவும்.',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}} மாற்றத்தை உறுதிப்படுத்தவும்',
|
|
||||||
'field-assignedTenant-label': 'ஒதுக்கப்பட்ட Tenant',
|
'field-assignedTenant-label': 'ஒதுக்கப்பட்ட Tenant',
|
||||||
'nav-tenantSelector-label': 'Tenant',
|
'nav-tenantSelector-label': 'Tenant',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const thTranslations: PluginDefaultTranslationsObject = {
|
export const thTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'กำหนดผู้เช่า',
|
||||||
'คุณกำลังจะเปลี่ยนสิทธิ์การเป็นเจ้าของจาก <0>{{fromTenant}}</0> ไปยัง <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'มอบหมาย "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'ยืนยันการเปลี่ยนแปลง {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'ผู้เช่าที่ได้รับการกำหนด',
|
'field-assignedTenant-label': 'ผู้เช่าที่ได้รับการกำหนด',
|
||||||
'nav-tenantSelector-label': 'ผู้เช่า',
|
'nav-tenantSelector-label': 'ผู้เช่า',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const trTranslations: PluginDefaultTranslationsObject = {
|
export const trTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Kiracı Ata',
|
||||||
"<0>{{fromTenant}}</0>'den <0>{{toTenant}}</0>'ye sahipliği değiştirmek üzeresiniz.",
|
'assign-tenant-modal-title': '"{{title}}" atayın.',
|
||||||
'confirm-modal-tenant-switch--heading': '{{tenantLabel}} değişikliğini onayla',
|
|
||||||
'field-assignedTenant-label': 'Atanan Kiracı',
|
'field-assignedTenant-label': 'Atanan Kiracı',
|
||||||
'nav-tenantSelector-label': 'Kiracı',
|
'nav-tenantSelector-label': 'Kiracı',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const ukTranslations: PluginDefaultTranslationsObject = {
|
export const ukTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Призначити орендаря',
|
||||||
'Ви збираєтеся змінити власність з <0>{{fromTenant}}</0> на <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Призначте "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Підтвердіть зміну {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Призначений орендар',
|
'field-assignedTenant-label': 'Призначений орендар',
|
||||||
'nav-tenantSelector-label': 'Орендар',
|
'nav-tenantSelector-label': 'Орендар',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const viTranslations: PluginDefaultTranslationsObject = {
|
export const viTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': 'Giao Tenant',
|
||||||
'Bạn sắp chuyển quyền sở hữu từ <0>{{fromTenant}}</0> đến <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': 'Gán "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': 'Xác nhận thay đổi {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': 'Người thuê đã được chỉ định',
|
'field-assignedTenant-label': 'Người thuê đã được chỉ định',
|
||||||
'nav-tenantSelector-label': 'Người thuê',
|
'nav-tenantSelector-label': 'Người thuê',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const zhTranslations: PluginDefaultTranslationsObject = {
|
export const zhTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': '分配租户',
|
||||||
'您即将从<0>{{fromTenant}}</0>更改为<0>{{toTenant}}</0>的所有权',
|
'assign-tenant-modal-title': '分配"{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': '确认更改{{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': '指定租户',
|
'field-assignedTenant-label': '指定租户',
|
||||||
'nav-tenantSelector-label': '租户',
|
'nav-tenantSelector-label': '租户',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.j
|
|||||||
|
|
||||||
export const zhTwTranslations: PluginDefaultTranslationsObject = {
|
export const zhTwTranslations: PluginDefaultTranslationsObject = {
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body':
|
'assign-tenant-button-label': '指派租戶',
|
||||||
'您即將變更擁有者,從 <0>{{fromTenant}}</0> 切換為 <0>{{toTenant}}</0>',
|
'assign-tenant-modal-title': '將 "{{title}}"',
|
||||||
'confirm-modal-tenant-switch--heading': '確認變更 {{tenantLabel}}',
|
|
||||||
'field-assignedTenant-label': '指派的租用戶',
|
'field-assignedTenant-label': '指派的租用戶',
|
||||||
'nav-tenantSelector-label': '租戶',
|
'nav-tenantSelector-label': '租戶',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import type { enTranslations } from './languages/en.js'
|
|||||||
|
|
||||||
export type PluginLanguage = Language<{
|
export type PluginLanguage = Language<{
|
||||||
'plugin-multi-tenant': {
|
'plugin-multi-tenant': {
|
||||||
'confirm-modal-tenant-switch--body': string
|
'assign-tenant-button-label': string
|
||||||
'confirm-modal-tenant-switch--heading': string
|
'assign-tenant-modal-title': string
|
||||||
'field-assignedTenant-label': string
|
'field-assignedTenant-label': string
|
||||||
'nav-tenantSelector-label': string
|
'nav-tenantSelector-label': string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,21 +92,27 @@ export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
|
|||||||
translations: {
|
translations: {
|
||||||
[key in AcceptedLanguages]?: {
|
[key in AcceptedLanguages]?: {
|
||||||
/**
|
/**
|
||||||
* @default 'You are about to change ownership from <0>{{fromTenant}}</0> to <0>{{toTenant}}</0>'
|
* Shown inside 3 dot menu on edit document view
|
||||||
*/
|
|
||||||
'confirm-modal-tenant-switch--body'?: string
|
|
||||||
/**
|
|
||||||
* `tenantLabel` defaults to the value of the `nav-tenantSelector-label` translation
|
|
||||||
*
|
*
|
||||||
* @default 'Confirm {{tenantLabel}} change'
|
* @default 'Assign Tenant'
|
||||||
*/
|
*/
|
||||||
'confirm-modal-tenant-switch--heading'?: string
|
'assign-tenant-button-label'?: string
|
||||||
/**
|
/**
|
||||||
|
* Shown as the title of the assign tenant modal
|
||||||
|
*
|
||||||
|
* @default 'Assign "{{title}}"'
|
||||||
|
*/
|
||||||
|
'assign-tenant-modal-title'?: string
|
||||||
|
/**
|
||||||
|
* Shown as the label for the assigned tenant field in the assign tenant modal
|
||||||
|
*
|
||||||
* @default 'Assigned Tenant'
|
* @default 'Assigned Tenant'
|
||||||
*/
|
*/
|
||||||
'field-assignedTenant-label'?: string
|
'field-assignedTenant-label'?: string
|
||||||
/**
|
/**
|
||||||
* @default 'Tenant'
|
* Shown as the label for the global tenant selector in the admin UI
|
||||||
|
*
|
||||||
|
* @default 'Filter by Tenant'
|
||||||
*/
|
*/
|
||||||
'nav-tenantSelector-label'?: string
|
'nav-tenantSelector-label'?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ function createErrorsFromMessage(message: string): {
|
|||||||
if (errors.length === 1) {
|
if (errors.length === 1) {
|
||||||
return {
|
return {
|
||||||
errors,
|
errors,
|
||||||
message: `${intro}:`,
|
message: `${intro}: `,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ import type { BrowserContext, Page } from '@playwright/test'
|
|||||||
import type { TypeWithID } from 'payload'
|
import type { TypeWithID } from 'payload'
|
||||||
|
|
||||||
import { expect, test } from '@playwright/test'
|
import { expect, test } from '@playwright/test'
|
||||||
import { devUser } from 'credentials.js'
|
|
||||||
import { openDocControls } from 'helpers/e2e/openDocControls.js'
|
|
||||||
import { openNav } from 'helpers/e2e/toggleNav.js'
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { wait } from 'payload/shared'
|
import { wait } from 'payload/shared'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
@@ -12,8 +9,8 @@ import { fileURLToPath } from 'url'
|
|||||||
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
|
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
|
||||||
import type { Config, ReadOnlyCollection, RestrictedVersion } from './payload-types.js'
|
import type { Config, ReadOnlyCollection, RestrictedVersion } from './payload-types.js'
|
||||||
|
|
||||||
|
import { devUser } from '../credentials.js'
|
||||||
import {
|
import {
|
||||||
closeNav,
|
|
||||||
ensureCompilationIsDone,
|
ensureCompilationIsDone,
|
||||||
exactText,
|
exactText,
|
||||||
initPageConsoleErrorCatch,
|
initPageConsoleErrorCatch,
|
||||||
@@ -21,6 +18,8 @@ import {
|
|||||||
} from '../helpers.js'
|
} from '../helpers.js'
|
||||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||||
import { login } from '../helpers/e2e/auth/login.js'
|
import { login } from '../helpers/e2e/auth/login.js'
|
||||||
|
import { openDocControls } from '../helpers/e2e/openDocControls.js'
|
||||||
|
import { closeNav, openNav } from '../helpers/e2e/toggleNav.js'
|
||||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||||
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -7,15 +7,12 @@ import type {
|
|||||||
} from '@playwright/test'
|
} from '@playwright/test'
|
||||||
import type { Config } from 'payload'
|
import type { Config } from 'payload'
|
||||||
|
|
||||||
import { formatAdminURL } from '@payloadcms/ui/shared'
|
|
||||||
import { expect } from '@playwright/test'
|
import { expect } from '@playwright/test'
|
||||||
import { defaults } from 'payload'
|
import { defaults } from 'payload'
|
||||||
import { wait } from 'payload/shared'
|
import { wait } from 'payload/shared'
|
||||||
import shelljs from 'shelljs'
|
import shelljs from 'shelljs'
|
||||||
import { setTimeout } from 'timers/promises'
|
import { setTimeout } from 'timers/promises'
|
||||||
|
|
||||||
import { devUser } from './credentials.js'
|
|
||||||
import { openNav } from './helpers/e2e/toggleNav.js'
|
|
||||||
import { POLL_TOPASS_TIMEOUT } from './playwright.config.js'
|
import { POLL_TOPASS_TIMEOUT } from './playwright.config.js'
|
||||||
|
|
||||||
export type AdminRoutes = NonNullable<Config['admin']>['routes']
|
export type AdminRoutes = NonNullable<Config['admin']>['routes']
|
||||||
@@ -220,14 +217,6 @@ export async function openCreateDocDrawer(page: Page, fieldSelector: string): Pr
|
|||||||
await wait(500) // wait for drawer form state to initialize
|
await wait(500) // wait for drawer form state to initialize
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function closeNav(page: Page): Promise<void> {
|
|
||||||
if (!(await page.locator('.template-default.template-default--nav-open').isVisible())) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await page.locator('.nav-toggler >> visible=true').click()
|
|
||||||
await expect(page.locator('.template-default.template-default--nav-open')).toBeHidden()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function openLocaleSelector(page: Page): Promise<void> {
|
export async function openLocaleSelector(page: Page): Promise<void> {
|
||||||
const button = page.locator('.localizer button.popup-button')
|
const button = page.locator('.localizer button.popup-button')
|
||||||
const popup = page.locator('.localizer .popup.popup--active')
|
const popup = page.locator('.localizer .popup.popup--active')
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function assertToastErrors({
|
|||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const isSingleError = errors.length === 1
|
const isSingleError = errors.length === 1
|
||||||
const message = isSingleError
|
const message = isSingleError
|
||||||
? 'The following field is invalid:'
|
? 'The following field is invalid: '
|
||||||
: `The following fields are invalid (${errors.length}):`
|
: `The following fields are invalid (${errors.length}):`
|
||||||
|
|
||||||
// Check the intro message text
|
// Check the intro message text
|
||||||
|
|||||||
@@ -24,3 +24,17 @@ export async function openNav(page: Page): Promise<void> {
|
|||||||
await expect(page.locator('.nav--nav-animate[inert], .nav--nav-hydrated[inert]')).toBeHidden()
|
await expect(page.locator('.nav--nav-animate[inert], .nav--nav-hydrated[inert]')).toBeHidden()
|
||||||
await expect(page.locator('.template-default.template-default--nav-open')).toBeVisible()
|
await expect(page.locator('.template-default.template-default--nav-open')).toBeVisible()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function closeNav(page: Page): Promise<void> {
|
||||||
|
// wait for the preferences/media queries to either open or close the nav
|
||||||
|
await expect(page.locator('.template-default--nav-hydrated')).toBeVisible()
|
||||||
|
|
||||||
|
// check to see if the nav is already closed and if so, return early
|
||||||
|
if (!(await page.locator('.template-default.template-default--nav-open').isVisible())) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// playwright: get first element with .nav-toggler which is VISIBLE (not hidden), could be 2 elements with .nav-toggler on mobile and desktop but only one is visible
|
||||||
|
await page.locator('.nav-toggler >> visible=true').click()
|
||||||
|
await expect(page.locator('.template-default.template-default--nav-open')).toBeHidden()
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default buildConfigWithDefaults({
|
|||||||
onInit: seed,
|
onInit: seed,
|
||||||
plugins: [
|
plugins: [
|
||||||
multiTenantPlugin<ConfigType>({
|
multiTenantPlugin<ConfigType>({
|
||||||
debug: true,
|
// debug: true,
|
||||||
userHasAccessToAllTenants: (user) => Boolean(user.roles?.includes('admin')),
|
userHasAccessToAllTenants: (user) => Boolean(user.roles?.includes('admin')),
|
||||||
useTenantsCollectionAccess: false,
|
useTenantsCollectionAccess: false,
|
||||||
tenantField: {
|
tenantField: {
|
||||||
@@ -52,9 +52,9 @@ export default buildConfigWithDefaults({
|
|||||||
i18n: {
|
i18n: {
|
||||||
translations: {
|
translations: {
|
||||||
en: {
|
en: {
|
||||||
'field-assignedTenant-label': 'Currently Assigned Site',
|
'field-assignedTenant-label': 'Site',
|
||||||
'nav-tenantSelector-label': 'Filter By Site',
|
'nav-tenantSelector-label': 'Filter by Site',
|
||||||
'confirm-modal-tenant-switch--heading': 'Confirm Site Change',
|
'assign-tenant-button-label': 'Assign Site',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import * as path from 'path'
|
|||||||
import { wait } from 'payload/shared'
|
import { wait } from 'payload/shared'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
|
||||||
import type { Config } from './payload-types.js'
|
import type { Config } from './payload-types.js'
|
||||||
|
|
||||||
import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
|
import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
|
||||||
@@ -18,7 +19,7 @@ import {
|
|||||||
getSelectInputValue,
|
getSelectInputValue,
|
||||||
selectInput,
|
selectInput,
|
||||||
} from '../helpers/e2e/selectInput.js'
|
} from '../helpers/e2e/selectInput.js'
|
||||||
import { openNav } from '../helpers/e2e/toggleNav.js'
|
import { closeNav, openNav } from '../helpers/e2e/toggleNav.js'
|
||||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||||
import { reInitializeDB } from '../helpers/reInitializeDB.js'
|
import { reInitializeDB } from '../helpers/reInitializeDB.js'
|
||||||
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
|
||||||
@@ -37,16 +38,19 @@ test.describe('Multi Tenant', () => {
|
|||||||
let menuItemsURL: AdminUrlUtil
|
let menuItemsURL: AdminUrlUtil
|
||||||
let usersURL: AdminUrlUtil
|
let usersURL: AdminUrlUtil
|
||||||
let tenantsURL: AdminUrlUtil
|
let tenantsURL: AdminUrlUtil
|
||||||
|
let payload: PayloadTestSDK<Config>
|
||||||
|
|
||||||
test.beforeAll(async ({ browser }, testInfo) => {
|
test.beforeAll(async ({ browser }, testInfo) => {
|
||||||
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
||||||
|
|
||||||
const { serverURL: serverFromInit, payload } = await initPayloadE2ENoConfig<Config>({ dirname })
|
const { serverURL: serverFromInit, payload: payloadFromInit } =
|
||||||
|
await initPayloadE2ENoConfig<Config>({ dirname })
|
||||||
serverURL = serverFromInit
|
serverURL = serverFromInit
|
||||||
globalMenuURL = new AdminUrlUtil(serverURL, menuSlug)
|
globalMenuURL = new AdminUrlUtil(serverURL, menuSlug)
|
||||||
menuItemsURL = new AdminUrlUtil(serverURL, menuItemsSlug)
|
menuItemsURL = new AdminUrlUtil(serverURL, menuItemsSlug)
|
||||||
usersURL = new AdminUrlUtil(serverURL, usersSlug)
|
usersURL = new AdminUrlUtil(serverURL, usersSlug)
|
||||||
tenantsURL = new AdminUrlUtil(serverURL, tenantsSlug)
|
tenantsURL = new AdminUrlUtil(serverURL, tenantsSlug)
|
||||||
|
payload = payloadFromInit
|
||||||
autosaveGlobalURL = new AdminUrlUtil(serverURL, autosaveGlobalSlug)
|
autosaveGlobalURL = new AdminUrlUtil(serverURL, autosaveGlobalSlug)
|
||||||
|
|
||||||
const context = await browser.newContext()
|
const context = await browser.newContext()
|
||||||
@@ -72,7 +76,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
|
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await page.goto(tenantsURL.list)
|
await page.goto(tenantsURL.list)
|
||||||
|
|
||||||
@@ -99,8 +103,8 @@ test.describe('Multi Tenant', () => {
|
|||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(tenantsURL.list)
|
await setTenantFilter({
|
||||||
await selectTenant({
|
urlUtil: tenantsURL,
|
||||||
page,
|
page,
|
||||||
tenant: 'Blue Dog',
|
tenant: 'Blue Dog',
|
||||||
})
|
})
|
||||||
@@ -127,7 +131,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(menuItemsURL.list)
|
await page.goto(menuItemsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.collection-list .table .cell-name', {
|
page.locator('.collection-list .table .cell-name', {
|
||||||
@@ -147,8 +151,8 @@ test.describe('Multi Tenant', () => {
|
|||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(menuItemsURL.list)
|
await setTenantFilter({
|
||||||
await selectTenant({
|
urlUtil: menuItemsURL,
|
||||||
page,
|
page,
|
||||||
tenant: 'Blue Dog',
|
tenant: 'Blue Dog',
|
||||||
})
|
})
|
||||||
@@ -172,7 +176,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(menuItemsURL.list)
|
await page.goto(menuItemsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.collection-list .table .cell-name', {
|
page.locator('.collection-list .table .cell-name', {
|
||||||
@@ -188,7 +192,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(menuItemsURL.list)
|
await page.goto(menuItemsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.collection-list .table .cell-name', {
|
page.locator('.collection-list .table .cell-name', {
|
||||||
@@ -207,7 +211,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(usersURL.list)
|
await page.goto(usersURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.collection-list .table .cell-email', {
|
page.locator('.collection-list .table .cell-email', {
|
||||||
@@ -233,8 +237,8 @@ test.describe('Multi Tenant', () => {
|
|||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(usersURL.list)
|
await setTenantFilter({
|
||||||
await selectTenant({
|
urlUtil: usersURL,
|
||||||
page,
|
page,
|
||||||
tenant: 'Blue Dog',
|
tenant: 'Blue Dog',
|
||||||
})
|
})
|
||||||
@@ -267,7 +271,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(menuItemsURL.list)
|
await page.goto(menuItemsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await goToListDoc({
|
await goToListDoc({
|
||||||
page,
|
page,
|
||||||
@@ -287,7 +291,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
.toBe('Blue Dog')
|
.toBe('Blue Dog')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should prompt for confirmation upon tenant switching', async () => {
|
test('should allow tenant switching cancellation', async () => {
|
||||||
await loginClientSide({
|
await loginClientSide({
|
||||||
page,
|
page,
|
||||||
serverURL,
|
serverURL,
|
||||||
@@ -295,7 +299,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(menuItemsURL.list)
|
await page.goto(menuItemsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await goToListDoc({
|
await goToListDoc({
|
||||||
page,
|
page,
|
||||||
@@ -307,14 +311,46 @@ test.describe('Multi Tenant', () => {
|
|||||||
await selectDocumentTenant({
|
await selectDocumentTenant({
|
||||||
page,
|
page,
|
||||||
tenant: 'Steel Cat',
|
tenant: 'Steel Cat',
|
||||||
|
action: 'cancel',
|
||||||
|
payload,
|
||||||
})
|
})
|
||||||
|
|
||||||
const confirmationModal = page.locator('#confirm-switch-tenant')
|
await expect(page.locator('#action-save')).toBeDisabled()
|
||||||
await expect(confirmationModal).toBeVisible()
|
|
||||||
await expect(
|
await page.goto(menuItemsURL.list)
|
||||||
confirmationModal.getByText('You are about to change ownership from Blue Dog to Steel Cat'),
|
await expect
|
||||||
).toBeVisible()
|
.poll(async () => {
|
||||||
|
return await getSelectedTenantFilterName({ page, payload })
|
||||||
|
})
|
||||||
|
.toBe('Blue Dog')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should allow tenant switching confirmation', async () => {
|
||||||
|
await loginClientSide({
|
||||||
|
page,
|
||||||
|
serverURL,
|
||||||
|
data: credentials.admin,
|
||||||
|
})
|
||||||
|
|
||||||
|
await page.goto(menuItemsURL.list)
|
||||||
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
|
await goToListDoc({
|
||||||
|
page,
|
||||||
|
cellClass: '.cell-name',
|
||||||
|
textToMatch: 'Spicy Mac',
|
||||||
|
urlUtil: menuItemsURL,
|
||||||
|
})
|
||||||
|
|
||||||
|
await selectDocumentTenant({
|
||||||
|
page,
|
||||||
|
payload,
|
||||||
|
tenant: 'Steel Cat',
|
||||||
|
})
|
||||||
|
|
||||||
|
await saveDocAndAssert(page)
|
||||||
|
})
|
||||||
|
|
||||||
test('should filter internal links in Lexical editor', async () => {
|
test('should filter internal links in Lexical editor', async () => {
|
||||||
await loginClientSide({
|
await loginClientSide({
|
||||||
page,
|
page,
|
||||||
@@ -324,6 +360,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
await page.goto(menuItemsURL.create)
|
await page.goto(menuItemsURL.create)
|
||||||
await selectDocumentTenant({
|
await selectDocumentTenant({
|
||||||
page,
|
page,
|
||||||
|
payload,
|
||||||
tenant: 'Blue Dog',
|
tenant: 'Blue Dog',
|
||||||
})
|
})
|
||||||
const editor = page.locator('[data-lexical-editor="true"]')
|
const editor = page.locator('[data-lexical-editor="true"]')
|
||||||
@@ -364,8 +401,8 @@ test.describe('Multi Tenant', () => {
|
|||||||
serverURL,
|
serverURL,
|
||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
await page.goto(tenantsURL.list)
|
await setTenantFilter({
|
||||||
await selectTenant({
|
urlUtil: tenantsURL,
|
||||||
page,
|
page,
|
||||||
tenant: 'Blue Dog',
|
tenant: 'Blue Dog',
|
||||||
})
|
})
|
||||||
@@ -381,8 +418,8 @@ test.describe('Multi Tenant', () => {
|
|||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(tenantsURL.list)
|
await setTenantFilter({
|
||||||
await selectTenant({
|
urlUtil: tenantsURL,
|
||||||
page,
|
page,
|
||||||
tenant: 'Blue Dog',
|
tenant: 'Blue Dog',
|
||||||
})
|
})
|
||||||
@@ -391,7 +428,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
|
|
||||||
// Attempt to switch tenants with unsaved changes
|
// Attempt to switch tenants with unsaved changes
|
||||||
await page.fill('#field-title', 'New Global Menu Name')
|
await page.fill('#field-title', 'New Global Menu Name')
|
||||||
await selectTenant({
|
await switchGlobalDocTenant({
|
||||||
page,
|
page,
|
||||||
tenant: 'Steel Cat',
|
tenant: 'Steel Cat',
|
||||||
})
|
})
|
||||||
@@ -424,15 +461,25 @@ test.describe('Multi Tenant', () => {
|
|||||||
data: credentials.admin,
|
data: credentials.admin,
|
||||||
})
|
})
|
||||||
await page.goto(tenantsURL.list)
|
await page.goto(tenantsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
await page.goto(autosaveGlobalURL.list)
|
await page.goto(autosaveGlobalURL.list)
|
||||||
await expect(page.locator('.doc-header__title')).toBeVisible()
|
await expect(page.locator('.doc-header__title')).toBeVisible()
|
||||||
const globalTenant = await getGlobalTenant({ page })
|
const docID = (await page.locator('.render-title').getAttribute('data-doc-id')) as string
|
||||||
await expect
|
await expect.poll(() => docID).not.toBeUndefined()
|
||||||
.poll(async () => {
|
const globalTenant = await getSelectedTenantFilterName({ page, payload })
|
||||||
return await getDocumentTenant({ page })
|
const autosaveGlobal = await payload.find({
|
||||||
})
|
collection: autosaveGlobalSlug,
|
||||||
.toBe(globalTenant)
|
where: {
|
||||||
|
id: {
|
||||||
|
equals: docID,
|
||||||
|
},
|
||||||
|
'tenant.name': {
|
||||||
|
equals: globalTenant,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await expect.poll(() => autosaveGlobal?.totalDocs).toBe(1)
|
||||||
|
await expect.poll(() => autosaveGlobal?.docs?.[0]?.tenant).toBeDefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -515,7 +562,7 @@ test.describe('Multi Tenant', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await page.goto(tenantsURL.list)
|
await page.goto(tenantsURL.list)
|
||||||
await clearGlobalTenant({ page })
|
await clearTenantFilter({ page })
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.collection-list .table .cell-name', {
|
page.locator('.collection-list .table .cell-name', {
|
||||||
@@ -602,24 +649,6 @@ test.describe('Multi Tenant', () => {
|
|||||||
/**
|
/**
|
||||||
* Helper Functions
|
* Helper Functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function getGlobalTenant({ page }: { page: Page }): Promise<string | undefined> {
|
|
||||||
await openNav(page)
|
|
||||||
return await getSelectInputValue<false>({
|
|
||||||
selectLocator: page.locator('.tenant-selector'),
|
|
||||||
multiSelect: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getDocumentTenant({ page }: { page: Page }): Promise<string | undefined> {
|
|
||||||
await openNav(page)
|
|
||||||
return await getSelectInputValue<false>({
|
|
||||||
selectLocator: page.locator('#field-tenant'),
|
|
||||||
multiSelect: false,
|
|
||||||
valueLabelClass: '.relationship--single-value',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getTenantOptions({ page }: { page: Page }): Promise<string[]> {
|
async function getTenantOptions({ page }: { page: Page }): Promise<string[]> {
|
||||||
await openNav(page)
|
await openNav(page)
|
||||||
return await getSelectInputOptions({
|
return await getSelectInputOptions({
|
||||||
@@ -627,33 +656,124 @@ async function getTenantOptions({ page }: { page: Page }): Promise<string[]> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openAssignTenantModal({
|
||||||
|
page,
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
page: Page
|
||||||
|
payload: PayloadTestSDK<Config>
|
||||||
|
}): Promise<void> {
|
||||||
|
const assignTenantModal = page.locator('#assign-tenant-field-modal')
|
||||||
|
|
||||||
|
const globalTenant = await getSelectedTenantFilterName({ page, payload })
|
||||||
|
if (!globalTenant) {
|
||||||
|
await expect(assignTenantModal).toBeVisible()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the assign tenant modal
|
||||||
|
const docControlsPopup = page.locator('.doc-controls__popup')
|
||||||
|
const docControlsButton = docControlsPopup.locator('.popup-button')
|
||||||
|
await expect(docControlsButton).toBeVisible()
|
||||||
|
await docControlsButton.click()
|
||||||
|
|
||||||
|
const assignTenantButtonLocator = docControlsPopup.locator('button', { hasText: 'Assign Site' })
|
||||||
|
await expect(assignTenantButtonLocator).toBeVisible()
|
||||||
|
await assignTenantButtonLocator.click()
|
||||||
|
|
||||||
|
await expect(assignTenantModal).toBeVisible()
|
||||||
|
}
|
||||||
|
|
||||||
async function selectDocumentTenant({
|
async function selectDocumentTenant({
|
||||||
page,
|
page,
|
||||||
tenant,
|
tenant,
|
||||||
|
action = 'confirm',
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
action?: 'cancel' | 'confirm'
|
||||||
|
page: Page
|
||||||
|
payload: PayloadTestSDK<Config>
|
||||||
|
tenant: string
|
||||||
|
}): Promise<void> {
|
||||||
|
await closeNav(page)
|
||||||
|
await openAssignTenantModal({ page, payload })
|
||||||
|
await selectInput({
|
||||||
|
selectLocator: page.locator('.tenantField'),
|
||||||
|
option: tenant,
|
||||||
|
multiSelect: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const assignTenantModal = page.locator('#assign-tenant-field-modal')
|
||||||
|
if (action === 'confirm') {
|
||||||
|
await assignTenantModal.locator('button', { hasText: 'Confirm' }).click()
|
||||||
|
await expect(assignTenantModal).toBeHidden()
|
||||||
|
} else {
|
||||||
|
await assignTenantModal.locator('button', { hasText: 'Cancel' }).click()
|
||||||
|
await expect(assignTenantModal).toBeHidden()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSelectedTenantFilterName({
|
||||||
|
page,
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
page: Page
|
||||||
|
payload: PayloadTestSDK<Config>
|
||||||
|
}): Promise<string | undefined> {
|
||||||
|
const cookies = await page.context().cookies()
|
||||||
|
const tenantIDFromCookie = cookies.find((c) => c.name === 'payload-tenant')?.value
|
||||||
|
if (tenantIDFromCookie) {
|
||||||
|
const tenant = await payload.find({
|
||||||
|
collection: 'tenants',
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
equals: tenantIDFromCookie,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return tenant?.docs?.[0]?.name || undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setTenantFilter({
|
||||||
|
page,
|
||||||
|
tenant,
|
||||||
|
urlUtil,
|
||||||
|
}: {
|
||||||
|
page: Page
|
||||||
|
tenant: string
|
||||||
|
urlUtil: AdminUrlUtil
|
||||||
|
}): Promise<void> {
|
||||||
|
await page.goto(urlUtil.list)
|
||||||
|
await openNav(page)
|
||||||
|
await selectInput({
|
||||||
|
selectLocator: page.locator('.tenant-selector'),
|
||||||
|
option: tenant,
|
||||||
|
multiSelect: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function switchGlobalDocTenant({
|
||||||
|
page,
|
||||||
|
tenant,
|
||||||
}: {
|
}: {
|
||||||
page: Page
|
page: Page
|
||||||
tenant: string
|
tenant: string
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
await openNav(page)
|
await openNav(page)
|
||||||
return selectInput({
|
await selectInput({
|
||||||
selectLocator: page.locator('.tenantField'),
|
|
||||||
option: tenant,
|
|
||||||
multiSelect: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selectTenant({ page, tenant }: { page: Page; tenant: string }): Promise<void> {
|
|
||||||
await openNav(page)
|
|
||||||
return selectInput({
|
|
||||||
selectLocator: page.locator('.tenant-selector'),
|
selectLocator: page.locator('.tenant-selector'),
|
||||||
option: tenant,
|
option: tenant,
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clearGlobalTenant({ page }: { page: Page }): Promise<void> {
|
async function clearTenantFilter({ page }: { page: Page }): Promise<void> {
|
||||||
await openNav(page)
|
await openNav(page)
|
||||||
return clearSelectInput({
|
await clearSelectInput({
|
||||||
selectLocator: page.locator('.tenant-selector'),
|
selectLocator: page.locator('.tenant-selector'),
|
||||||
})
|
})
|
||||||
|
await closeNav(page)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export interface FoodItem {
|
|||||||
root: {
|
root: {
|
||||||
type: string;
|
type: string;
|
||||||
children: {
|
children: {
|
||||||
type: string;
|
type: any;
|
||||||
version: number;
|
version: number;
|
||||||
[k: string]: unknown;
|
[k: string]: unknown;
|
||||||
}[];
|
}[];
|
||||||
|
|||||||
Reference in New Issue
Block a user