@payloadcms/plugin-multi-tenant 3.44.0 → 3.45.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TenantField/index.client.d.ts.map +1 -1
- package/dist/components/TenantField/index.client.js +17 -8
- package/dist/components/TenantField/index.client.js.map +1 -1
- package/dist/components/TenantSelector/index.d.ts.map +1 -1
- package/dist/components/TenantSelector/index.js +37 -16
- package/dist/components/TenantSelector/index.js.map +1 -1
- package/dist/components/WatchTenantCollection/index.d.ts.map +1 -1
- package/dist/components/WatchTenantCollection/index.js +17 -23
- package/dist/components/WatchTenantCollection/index.js.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.client.d.ts +25 -6
- package/dist/providers/TenantSelectionProvider/index.client.d.ts.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.client.js +74 -61
- package/dist/providers/TenantSelectionProvider/index.client.js.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.d.ts.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.js +2 -0
- package/dist/providers/TenantSelectionProvider/index.js.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/components/TenantField/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAA;AAG3D,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,cAAc,CAAA;AAIrB,KAAK,KAAK,GAAG;IACX,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,4BAA4B,CAAA;AAEhC,eAAO,MAAM,WAAW,SAAU,KAAK,
|
|
1
|
+
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/components/TenantField/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAA;AAG3D,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,cAAc,CAAA;AAIrB,KAAK,KAAK,GAAG;IACX,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,4BAA4B,CAAA;AAEhC,eAAO,MAAM,WAAW,SAAU,KAAK,6BA2DtC,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { RelationshipField, useField } from '@payloadcms/ui';
|
|
3
|
+
import { RelationshipField, useField, useFormModified } from '@payloadcms/ui';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js';
|
|
6
6
|
import './index.scss';
|
|
@@ -8,7 +8,8 @@ const baseClass = 'tenantField';
|
|
|
8
8
|
export const TenantField = (args)=>{
|
|
9
9
|
const { debug, unique } = args;
|
|
10
10
|
const { setValue, value } = useField();
|
|
11
|
-
const
|
|
11
|
+
const modified = useFormModified();
|
|
12
|
+
const { options, selectedTenantID, setEntityType: setEntityType, setModified, setTenant } = useTenantSelection();
|
|
12
13
|
const hasSetValueRef = React.useRef(false);
|
|
13
14
|
React.useEffect(()=>{
|
|
14
15
|
if (!hasSetValueRef.current) {
|
|
@@ -29,7 +30,7 @@ export const TenantField = (args)=>{
|
|
|
29
30
|
hasSetValueRef.current = true;
|
|
30
31
|
} else if (!value || value !== selectedTenantID) {
|
|
31
32
|
// Update the field on the document value when the tenant is changed
|
|
32
|
-
setValue(selectedTenantID);
|
|
33
|
+
setValue(selectedTenantID, !value || value === selectedTenantID);
|
|
33
34
|
}
|
|
34
35
|
}, [
|
|
35
36
|
value,
|
|
@@ -40,15 +41,23 @@ export const TenantField = (args)=>{
|
|
|
40
41
|
unique
|
|
41
42
|
]);
|
|
42
43
|
React.useEffect(()=>{
|
|
43
|
-
|
|
44
|
-
setPreventRefreshOnChange(true);
|
|
45
|
-
}
|
|
44
|
+
setEntityType(unique ? 'global' : 'document');
|
|
46
45
|
return ()=>{
|
|
47
|
-
|
|
46
|
+
setEntityType(undefined);
|
|
48
47
|
};
|
|
49
48
|
}, [
|
|
50
49
|
unique,
|
|
51
|
-
|
|
50
|
+
setEntityType
|
|
51
|
+
]);
|
|
52
|
+
React.useEffect(()=>{
|
|
53
|
+
// sync form modified state with the tenant selection provider context
|
|
54
|
+
setModified(modified);
|
|
55
|
+
return ()=>{
|
|
56
|
+
setModified(false);
|
|
57
|
+
};
|
|
58
|
+
}, [
|
|
59
|
+
modified,
|
|
60
|
+
setModified
|
|
52
61
|
]);
|
|
53
62
|
if (debug) {
|
|
54
63
|
return /*#__PURE__*/ _jsxs("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/TenantField/index.client.tsx"],"sourcesContent":["'use client'\n\nimport type { RelationshipFieldClientProps } from 'payload'\n\nimport { RelationshipField, useField } from '@payloadcms/ui'\nimport React from 'react'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\nimport './index.scss'\n\nconst baseClass = 'tenantField'\n\ntype Props = {\n debug?: boolean\n unique?: boolean\n} & RelationshipFieldClientProps\n\nexport const TenantField = (args: Props) => {\n const { debug, unique } = args\n const { setValue, value } = useField<number | string>()\n const {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/TenantField/index.client.tsx"],"sourcesContent":["'use client'\n\nimport type { RelationshipFieldClientProps } from 'payload'\n\nimport { RelationshipField, useField, useFormModified } from '@payloadcms/ui'\nimport React from 'react'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\nimport './index.scss'\n\nconst baseClass = 'tenantField'\n\ntype Props = {\n debug?: boolean\n unique?: boolean\n} & RelationshipFieldClientProps\n\nexport const TenantField = (args: Props) => {\n const { debug, unique } = args\n const { setValue, value } = useField<number | string>()\n const modified = useFormModified()\n const {\n options,\n selectedTenantID,\n setEntityType: setEntityType,\n setModified,\n setTenant,\n } = useTenantSelection()\n\n const hasSetValueRef = React.useRef(false)\n\n React.useEffect(() => {\n if (!hasSetValueRef.current) {\n // set value on load\n if (value && value !== selectedTenantID) {\n setTenant({ id: value, refresh: unique })\n } else {\n // in the document view, the tenant field should always have a value\n const defaultValue = selectedTenantID || options[0]?.value\n setTenant({ id: defaultValue, refresh: unique })\n }\n hasSetValueRef.current = true\n } else if (!value || value !== selectedTenantID) {\n // Update the field on the document value when the tenant is changed\n setValue(selectedTenantID, !value || value === selectedTenantID)\n }\n }, [value, selectedTenantID, setTenant, setValue, options, unique])\n\n React.useEffect(() => {\n setEntityType(unique ? 'global' : 'document')\n return () => {\n setEntityType(undefined)\n }\n }, [unique, setEntityType])\n\n React.useEffect(() => {\n // sync form modified state with the tenant selection provider context\n setModified(modified)\n\n return () => {\n setModified(false)\n }\n }, [modified, setModified])\n\n if (debug) {\n return (\n <div className={baseClass}>\n <div className={`${baseClass}__wrapper`}>\n <RelationshipField {...args} />\n </div>\n <div className={`${baseClass}__hr`} />\n </div>\n )\n }\n\n return null\n}\n"],"names":["RelationshipField","useField","useFormModified","React","useTenantSelection","baseClass","TenantField","args","debug","unique","setValue","value","modified","options","selectedTenantID","setEntityType","setModified","setTenant","hasSetValueRef","useRef","useEffect","current","id","refresh","defaultValue","undefined","div","className"],"mappings":"AAAA;;AAIA,SAASA,iBAAiB,EAAEC,QAAQ,EAAEC,eAAe,QAAQ,iBAAgB;AAC7E,OAAOC,WAAW,QAAO;AAEzB,SAASC,kBAAkB,QAAQ,0DAAyD;AAC5F,OAAO,eAAc;AAErB,MAAMC,YAAY;AAOlB,OAAO,MAAMC,cAAc,CAACC;IAC1B,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGF;IAC1B,MAAM,EAAEG,QAAQ,EAAEC,KAAK,EAAE,GAAGV;IAC5B,MAAMW,WAAWV;IACjB,MAAM,EACJW,OAAO,EACPC,gBAAgB,EAChBC,eAAeA,aAAa,EAC5BC,WAAW,EACXC,SAAS,EACV,GAAGb;IAEJ,MAAMc,iBAAiBf,MAAMgB,MAAM,CAAC;IAEpChB,MAAMiB,SAAS,CAAC;QACd,IAAI,CAACF,eAAeG,OAAO,EAAE;YAC3B,oBAAoB;YACpB,IAAIV,SAASA,UAAUG,kBAAkB;gBACvCG,UAAU;oBAAEK,IAAIX;oBAAOY,SAASd;gBAAO;YACzC,OAAO;gBACL,oEAAoE;gBACpE,MAAMe,eAAeV,oBAAoBD,OAAO,CAAC,EAAE,EAAEF;gBACrDM,UAAU;oBAAEK,IAAIE;oBAAcD,SAASd;gBAAO;YAChD;YACAS,eAAeG,OAAO,GAAG;QAC3B,OAAO,IAAI,CAACV,SAASA,UAAUG,kBAAkB;YAC/C,oEAAoE;YACpEJ,SAASI,kBAAkB,CAACH,SAASA,UAAUG;QACjD;IACF,GAAG;QAACH;QAAOG;QAAkBG;QAAWP;QAAUG;QAASJ;KAAO;IAElEN,MAAMiB,SAAS,CAAC;QACdL,cAAcN,SAAS,WAAW;QAClC,OAAO;YACLM,cAAcU;QAChB;IACF,GAAG;QAAChB;QAAQM;KAAc;IAE1BZ,MAAMiB,SAAS,CAAC;QACd,sEAAsE;QACtEJ,YAAYJ;QAEZ,OAAO;YACLI,YAAY;QACd;IACF,GAAG;QAACJ;QAAUI;KAAY;IAE1B,IAAIR,OAAO;QACT,qBACE,MAACkB;YAAIC,WAAWtB;;8BACd,KAACqB;oBAAIC,WAAW,GAAGtB,UAAU,SAAS,CAAC;8BACrC,cAAA,KAACL;wBAAmB,GAAGO,IAAI;;;8BAE7B,KAACmB;oBAAIC,WAAW,GAAGtB,UAAU,IAAI,CAAC;;;;IAGxC;IAEA,OAAO;AACT,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TenantSelector/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAUxC,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TenantSelector/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAUxC,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,cAAc,CAAA;AAKrB,eAAO,MAAM,cAAc,wBAAyB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,6BAuH1F,CAAA"}
|
|
@@ -5,10 +5,11 @@ import { ConfirmationModal, SelectInput, Translation, useModal, useTranslation }
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js';
|
|
7
7
|
import './index.scss';
|
|
8
|
-
const confirmSwitchTenantSlug = '
|
|
8
|
+
const confirmSwitchTenantSlug = 'confirm-switch-tenant';
|
|
9
|
+
const confirmLeaveWithoutSavingSlug = 'confirm-leave-without-saving';
|
|
9
10
|
export const TenantSelector = ({ label, viewType })=>{
|
|
10
|
-
const {
|
|
11
|
-
const { openModal } = useModal();
|
|
11
|
+
const { entityType, modified, options, selectedTenantID, setTenant } = useTenantSelection();
|
|
12
|
+
const { closeModal, openModal } = useModal();
|
|
12
13
|
const { i18n, t } = useTranslation();
|
|
13
14
|
const [tenantSelection, setTenantSelection] = React.useState();
|
|
14
15
|
const selectedValue = React.useMemo(()=>{
|
|
@@ -45,17 +46,30 @@ export const TenantSelector = ({ label, viewType })=>{
|
|
|
45
46
|
setTenant
|
|
46
47
|
]);
|
|
47
48
|
const onChange = React.useCallback((option)=>{
|
|
48
|
-
if (
|
|
49
|
-
|
|
49
|
+
if (option && 'value' in option && option.value === selectedTenantID) {
|
|
50
|
+
// If the selected option is the same as the current tenant, do nothing
|
|
50
51
|
return;
|
|
52
|
+
}
|
|
53
|
+
if (entityType !== 'document') {
|
|
54
|
+
if (entityType === 'global' && modified) {
|
|
55
|
+
// If the entityType is 'global' and there are unsaved changes, prompt for confirmation
|
|
56
|
+
setTenantSelection(option);
|
|
57
|
+
openModal(confirmLeaveWithoutSavingSlug);
|
|
58
|
+
} else {
|
|
59
|
+
// If the entityType is not 'document', switch tenant without confirmation
|
|
60
|
+
switchTenant(option);
|
|
61
|
+
}
|
|
51
62
|
} else {
|
|
63
|
+
// non-unique documents should always prompt for confirmation
|
|
52
64
|
setTenantSelection(option);
|
|
53
65
|
openModal(confirmSwitchTenantSlug);
|
|
54
66
|
}
|
|
55
67
|
}, [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
selectedTenantID,
|
|
69
|
+
entityType,
|
|
70
|
+
modified,
|
|
71
|
+
switchTenant,
|
|
72
|
+
openModal
|
|
59
73
|
]);
|
|
60
74
|
if (options.length <= 1) {
|
|
61
75
|
return null;
|
|
@@ -90,19 +104,26 @@ export const TenantSelector = ({ label, viewType })=>{
|
|
|
90
104
|
toTenant: newSelectedValue?.label
|
|
91
105
|
}
|
|
92
106
|
}),
|
|
93
|
-
heading:
|
|
94
|
-
|
|
95
|
-
// @ts-expect-error
|
|
96
|
-
i18nKey: "plugin-multi-tenant:confirm-tenant-switch--heading",
|
|
97
|
-
t: t,
|
|
98
|
-
variables: {
|
|
99
|
-
tenantLabel: getTranslation(label, i18n)
|
|
100
|
-
}
|
|
107
|
+
heading: t('plugin-multi-tenant:confirm-tenant-switch--heading', {
|
|
108
|
+
tenantLabel: getTranslation(label, i18n)
|
|
101
109
|
}),
|
|
102
110
|
modalSlug: confirmSwitchTenantSlug,
|
|
103
111
|
onConfirm: ()=>{
|
|
104
112
|
switchTenant(tenantSelection);
|
|
105
113
|
}
|
|
114
|
+
}),
|
|
115
|
+
/*#__PURE__*/ _jsx(ConfirmationModal, {
|
|
116
|
+
body: t('general:changesNotSaved'),
|
|
117
|
+
cancelLabel: t('general:stayOnThisPage'),
|
|
118
|
+
confirmLabel: t('general:leaveAnyway'),
|
|
119
|
+
heading: t('general:leaveWithoutSaving'),
|
|
120
|
+
modalSlug: confirmLeaveWithoutSavingSlug,
|
|
121
|
+
onCancel: ()=>{
|
|
122
|
+
closeModal(confirmLeaveWithoutSavingSlug);
|
|
123
|
+
},
|
|
124
|
+
onConfirm: ()=>{
|
|
125
|
+
switchTenant(tenantSelection);
|
|
126
|
+
}
|
|
106
127
|
})
|
|
107
128
|
]
|
|
108
129
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/TenantSelector/index.tsx"],"sourcesContent":["'use client'\nimport type { ReactSelectOption } from '@payloadcms/ui'\nimport type { ViewTypes } from 'payload'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport {\n ConfirmationModal,\n SelectInput,\n Translation,\n useModal,\n useTranslation,\n} from '@payloadcms/ui'\nimport React from 'react'\n\nimport type {\n PluginMultiTenantTranslationKeys,\n PluginMultiTenantTranslations,\n} from '../../translations/index.js'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\nimport './index.scss'\n\nconst confirmSwitchTenantSlug = '
|
|
1
|
+
{"version":3,"sources":["../../../src/components/TenantSelector/index.tsx"],"sourcesContent":["'use client'\nimport type { ReactSelectOption } from '@payloadcms/ui'\nimport type { ViewTypes } from 'payload'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport {\n ConfirmationModal,\n SelectInput,\n Translation,\n useModal,\n useTranslation,\n} from '@payloadcms/ui'\nimport React from 'react'\n\nimport type {\n PluginMultiTenantTranslationKeys,\n PluginMultiTenantTranslations,\n} from '../../translations/index.js'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\nimport './index.scss'\n\nconst confirmSwitchTenantSlug = 'confirm-switch-tenant'\nconst confirmLeaveWithoutSavingSlug = 'confirm-leave-without-saving'\n\nexport const TenantSelector = ({ label, viewType }: { label: string; viewType?: ViewTypes }) => {\n const { entityType, modified, options, selectedTenantID, setTenant } = useTenantSelection()\n const { closeModal, openModal } = useModal()\n const { i18n, t } = useTranslation<\n PluginMultiTenantTranslations,\n PluginMultiTenantTranslationKeys\n >()\n const [tenantSelection, setTenantSelection] = React.useState<\n ReactSelectOption | ReactSelectOption[]\n >()\n\n const selectedValue = React.useMemo(() => {\n if (selectedTenantID) {\n return options.find((option) => option.value === selectedTenantID)\n }\n return undefined\n }, [options, selectedTenantID])\n\n const newSelectedValue = React.useMemo(() => {\n if (tenantSelection && 'value' in tenantSelection) {\n return options.find((option) => option.value === tenantSelection.value)\n }\n return undefined\n }, [options, tenantSelection])\n\n const switchTenant = React.useCallback(\n (option: ReactSelectOption | ReactSelectOption[] | undefined) => {\n if (option && 'value' in option) {\n setTenant({ id: option.value as string, refresh: true })\n } else {\n setTenant({ id: undefined, refresh: true })\n }\n },\n [setTenant],\n )\n\n const onChange = React.useCallback(\n (option: ReactSelectOption | ReactSelectOption[]) => {\n if (option && 'value' in option && option.value === selectedTenantID) {\n // If the selected option is the same as the current tenant, do nothing\n return\n }\n\n if (entityType !== 'document') {\n if (entityType === 'global' && modified) {\n // If the entityType is 'global' and there are unsaved changes, prompt for confirmation\n setTenantSelection(option)\n openModal(confirmLeaveWithoutSavingSlug)\n } else {\n // If the entityType is not 'document', switch tenant without confirmation\n switchTenant(option)\n }\n } else {\n // non-unique documents should always prompt for confirmation\n setTenantSelection(option)\n openModal(confirmSwitchTenantSlug)\n }\n },\n [selectedTenantID, entityType, modified, switchTenant, openModal],\n )\n\n if (options.length <= 1) {\n return null\n }\n\n return (\n <div className=\"tenant-selector\">\n <SelectInput\n isClearable={viewType === 'list'}\n label={getTranslation(label, i18n)}\n name=\"setTenant\"\n onChange={onChange}\n options={options}\n path=\"setTenant\"\n value={selectedTenantID as string | undefined}\n />\n\n <ConfirmationModal\n body={\n <Translation\n elements={{\n 0: ({ children }) => {\n return <b>{children}</b>\n },\n }}\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n i18nKey=\"plugin-multi-tenant:confirm-tenant-switch--body\"\n t={t}\n variables={{\n fromTenant: selectedValue?.label,\n toTenant: newSelectedValue?.label,\n }}\n />\n }\n heading={t('plugin-multi-tenant:confirm-tenant-switch--heading', {\n tenantLabel: getTranslation(label, i18n),\n })}\n modalSlug={confirmSwitchTenantSlug}\n onConfirm={() => {\n switchTenant(tenantSelection)\n }}\n />\n\n <ConfirmationModal\n body={t('general:changesNotSaved')}\n cancelLabel={t('general:stayOnThisPage')}\n confirmLabel={t('general:leaveAnyway')}\n heading={t('general:leaveWithoutSaving')}\n modalSlug={confirmLeaveWithoutSavingSlug}\n onCancel={() => {\n closeModal(confirmLeaveWithoutSavingSlug)\n }}\n onConfirm={() => {\n switchTenant(tenantSelection)\n }}\n />\n </div>\n )\n}\n"],"names":["getTranslation","ConfirmationModal","SelectInput","Translation","useModal","useTranslation","React","useTenantSelection","confirmSwitchTenantSlug","confirmLeaveWithoutSavingSlug","TenantSelector","label","viewType","entityType","modified","options","selectedTenantID","setTenant","closeModal","openModal","i18n","t","tenantSelection","setTenantSelection","useState","selectedValue","useMemo","find","option","value","undefined","newSelectedValue","switchTenant","useCallback","id","refresh","onChange","length","div","className","isClearable","name","path","body","elements","children","b","i18nKey","variables","fromTenant","toTenant","heading","tenantLabel","modalSlug","onConfirm","cancelLabel","confirmLabel","onCancel"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/WatchTenantCollection/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/WatchTenantCollection/index.tsx"],"names":[],"mappings":"AAiBA,eAAO,MAAM,qBAAqB,YAmCjC,CAAA"}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useConfig, useDocumentInfo, useDocumentTitle, useEffectEvent, useFormFields } from '@payloadcms/ui';
|
|
2
|
+
import { useConfig, useDocumentInfo, useDocumentTitle, useEffectEvent, useFormFields, useFormSubmitted, useOperation } from '@payloadcms/ui';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js';
|
|
5
5
|
export const WatchTenantCollection = ()=>{
|
|
6
6
|
const { id, collectionSlug } = useDocumentInfo();
|
|
7
|
+
const operation = useOperation();
|
|
8
|
+
const submitted = useFormSubmitted();
|
|
7
9
|
const { title } = useDocumentTitle();
|
|
8
|
-
const addedNewTenant = React.useRef(false);
|
|
9
10
|
const { getEntityConfig } = useConfig();
|
|
10
11
|
const [useAsTitleName] = React.useState(()=>getEntityConfig({
|
|
11
12
|
collectionSlug
|
|
12
13
|
}).admin.useAsTitle);
|
|
13
14
|
const titleField = useFormFields(([fields])=>useAsTitleName ? fields[useAsTitleName] : {});
|
|
14
|
-
const {
|
|
15
|
+
const { syncTenants, updateTenants } = useTenantSelection();
|
|
15
16
|
const syncTenantTitle = useEffectEvent(()=>{
|
|
16
17
|
if (id) {
|
|
17
18
|
updateTenants({
|
|
@@ -20,33 +21,26 @@ export const WatchTenantCollection = ()=>{
|
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
});
|
|
23
|
-
React.useEffect(()=>{
|
|
24
|
-
if (!id || !title || addedNewTenant.current) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
// Track tenant creation and add it to the tenant selector
|
|
28
|
-
const exists = options.some((opt)=>opt.value === id);
|
|
29
|
-
if (!exists) {
|
|
30
|
-
addedNewTenant.current = true;
|
|
31
|
-
updateTenants({
|
|
32
|
-
id,
|
|
33
|
-
label: title
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
// eslint-disable-next-line react-compiler/react-compiler
|
|
37
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
-
}, [
|
|
39
|
-
id
|
|
40
|
-
]);
|
|
41
24
|
React.useEffect(()=>{
|
|
42
25
|
// only update the tenant selector when the document saves
|
|
43
26
|
// → aka when initial value changes
|
|
44
27
|
if (id && titleField?.initialValue) {
|
|
45
|
-
syncTenantTitle();
|
|
28
|
+
void syncTenantTitle();
|
|
46
29
|
}
|
|
47
30
|
}, [
|
|
48
31
|
id,
|
|
49
|
-
titleField?.initialValue
|
|
32
|
+
titleField?.initialValue,
|
|
33
|
+
syncTenants
|
|
34
|
+
]);
|
|
35
|
+
React.useEffect(()=>{
|
|
36
|
+
if (operation === 'create' && submitted) {
|
|
37
|
+
void syncTenants();
|
|
38
|
+
}
|
|
39
|
+
}, [
|
|
40
|
+
operation,
|
|
41
|
+
submitted,
|
|
42
|
+
syncTenants,
|
|
43
|
+
id
|
|
50
44
|
]);
|
|
51
45
|
return null;
|
|
52
46
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/WatchTenantCollection/index.tsx"],"sourcesContent":["'use client'\n\nimport type { ClientCollectionConfig } from 'payload'\n\nimport {\n useConfig,\n useDocumentInfo,\n useDocumentTitle,\n useEffectEvent,\n useFormFields,\n} from '@payloadcms/ui'\nimport React from 'react'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\n\nexport const WatchTenantCollection = () => {\n const { id, collectionSlug } = useDocumentInfo()\n const
|
|
1
|
+
{"version":3,"sources":["../../../src/components/WatchTenantCollection/index.tsx"],"sourcesContent":["'use client'\n\nimport type { ClientCollectionConfig } from 'payload'\n\nimport {\n useConfig,\n useDocumentInfo,\n useDocumentTitle,\n useEffectEvent,\n useFormFields,\n useFormSubmitted,\n useOperation,\n} from '@payloadcms/ui'\nimport React from 'react'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\n\nexport const WatchTenantCollection = () => {\n const { id, collectionSlug } = useDocumentInfo()\n const operation = useOperation()\n const submitted = useFormSubmitted()\n const { title } = useDocumentTitle()\n\n const { getEntityConfig } = useConfig()\n const [useAsTitleName] = React.useState(\n () => (getEntityConfig({ collectionSlug }) as ClientCollectionConfig).admin.useAsTitle,\n )\n const titleField = useFormFields(([fields]) => (useAsTitleName ? fields[useAsTitleName] : {}))\n\n const { syncTenants, updateTenants } = useTenantSelection()\n\n const syncTenantTitle = useEffectEvent(() => {\n if (id) {\n updateTenants({ id, label: title })\n }\n })\n\n React.useEffect(() => {\n // only update the tenant selector when the document saves\n // → aka when initial value changes\n if (id && titleField?.initialValue) {\n void syncTenantTitle()\n }\n }, [id, titleField?.initialValue, syncTenants])\n\n React.useEffect(() => {\n if (operation === 'create' && submitted) {\n void syncTenants()\n }\n }, [operation, submitted, syncTenants, id])\n\n return null\n}\n"],"names":["useConfig","useDocumentInfo","useDocumentTitle","useEffectEvent","useFormFields","useFormSubmitted","useOperation","React","useTenantSelection","WatchTenantCollection","id","collectionSlug","operation","submitted","title","getEntityConfig","useAsTitleName","useState","admin","useAsTitle","titleField","fields","syncTenants","updateTenants","syncTenantTitle","label","useEffect","initialValue"],"mappings":"AAAA;AAIA,SACEA,SAAS,EACTC,eAAe,EACfC,gBAAgB,EAChBC,cAAc,EACdC,aAAa,EACbC,gBAAgB,EAChBC,YAAY,QACP,iBAAgB;AACvB,OAAOC,WAAW,QAAO;AAEzB,SAASC,kBAAkB,QAAQ,0DAAyD;AAE5F,OAAO,MAAMC,wBAAwB;IACnC,MAAM,EAAEC,EAAE,EAAEC,cAAc,EAAE,GAAGV;IAC/B,MAAMW,YAAYN;IAClB,MAAMO,YAAYR;IAClB,MAAM,EAAES,KAAK,EAAE,GAAGZ;IAElB,MAAM,EAAEa,eAAe,EAAE,GAAGf;IAC5B,MAAM,CAACgB,eAAe,GAAGT,MAAMU,QAAQ,CACrC,IAAM,AAACF,gBAAgB;YAAEJ;QAAe,GAA8BO,KAAK,CAACC,UAAU;IAExF,MAAMC,aAAahB,cAAc,CAAC,CAACiB,OAAO,GAAML,iBAAiBK,MAAM,CAACL,eAAe,GAAG,CAAC;IAE3F,MAAM,EAAEM,WAAW,EAAEC,aAAa,EAAE,GAAGf;IAEvC,MAAMgB,kBAAkBrB,eAAe;QACrC,IAAIO,IAAI;YACNa,cAAc;gBAAEb;gBAAIe,OAAOX;YAAM;QACnC;IACF;IAEAP,MAAMmB,SAAS,CAAC;QACd,0DAA0D;QAC1D,mCAAmC;QACnC,IAAIhB,MAAMU,YAAYO,cAAc;YAClC,KAAKH;QACP;IACF,GAAG;QAACd;QAAIU,YAAYO;QAAcL;KAAY;IAE9Cf,MAAMmB,SAAS,CAAC;QACd,IAAId,cAAc,YAAYC,WAAW;YACvC,KAAKS;QACP;IACF,GAAG;QAACV;QAAWC;QAAWS;QAAaZ;KAAG;IAE1C,OAAO;AACT,EAAC"}
|
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
import type { OptionObject } from 'payload';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
type ContextType = {
|
|
4
|
+
/**
|
|
5
|
+
* What is the context of the selector? It is either 'document' | 'global' | undefined.
|
|
6
|
+
*
|
|
7
|
+
* - 'document' means you are viewing a document in the context of a tenant
|
|
8
|
+
* - 'global' means you are viewing a "global" (globals are collection documents but prevent you from viewing the list view) document in the context of a tenant
|
|
9
|
+
* - undefined means you are not viewing a document at all
|
|
10
|
+
*/
|
|
11
|
+
entityType?: 'document' | 'global';
|
|
12
|
+
/**
|
|
13
|
+
* Hoists the forms modified state
|
|
14
|
+
*/
|
|
15
|
+
modified?: boolean;
|
|
4
16
|
/**
|
|
5
17
|
* Array of options to select from
|
|
6
18
|
*/
|
|
7
19
|
options: OptionObject[];
|
|
8
|
-
preventRefreshOnChange: boolean;
|
|
9
20
|
/**
|
|
10
21
|
* The currently selected tenant ID
|
|
11
22
|
*/
|
|
12
23
|
selectedTenantID: number | string | undefined;
|
|
13
24
|
/**
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
* Sets the entityType when a document is loaded and sets it to undefined when the document unmounts.
|
|
26
|
+
*/
|
|
27
|
+
setEntityType: React.Dispatch<React.SetStateAction<'document' | 'global' | undefined>>;
|
|
28
|
+
/**
|
|
29
|
+
* Sets the modified state
|
|
17
30
|
*/
|
|
18
|
-
|
|
31
|
+
setModified: React.Dispatch<React.SetStateAction<boolean>>;
|
|
19
32
|
/**
|
|
20
33
|
* Sets the selected tenant ID
|
|
21
34
|
*
|
|
@@ -26,6 +39,10 @@ type ContextType = {
|
|
|
26
39
|
id: number | string | undefined;
|
|
27
40
|
refresh?: boolean;
|
|
28
41
|
}) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Used to sync tenants displayed in the tenant selector when updates are made to the tenants collection.
|
|
44
|
+
*/
|
|
45
|
+
syncTenants: () => Promise<void>;
|
|
29
46
|
/**
|
|
30
47
|
*
|
|
31
48
|
*/
|
|
@@ -34,11 +51,13 @@ type ContextType = {
|
|
|
34
51
|
label: string;
|
|
35
52
|
}) => void;
|
|
36
53
|
};
|
|
37
|
-
export declare const TenantSelectionProviderClient: ({ children, initialValue, tenantCookie, tenantOptions: tenantOptionsFromProps, }: {
|
|
54
|
+
export declare const TenantSelectionProviderClient: ({ children, initialValue, tenantCookie, tenantOptions: tenantOptionsFromProps, tenantsCollectionSlug, useAsTitle, }: {
|
|
38
55
|
children: React.ReactNode;
|
|
39
56
|
initialValue?: number | string;
|
|
40
57
|
tenantCookie?: string;
|
|
41
58
|
tenantOptions: OptionObject[];
|
|
59
|
+
tenantsCollectionSlug: string;
|
|
60
|
+
useAsTitle: string;
|
|
42
61
|
}) => React.JSX.Element;
|
|
43
62
|
export declare const useTenantSelection: () => ContextType;
|
|
44
63
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C,OAAO,KAAwB,MAAM,OAAO,CAAA;AAE5C,KAAK,WAAW,GAAG;IACjB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,
|
|
1
|
+
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C,OAAO,KAAwB,MAAM,OAAO,CAAA;AAE5C,KAAK,WAAW,GAAG;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB;;OAEG;IACH,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC7C;;OAEG;IACH,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAA;IACtF;;OAEG;IACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;IAC1D;;;;;OAKG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACjF;;OAEG;IACH,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC;;OAEG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE,CAAA;AAaD,eAAO,MAAM,6BAA6B,wHAOvC;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;CACnB,sBA8JA,CAAA;AAED,eAAO,MAAM,kBAAkB,mBAA2B,CAAA"}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useAuth } from '@payloadcms/ui';
|
|
3
|
+
import { toast, useAuth, useConfig } from '@payloadcms/ui';
|
|
4
4
|
import { useRouter } from 'next/navigation.js';
|
|
5
5
|
import React, { createContext } from 'react';
|
|
6
6
|
const Context = /*#__PURE__*/ createContext({
|
|
7
|
+
entityType: undefined,
|
|
7
8
|
options: [],
|
|
8
|
-
preventRefreshOnChange: false,
|
|
9
9
|
selectedTenantID: undefined,
|
|
10
|
-
|
|
10
|
+
setEntityType: ()=>undefined,
|
|
11
|
+
setModified: ()=>undefined,
|
|
11
12
|
setTenant: ()=>null,
|
|
13
|
+
syncTenants: ()=>Promise.resolve(),
|
|
12
14
|
updateTenants: ()=>null
|
|
13
15
|
});
|
|
14
|
-
export const TenantSelectionProviderClient = ({ children, initialValue, tenantCookie, tenantOptions: tenantOptionsFromProps })=>{
|
|
16
|
+
export const TenantSelectionProviderClient = ({ children, initialValue, tenantCookie, tenantOptions: tenantOptionsFromProps, tenantsCollectionSlug, useAsTitle })=>{
|
|
15
17
|
const [selectedTenantID, setSelectedTenantID] = React.useState(initialValue);
|
|
16
|
-
const [
|
|
18
|
+
const [modified, setModified] = React.useState(false);
|
|
19
|
+
const [entityType, setEntityType] = React.useState(undefined);
|
|
17
20
|
const { user } = useAuth();
|
|
21
|
+
const { config } = useConfig();
|
|
18
22
|
const userID = React.useMemo(()=>user?.id, [
|
|
19
23
|
user?.id
|
|
20
24
|
]);
|
|
@@ -35,96 +39,102 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
|
|
|
35
39
|
const setTenant = React.useCallback(({ id, refresh })=>{
|
|
36
40
|
if (id === undefined) {
|
|
37
41
|
if (tenantOptions.length > 1) {
|
|
42
|
+
// users with multiple tenants can clear the tenant selection
|
|
38
43
|
setSelectedTenantID(undefined);
|
|
39
44
|
deleteCookie();
|
|
40
45
|
} else {
|
|
46
|
+
// if there is only one tenant, force the selection of that tenant
|
|
41
47
|
setSelectedTenantID(tenantOptions[0]?.value);
|
|
42
48
|
setCookie(String(tenantOptions[0]?.value));
|
|
43
49
|
}
|
|
50
|
+
} else if (!tenantOptions.find((option)=>option.value === id)) {
|
|
51
|
+
// if the tenant is not valid, set the first tenant as selected
|
|
52
|
+
if (tenantOptions?.[0]?.value) {
|
|
53
|
+
setTenant({
|
|
54
|
+
id: tenantOptions[0].value,
|
|
55
|
+
refresh: true
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
setTenant({
|
|
59
|
+
id: undefined,
|
|
60
|
+
refresh: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
44
63
|
} else {
|
|
64
|
+
// if the tenant is in the options, set it as selected
|
|
45
65
|
setSelectedTenantID(id);
|
|
46
66
|
setCookie(String(id));
|
|
47
67
|
}
|
|
48
|
-
if (
|
|
68
|
+
if (entityType !== 'document' && refresh) {
|
|
49
69
|
router.refresh();
|
|
50
70
|
}
|
|
51
71
|
}, [
|
|
52
72
|
deleteCookie,
|
|
53
|
-
|
|
73
|
+
entityType,
|
|
54
74
|
router,
|
|
55
75
|
setCookie,
|
|
56
|
-
setSelectedTenantID,
|
|
57
76
|
tenantOptions
|
|
58
77
|
]);
|
|
78
|
+
const syncTenants = React.useCallback(async ()=>{
|
|
79
|
+
try {
|
|
80
|
+
const req = await fetch(`${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}?select[${useAsTitle}]=true&limit=0&depth=0`, {
|
|
81
|
+
credentials: 'include',
|
|
82
|
+
method: 'GET'
|
|
83
|
+
});
|
|
84
|
+
const result = await req.json();
|
|
85
|
+
if (result.docs) {
|
|
86
|
+
setTenantOptions(result.docs.map((doc)=>({
|
|
87
|
+
label: doc[useAsTitle],
|
|
88
|
+
value: doc.id
|
|
89
|
+
})));
|
|
90
|
+
}
|
|
91
|
+
} catch (e) {
|
|
92
|
+
toast.error(`Error fetching tenants`);
|
|
93
|
+
}
|
|
94
|
+
}, [
|
|
95
|
+
config.serverURL,
|
|
96
|
+
config.routes.api,
|
|
97
|
+
tenantsCollectionSlug,
|
|
98
|
+
useAsTitle
|
|
99
|
+
]);
|
|
59
100
|
const updateTenants = React.useCallback(({ id, label })=>{
|
|
60
101
|
setTenantOptions((prev)=>{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const updated = prev.map((currentTenant)=>{
|
|
64
|
-
if (stringID === String(currentTenant.value)) {
|
|
65
|
-
exists = true;
|
|
102
|
+
return prev.map((currentTenant)=>{
|
|
103
|
+
if (id === currentTenant.value) {
|
|
66
104
|
return {
|
|
67
105
|
label,
|
|
68
|
-
value:
|
|
106
|
+
value: id
|
|
69
107
|
};
|
|
70
108
|
}
|
|
71
109
|
return currentTenant;
|
|
72
110
|
});
|
|
73
|
-
if (!exists) {
|
|
74
|
-
updated.push({
|
|
75
|
-
label,
|
|
76
|
-
value: stringID
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
// Sort alphabetically by label (or value as fallback)
|
|
80
|
-
return updated.sort((a, b)=>{
|
|
81
|
-
const aKey = typeof a.label === 'string' ? a.label : String(a.value);
|
|
82
|
-
const bKey = typeof b.label === 'string' ? b.label : String(b.value);
|
|
83
|
-
return aKey.localeCompare(bKey);
|
|
84
|
-
});
|
|
85
111
|
});
|
|
86
|
-
|
|
112
|
+
void syncTenants();
|
|
113
|
+
}, [
|
|
114
|
+
syncTenants
|
|
115
|
+
]);
|
|
87
116
|
React.useEffect(()=>{
|
|
88
|
-
if (
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
id: tenantOptions[0].value,
|
|
92
|
-
refresh: true
|
|
93
|
-
});
|
|
94
|
-
} else {
|
|
117
|
+
if (userID && !tenantCookie) {
|
|
118
|
+
if (tenantOptionsFromProps.length === 1) {
|
|
119
|
+
// Users with no cookie set and only 1 tenant should set that tenant automatically
|
|
95
120
|
setTenant({
|
|
96
|
-
id:
|
|
121
|
+
id: tenantOptionsFromProps[0]?.value,
|
|
97
122
|
refresh: true
|
|
98
123
|
});
|
|
124
|
+
setTenantOptions(tenantOptionsFromProps);
|
|
125
|
+
} else if ((!tenantOptions || tenantOptions.length === 0) && tenantOptionsFromProps) {
|
|
126
|
+
// If there are no tenant options, set them from the props
|
|
127
|
+
setTenantOptions(tenantOptionsFromProps);
|
|
99
128
|
}
|
|
100
129
|
}
|
|
101
130
|
}, [
|
|
102
|
-
tenantCookie,
|
|
103
|
-
setTenant,
|
|
104
|
-
selectedTenantID,
|
|
105
|
-
tenantOptions,
|
|
106
131
|
initialValue,
|
|
107
|
-
|
|
108
|
-
]);
|
|
109
|
-
React.useEffect(()=>{
|
|
110
|
-
if (userID && !tenantCookie) {
|
|
111
|
-
// User is logged in, but does not have a tenant cookie, set it
|
|
112
|
-
setSelectedTenantID(initialValue);
|
|
113
|
-
setTenantOptions(tenantOptionsFromProps);
|
|
114
|
-
if (initialValue) {
|
|
115
|
-
setCookie(String(initialValue));
|
|
116
|
-
} else {
|
|
117
|
-
deleteCookie();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}, [
|
|
121
|
-
userID,
|
|
132
|
+
selectedTenantID,
|
|
122
133
|
tenantCookie,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
tenantOptionsFromProps
|
|
134
|
+
userID,
|
|
135
|
+
setTenant,
|
|
136
|
+
tenantOptionsFromProps,
|
|
137
|
+
tenantOptions
|
|
128
138
|
]);
|
|
129
139
|
React.useEffect(()=>{
|
|
130
140
|
if (!userID && tenantCookie) {
|
|
@@ -146,11 +156,14 @@ export const TenantSelectionProviderClient = ({ children, initialValue, tenantCo
|
|
|
146
156
|
"data-selected-tenant-title": selectedTenantLabel,
|
|
147
157
|
children: /*#__PURE__*/ _jsx(Context, {
|
|
148
158
|
value: {
|
|
159
|
+
entityType,
|
|
160
|
+
modified,
|
|
149
161
|
options: tenantOptions,
|
|
150
|
-
preventRefreshOnChange,
|
|
151
162
|
selectedTenantID,
|
|
152
|
-
|
|
163
|
+
setEntityType,
|
|
164
|
+
setModified,
|
|
153
165
|
setTenant,
|
|
166
|
+
syncTenants,
|
|
154
167
|
updateTenants
|
|
155
168
|
},
|
|
156
169
|
children: children
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"sourcesContent":["'use client'\n\nimport type { OptionObject } from 'payload'\n\nimport { useAuth } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport React, { createContext } from 'react'\n\ntype ContextType = {\n /**\n * Array of options to select from\n */\n options: OptionObject[]\n preventRefreshOnChange: boolean\n /**\n * The currently selected tenant ID\n */\n selectedTenantID: number | string | undefined\n /**\n * Prevents a refresh when the tenant is changed\n *\n * If not switching tenants while viewing a \"global\", set to true\n */\n setPreventRefreshOnChange: React.Dispatch<React.SetStateAction<boolean>>\n /**\n * Sets the selected tenant ID\n *\n * @param args.id - The ID of the tenant to select\n * @param args.refresh - Whether to refresh the page after changing the tenant\n */\n setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void\n /**\n *\n */\n updateTenants: (args: { id: number | string; label: string }) => void\n}\n\nconst Context = createContext<ContextType>({\n options: [],\n preventRefreshOnChange: false,\n selectedTenantID: undefined,\n setPreventRefreshOnChange: () => null,\n setTenant: () => null,\n updateTenants: () => null,\n})\n\nexport const TenantSelectionProviderClient = ({\n children,\n initialValue,\n tenantCookie,\n tenantOptions: tenantOptionsFromProps,\n}: {\n children: React.ReactNode\n initialValue?: number | string\n tenantCookie?: string\n tenantOptions: OptionObject[]\n}) => {\n const [selectedTenantID, setSelectedTenantID] = React.useState<number | string | undefined>(\n initialValue,\n )\n const [preventRefreshOnChange, setPreventRefreshOnChange] = React.useState(false)\n const { user } = useAuth()\n const userID = React.useMemo(() => user?.id, [user?.id])\n const [tenantOptions, setTenantOptions] = React.useState<OptionObject[]>(\n () => tenantOptionsFromProps,\n )\n const selectedTenantLabel = React.useMemo(\n () => tenantOptions.find((option) => option.value === selectedTenantID)?.label,\n [selectedTenantID, tenantOptions],\n )\n\n const router = useRouter()\n\n const setCookie = React.useCallback((value?: string) => {\n const expires = '; expires=Fri, 31 Dec 9999 23:59:59 GMT'\n document.cookie = 'payload-tenant=' + (value || '') + expires + '; path=/'\n }, [])\n\n const deleteCookie = React.useCallback(() => {\n // eslint-disable-next-line react-compiler/react-compiler -- TODO: fix\n document.cookie = 'payload-tenant=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'\n }, [])\n\n const setTenant = React.useCallback<ContextType['setTenant']>(\n ({ id, refresh }) => {\n if (id === undefined) {\n if (tenantOptions.length > 1) {\n setSelectedTenantID(undefined)\n deleteCookie()\n } else {\n setSelectedTenantID(tenantOptions[0]?.value)\n setCookie(String(tenantOptions[0]?.value))\n }\n } else {\n setSelectedTenantID(id)\n setCookie(String(id))\n }\n if (!preventRefreshOnChange && refresh) {\n router.refresh()\n }\n },\n [deleteCookie, preventRefreshOnChange, router, setCookie, setSelectedTenantID, tenantOptions],\n )\n\n const updateTenants = React.useCallback<ContextType['updateTenants']>(({ id, label }) => {\n setTenantOptions((prev) => {\n const stringID = String(id)\n let exists = false\n const updated = prev.map((currentTenant) => {\n if (stringID === String(currentTenant.value)) {\n exists = true\n return {\n label,\n value: stringID,\n }\n }\n return currentTenant\n })\n\n if (!exists) {\n updated.push({ label, value: stringID })\n }\n\n // Sort alphabetically by label (or value as fallback)\n return updated.sort((a, b) => {\n const aKey = typeof a.label === 'string' ? a.label : String(a.value)\n const bKey = typeof b.label === 'string' ? b.label : String(b.value)\n return aKey.localeCompare(bKey)\n })\n })\n }, [])\n\n React.useEffect(() => {\n if (selectedTenantID && !tenantOptions.find((option) => option.value === selectedTenantID)) {\n if (tenantOptions?.[0]?.value) {\n setTenant({ id: tenantOptions[0].value, refresh: true })\n } else {\n setTenant({ id: undefined, refresh: true })\n }\n }\n }, [tenantCookie, setTenant, selectedTenantID, tenantOptions, initialValue, setCookie])\n\n React.useEffect(() => {\n if (userID && !tenantCookie) {\n // User is logged in, but does not have a tenant cookie, set it\n setSelectedTenantID(initialValue)\n setTenantOptions(tenantOptionsFromProps)\n if (initialValue) {\n setCookie(String(initialValue))\n } else {\n deleteCookie()\n }\n }\n }, [userID, tenantCookie, initialValue, setCookie, deleteCookie, router, tenantOptionsFromProps])\n\n React.useEffect(() => {\n if (!userID && tenantCookie) {\n // User is not logged in, but has a tenant cookie, delete it\n deleteCookie()\n setSelectedTenantID(undefined)\n } else if (userID) {\n // User changed, refresh\n router.refresh()\n }\n }, [userID, tenantCookie, deleteCookie, router])\n\n return (\n <span\n data-selected-tenant-id={selectedTenantID}\n data-selected-tenant-title={selectedTenantLabel}\n >\n <Context\n value={{\n options: tenantOptions,\n preventRefreshOnChange,\n selectedTenantID,\n setPreventRefreshOnChange,\n setTenant,\n updateTenants,\n }}\n >\n {children}\n </Context>\n </span>\n )\n}\n\nexport const useTenantSelection = () => React.use(Context)\n"],"names":["useAuth","useRouter","React","createContext","Context","options","preventRefreshOnChange","selectedTenantID","undefined","setPreventRefreshOnChange","setTenant","updateTenants","TenantSelectionProviderClient","children","initialValue","tenantCookie","tenantOptions","tenantOptionsFromProps","setSelectedTenantID","useState","user","userID","useMemo","id","setTenantOptions","selectedTenantLabel","find","option","value","label","router","setCookie","useCallback","expires","document","cookie","deleteCookie","refresh","length","String","prev","stringID","exists","updated","map","currentTenant","push","sort","a","b","aKey","bKey","localeCompare","useEffect","span","data-selected-tenant-id","data-selected-tenant-title","useTenantSelection","use"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"sourcesContent":["'use client'\n\nimport type { OptionObject } from 'payload'\n\nimport { toast, useAuth, useConfig } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation.js'\nimport React, { createContext } from 'react'\n\ntype ContextType = {\n /**\n * What is the context of the selector? It is either 'document' | 'global' | undefined.\n *\n * - 'document' means you are viewing a document in the context of a tenant\n * - 'global' means you are viewing a \"global\" (globals are collection documents but prevent you from viewing the list view) document in the context of a tenant\n * - undefined means you are not viewing a document at all\n */\n entityType?: 'document' | 'global'\n /**\n * Hoists the forms modified state\n */\n modified?: boolean\n /**\n * Array of options to select from\n */\n options: OptionObject[]\n /**\n * The currently selected tenant ID\n */\n selectedTenantID: number | string | undefined\n /**\n * Sets the entityType when a document is loaded and sets it to undefined when the document unmounts.\n */\n setEntityType: React.Dispatch<React.SetStateAction<'document' | 'global' | undefined>>\n /**\n * Sets the modified state\n */\n setModified: React.Dispatch<React.SetStateAction<boolean>>\n /**\n * Sets the selected tenant ID\n *\n * @param args.id - The ID of the tenant to select\n * @param args.refresh - Whether to refresh the page after changing the tenant\n */\n setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void\n /**\n * Used to sync tenants displayed in the tenant selector when updates are made to the tenants collection.\n */\n syncTenants: () => Promise<void>\n /**\n *\n */\n updateTenants: (args: { id: number | string; label: string }) => void\n}\n\nconst Context = createContext<ContextType>({\n entityType: undefined,\n options: [],\n selectedTenantID: undefined,\n setEntityType: () => undefined,\n setModified: () => undefined,\n setTenant: () => null,\n syncTenants: () => Promise.resolve(),\n updateTenants: () => null,\n})\n\nexport const TenantSelectionProviderClient = ({\n children,\n initialValue,\n tenantCookie,\n tenantOptions: tenantOptionsFromProps,\n tenantsCollectionSlug,\n useAsTitle,\n}: {\n children: React.ReactNode\n initialValue?: number | string\n tenantCookie?: string\n tenantOptions: OptionObject[]\n tenantsCollectionSlug: string\n useAsTitle: string\n}) => {\n const [selectedTenantID, setSelectedTenantID] = React.useState<number | string | undefined>(\n initialValue,\n )\n const [modified, setModified] = React.useState<boolean>(false)\n const [entityType, setEntityType] = React.useState<'document' | 'global' | undefined>(undefined)\n const { user } = useAuth()\n const { config } = useConfig()\n const userID = React.useMemo(() => user?.id, [user?.id])\n const [tenantOptions, setTenantOptions] = React.useState<OptionObject[]>(\n () => tenantOptionsFromProps,\n )\n const selectedTenantLabel = React.useMemo(\n () => tenantOptions.find((option) => option.value === selectedTenantID)?.label,\n [selectedTenantID, tenantOptions],\n )\n\n const router = useRouter()\n\n const setCookie = React.useCallback((value?: string) => {\n const expires = '; expires=Fri, 31 Dec 9999 23:59:59 GMT'\n document.cookie = 'payload-tenant=' + (value || '') + expires + '; path=/'\n }, [])\n\n const deleteCookie = React.useCallback(() => {\n // eslint-disable-next-line react-compiler/react-compiler -- TODO: fix\n document.cookie = 'payload-tenant=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'\n }, [])\n\n const setTenant = React.useCallback<ContextType['setTenant']>(\n ({ id, refresh }) => {\n if (id === undefined) {\n if (tenantOptions.length > 1) {\n // users with multiple tenants can clear the tenant selection\n setSelectedTenantID(undefined)\n deleteCookie()\n } else {\n // if there is only one tenant, force the selection of that tenant\n setSelectedTenantID(tenantOptions[0]?.value)\n setCookie(String(tenantOptions[0]?.value))\n }\n } else if (!tenantOptions.find((option) => option.value === id)) {\n // if the tenant is not valid, set the first tenant as selected\n if (tenantOptions?.[0]?.value) {\n setTenant({ id: tenantOptions[0].value, refresh: true })\n } else {\n setTenant({ id: undefined, refresh: true })\n }\n } else {\n // if the tenant is in the options, set it as selected\n setSelectedTenantID(id)\n setCookie(String(id))\n }\n if (entityType !== 'document' && refresh) {\n router.refresh()\n }\n },\n [deleteCookie, entityType, router, setCookie, tenantOptions],\n )\n\n const syncTenants = React.useCallback(async () => {\n try {\n const req = await fetch(\n `${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}?select[${useAsTitle}]=true&limit=0&depth=0`,\n {\n credentials: 'include',\n method: 'GET',\n },\n )\n\n const result = await req.json()\n\n if (result.docs) {\n setTenantOptions(\n result.docs.map((doc: Record<string, number | string>) => ({\n label: doc[useAsTitle],\n value: doc.id,\n })),\n )\n }\n } catch (e) {\n toast.error(`Error fetching tenants`)\n }\n }, [config.serverURL, config.routes.api, tenantsCollectionSlug, useAsTitle])\n\n const updateTenants = React.useCallback<ContextType['updateTenants']>(\n ({ id, label }) => {\n setTenantOptions((prev) => {\n return prev.map((currentTenant) => {\n if (id === currentTenant.value) {\n return {\n label,\n value: id,\n }\n }\n return currentTenant\n })\n })\n\n void syncTenants()\n },\n [syncTenants],\n )\n\n React.useEffect(() => {\n if (userID && !tenantCookie) {\n if (tenantOptionsFromProps.length === 1) {\n // Users with no cookie set and only 1 tenant should set that tenant automatically\n setTenant({ id: tenantOptionsFromProps[0]?.value, refresh: true })\n setTenantOptions(tenantOptionsFromProps)\n } else if ((!tenantOptions || tenantOptions.length === 0) && tenantOptionsFromProps) {\n // If there are no tenant options, set them from the props\n setTenantOptions(tenantOptionsFromProps)\n }\n }\n }, [\n initialValue,\n selectedTenantID,\n tenantCookie,\n userID,\n setTenant,\n tenantOptionsFromProps,\n tenantOptions,\n ])\n\n React.useEffect(() => {\n if (!userID && tenantCookie) {\n // User is not logged in, but has a tenant cookie, delete it\n deleteCookie()\n setSelectedTenantID(undefined)\n } else if (userID) {\n // User changed, refresh\n router.refresh()\n }\n }, [userID, tenantCookie, deleteCookie, router])\n\n return (\n <span\n data-selected-tenant-id={selectedTenantID}\n data-selected-tenant-title={selectedTenantLabel}\n >\n <Context\n value={{\n entityType,\n modified,\n options: tenantOptions,\n selectedTenantID,\n setEntityType,\n setModified,\n setTenant,\n syncTenants,\n updateTenants,\n }}\n >\n {children}\n </Context>\n </span>\n )\n}\n\nexport const useTenantSelection = () => React.use(Context)\n"],"names":["toast","useAuth","useConfig","useRouter","React","createContext","Context","entityType","undefined","options","selectedTenantID","setEntityType","setModified","setTenant","syncTenants","Promise","resolve","updateTenants","TenantSelectionProviderClient","children","initialValue","tenantCookie","tenantOptions","tenantOptionsFromProps","tenantsCollectionSlug","useAsTitle","setSelectedTenantID","useState","modified","user","config","userID","useMemo","id","setTenantOptions","selectedTenantLabel","find","option","value","label","router","setCookie","useCallback","expires","document","cookie","deleteCookie","refresh","length","String","req","fetch","serverURL","routes","api","credentials","method","result","json","docs","map","doc","e","error","prev","currentTenant","useEffect","span","data-selected-tenant-id","data-selected-tenant-title","useTenantSelection","use"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAO1D,KAAK,IAAI,GAAG;IACV,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,IAAI,CAAA;CACX,CAAA;AAED,eAAO,MAAM,uBAAuB,oEAMjC,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAO1D,KAAK,IAAI,GAAG;IACV,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,IAAI,CAAA;CACX,CAAA;AAED,eAAO,MAAM,uBAAuB,oEAMjC,IAAI,yCAoDN,CAAA"}
|
|
@@ -40,6 +40,8 @@ export const TenantSelectionProvider = async ({ children, payload, tenantsCollec
|
|
|
40
40
|
initialValue: initialValue,
|
|
41
41
|
tenantCookie: tenantCookie,
|
|
42
42
|
tenantOptions: tenantOptions,
|
|
43
|
+
tenantsCollectionSlug: tenantsCollectionSlug,
|
|
44
|
+
useAsTitle: useAsTitle,
|
|
43
45
|
children: children
|
|
44
46
|
});
|
|
45
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/providers/TenantSelectionProvider/index.tsx"],"sourcesContent":["import type { OptionObject, Payload, User } from 'payload'\n\nimport { cookies as getCookies } from 'next/headers.js'\n\nimport { findTenantOptions } from '../../queries/findTenantOptions.js'\nimport { TenantSelectionProviderClient } from './index.client.js'\n\ntype Args = {\n children: React.ReactNode\n payload: Payload\n tenantsCollectionSlug: string\n useAsTitle: string\n user: User\n}\n\nexport const TenantSelectionProvider = async ({\n children,\n payload,\n tenantsCollectionSlug,\n useAsTitle,\n user,\n}: Args) => {\n let tenantOptions: OptionObject[] = []\n\n try {\n const { docs } = await findTenantOptions({\n limit: 0,\n payload,\n tenantsCollectionSlug,\n useAsTitle,\n user,\n })\n tenantOptions = docs.map((doc) => ({\n label: String(doc[useAsTitle]),\n value: doc.id,\n }))\n } catch (_) {\n // user likely does not have access\n }\n\n const cookies = await getCookies()\n let tenantCookie = cookies.get('payload-tenant')?.value\n let initialValue = undefined\n\n /**\n * Ensure the cookie is a valid tenant\n */\n if (tenantCookie) {\n const matchingOption = tenantOptions.find((option) => String(option.value) === tenantCookie)\n if (matchingOption) {\n initialValue = matchingOption.value\n }\n }\n\n /**\n * If the there was no cookie or the cookie was an invalid tenantID set intialValue\n */\n if (!initialValue) {\n tenantCookie = undefined\n initialValue = tenantOptions.length > 1 ? undefined : tenantOptions[0]?.value\n }\n\n return (\n <TenantSelectionProviderClient\n initialValue={initialValue}\n tenantCookie={tenantCookie}\n tenantOptions={tenantOptions}\n >\n {children}\n </TenantSelectionProviderClient>\n )\n}\n"],"names":["cookies","getCookies","findTenantOptions","TenantSelectionProviderClient","TenantSelectionProvider","children","payload","tenantsCollectionSlug","useAsTitle","user","tenantOptions","docs","limit","map","doc","label","String","value","id","_","tenantCookie","get","initialValue","undefined","matchingOption","find","option","length"],"mappings":";AAEA,SAASA,WAAWC,UAAU,QAAQ,kBAAiB;AAEvD,SAASC,iBAAiB,QAAQ,qCAAoC;AACtE,SAASC,6BAA6B,QAAQ,oBAAmB;AAUjE,OAAO,MAAMC,0BAA0B,OAAO,EAC5CC,QAAQ,EACRC,OAAO,EACPC,qBAAqB,EACrBC,UAAU,EACVC,IAAI,EACC;IACL,IAAIC,gBAAgC,EAAE;IAEtC,IAAI;QACF,MAAM,EAAEC,IAAI,EAAE,GAAG,MAAMT,kBAAkB;YACvCU,OAAO;YACPN;YACAC;YACAC;YACAC;QACF;QACAC,gBAAgBC,KAAKE,GAAG,CAAC,CAACC,MAAS,CAAA;gBACjCC,OAAOC,OAAOF,GAAG,CAACN,WAAW;gBAC7BS,OAAOH,IAAII,EAAE;YACf,CAAA;IACF,EAAE,OAAOC,GAAG;IACV,mCAAmC;IACrC;IAEA,MAAMnB,UAAU,MAAMC;IACtB,IAAImB,eAAepB,QAAQqB,GAAG,CAAC,mBAAmBJ;IAClD,IAAIK,eAAeC;IAEnB;;GAEC,GACD,IAAIH,cAAc;QAChB,MAAMI,iBAAiBd,cAAce,IAAI,CAAC,CAACC,SAAWV,OAAOU,OAAOT,KAAK,MAAMG;QAC/E,IAAII,gBAAgB;YAClBF,eAAeE,eAAeP,KAAK;QACrC;IACF;IAEA;;GAEC,GACD,IAAI,CAACK,cAAc;QACjBF,eAAeG;QACfD,eAAeZ,cAAciB,MAAM,GAAG,IAAIJ,YAAYb,aAAa,CAAC,EAAE,EAAEO;IAC1E;IAEA,qBACE,KAACd;QACCmB,cAAcA;QACdF,cAAcA;QACdV,eAAeA;
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/TenantSelectionProvider/index.tsx"],"sourcesContent":["import type { OptionObject, Payload, User } from 'payload'\n\nimport { cookies as getCookies } from 'next/headers.js'\n\nimport { findTenantOptions } from '../../queries/findTenantOptions.js'\nimport { TenantSelectionProviderClient } from './index.client.js'\n\ntype Args = {\n children: React.ReactNode\n payload: Payload\n tenantsCollectionSlug: string\n useAsTitle: string\n user: User\n}\n\nexport const TenantSelectionProvider = async ({\n children,\n payload,\n tenantsCollectionSlug,\n useAsTitle,\n user,\n}: Args) => {\n let tenantOptions: OptionObject[] = []\n\n try {\n const { docs } = await findTenantOptions({\n limit: 0,\n payload,\n tenantsCollectionSlug,\n useAsTitle,\n user,\n })\n tenantOptions = docs.map((doc) => ({\n label: String(doc[useAsTitle]),\n value: doc.id,\n }))\n } catch (_) {\n // user likely does not have access\n }\n\n const cookies = await getCookies()\n let tenantCookie = cookies.get('payload-tenant')?.value\n let initialValue = undefined\n\n /**\n * Ensure the cookie is a valid tenant\n */\n if (tenantCookie) {\n const matchingOption = tenantOptions.find((option) => String(option.value) === tenantCookie)\n if (matchingOption) {\n initialValue = matchingOption.value\n }\n }\n\n /**\n * If the there was no cookie or the cookie was an invalid tenantID set intialValue\n */\n if (!initialValue) {\n tenantCookie = undefined\n initialValue = tenantOptions.length > 1 ? undefined : tenantOptions[0]?.value\n }\n\n return (\n <TenantSelectionProviderClient\n initialValue={initialValue}\n tenantCookie={tenantCookie}\n tenantOptions={tenantOptions}\n tenantsCollectionSlug={tenantsCollectionSlug}\n useAsTitle={useAsTitle}\n >\n {children}\n </TenantSelectionProviderClient>\n )\n}\n"],"names":["cookies","getCookies","findTenantOptions","TenantSelectionProviderClient","TenantSelectionProvider","children","payload","tenantsCollectionSlug","useAsTitle","user","tenantOptions","docs","limit","map","doc","label","String","value","id","_","tenantCookie","get","initialValue","undefined","matchingOption","find","option","length"],"mappings":";AAEA,SAASA,WAAWC,UAAU,QAAQ,kBAAiB;AAEvD,SAASC,iBAAiB,QAAQ,qCAAoC;AACtE,SAASC,6BAA6B,QAAQ,oBAAmB;AAUjE,OAAO,MAAMC,0BAA0B,OAAO,EAC5CC,QAAQ,EACRC,OAAO,EACPC,qBAAqB,EACrBC,UAAU,EACVC,IAAI,EACC;IACL,IAAIC,gBAAgC,EAAE;IAEtC,IAAI;QACF,MAAM,EAAEC,IAAI,EAAE,GAAG,MAAMT,kBAAkB;YACvCU,OAAO;YACPN;YACAC;YACAC;YACAC;QACF;QACAC,gBAAgBC,KAAKE,GAAG,CAAC,CAACC,MAAS,CAAA;gBACjCC,OAAOC,OAAOF,GAAG,CAACN,WAAW;gBAC7BS,OAAOH,IAAII,EAAE;YACf,CAAA;IACF,EAAE,OAAOC,GAAG;IACV,mCAAmC;IACrC;IAEA,MAAMnB,UAAU,MAAMC;IACtB,IAAImB,eAAepB,QAAQqB,GAAG,CAAC,mBAAmBJ;IAClD,IAAIK,eAAeC;IAEnB;;GAEC,GACD,IAAIH,cAAc;QAChB,MAAMI,iBAAiBd,cAAce,IAAI,CAAC,CAACC,SAAWV,OAAOU,OAAOT,KAAK,MAAMG;QAC/E,IAAII,gBAAgB;YAClBF,eAAeE,eAAeP,KAAK;QACrC;IACF;IAEA;;GAEC,GACD,IAAI,CAACK,cAAc;QACjBF,eAAeG;QACfD,eAAeZ,cAAciB,MAAM,GAAG,IAAIJ,YAAYb,aAAa,CAAC,EAAE,EAAEO;IAC1E;IAEA,qBACE,KAACd;QACCmB,cAAcA;QACdF,cAAcA;QACdV,eAAeA;QACfH,uBAAuBA;QACvBC,YAAYA;kBAEXH;;AAGP,EAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-multi-tenant",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.45.0-canary.0",
|
|
4
4
|
"description": "Multi Tenant plugin for Payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -80,15 +80,15 @@
|
|
|
80
80
|
"types.d.ts"
|
|
81
81
|
],
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@payloadcms/translations": "3.44.0",
|
|
84
|
-
"@payloadcms/ui": "3.44.0",
|
|
85
83
|
"@payloadcms/eslint-config": "3.28.0",
|
|
86
|
-
"
|
|
84
|
+
"@payloadcms/translations": "3.45.0-canary.0",
|
|
85
|
+
"@payloadcms/ui": "3.45.0-canary.0",
|
|
86
|
+
"payload": "3.45.0-canary.0"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"next": "^15.2.3",
|
|
90
|
-
"@payloadcms/ui": "3.
|
|
91
|
-
"payload": "3.
|
|
90
|
+
"@payloadcms/ui": "3.45.0-canary.0",
|
|
91
|
+
"payload": "3.45.0-canary.0"
|
|
92
92
|
},
|
|
93
93
|
"homepage:": "https://payloadcms.com",
|
|
94
94
|
"scripts": {
|