fix: missing x-data-source parameter in duplicate request template for external data source block (#5882)

* fix: issue with external data source collection duplicate failing to get data template

* fix: missing x-data-source parameter in duplicate request template for external data source block

* fix: date template with external data source

* fix: bug

* fix: data template with multi primary keys

---------

Co-authored-by: Chareice <chareice@live.com>
This commit is contained in:
Katherine 2024-12-17 11:06:51 +08:00 committed by GitHub
parent 347d43c0c5
commit 0c742fc3ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 35 additions and 13 deletions

View File

@ -2,9 +2,7 @@
"version": "1.4.10", "version": "1.4.10",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"npmClientArgs": [ "npmClientArgs": ["--ignore-engines"],
"--ignore-engines"
],
"command": { "command": {
"version": { "version": {
"forcePublish": true, "forcePublish": true,

View File

@ -19,6 +19,7 @@ import { useCollectionManager_deprecated } from '../../../collection-manager';
import { compatibleDataId } from '../../../schema-settings/DataTemplates/FormDataTemplates'; import { compatibleDataId } from '../../../schema-settings/DataTemplates/FormDataTemplates';
import { useToken } from '../__builtins__'; import { useToken } from '../__builtins__';
import { RemoteSelect } from '../remote-select'; import { RemoteSelect } from '../remote-select';
import { useDataSourceHeaders, useDataSourceKey } from '../../../data-source';
export interface ITemplate { export interface ITemplate {
config?: { config?: {
@ -101,11 +102,13 @@ export const Templates = ({ style = {}, form }: { style?: React.CSSProperties; f
const [targetTemplateData, setTemplateData] = useState(null); const [targetTemplateData, setTemplateData] = useState(null);
const api = useAPIClient(); const api = useAPIClient();
const { t } = useTranslation(); const { t } = useTranslation();
const dataSource = useDataSourceKey();
const headers = useDataSourceHeaders(dataSource);
useEffect(() => { useEffect(() => {
if (enabled && defaultTemplate && form) { if (enabled && defaultTemplate && form) {
form.__template = true; form.__template = true;
if (defaultTemplate.key === 'duplicate') { if (defaultTemplate.key === 'duplicate') {
handleTemplateDataChange(defaultTemplate.dataId, defaultTemplate); handleTemplateDataChange(defaultTemplate.dataId, defaultTemplate, headers);
} }
} }
}, []); }, []);
@ -139,10 +142,10 @@ export const Templates = ({ style = {}, form }: { style?: React.CSSProperties; f
form?.reset(); form?.reset();
}, []); }, []);
const handleTemplateDataChange: any = useCallback(async (value, option) => { const handleTemplateDataChange: any = useCallback(async (value, option, headers) => {
const template = { ...option, dataId: value }; const template = { ...option, dataId: value };
setTemplateData(option); setTemplateData(option);
fetchTemplateData(api, template, t) fetchTemplateData(api, template, headers)
.then((data) => { .then((data) => {
if (form && data) { if (form && data) {
// 切换之前先把之前的数据清空 // 切换之前先把之前的数据清空
@ -194,7 +197,7 @@ export const Templates = ({ style = {}, form }: { style?: React.CSSProperties; f
filter: template?.dataScope, filter: template?.dataScope,
}, },
}} }}
onChange={(value) => handleTemplateDataChange(value?.id, { ...value, ...template })} onChange={(value) => handleTemplateDataChange(value?.id, { ...value, ...template }, headers)}
targetField={getCollectionJoinField(`${template?.collection}.${template.titleField}`)} targetField={getCollectionJoinField(`${template?.collection}.${template.titleField}`)}
/> />
)} )}
@ -211,12 +214,16 @@ function findDataTemplates(fieldSchema): ITemplate {
return {} as ITemplate; return {} as ITemplate;
} }
export async function fetchTemplateData(api, template: { collection: string; dataId: number; fields: string[] }, t) { export async function fetchTemplateData(
api,
template: { collection: string; dataId: number; fields: string[] },
headers?,
) {
if (template.fields.length === 0 || !template.dataId) { if (template.fields.length === 0 || !template.dataId) {
return; return;
} }
return api return api
.resource(template.collection) .resource(template.collection, undefined, headers)
.get({ .get({
filterByTk: template.dataId, filterByTk: template.dataId,
fields: template.fields, fields: template.fields,

View File

@ -18,7 +18,7 @@ export async function dataTemplate(ctx: Context, next) {
if (isTemplate && actionName === 'get') { if (isTemplate && actionName === 'get') {
ctx.body = traverseJSON(JSON.parse(JSON.stringify(ctx.body)), { ctx.body = traverseJSON(JSON.parse(JSON.stringify(ctx.body)), {
collection: ctx.db.getCollection(resourceName), collection: ctx.getCurrentRepository().collection,
include: [...(fields || []), ...(appends || [])], include: [...(fields || []), ...(appends || [])],
}); });
} }
@ -75,6 +75,7 @@ const traverseJSON = (data, options: TraverseOptions) => {
if (!data) { if (!data) {
return data; return data;
} }
const { collection, exclude = [], include = [], excludePk = true } = options; const { collection, exclude = [], include = [], excludePk = true } = options;
const map = parseInclude(include); const map = parseInclude(include);
const result = {}; const result = {};
@ -94,9 +95,11 @@ const traverseJSON = (data, options: TraverseOptions) => {
result[key] = data[key]; result[key] = data[key];
continue; continue;
} }
if (field.options.primaryKey && excludePk) {
if (field.options.primaryKey && excludePk && !collection.isMultiFilterTargetKey()) {
continue; continue;
} }
if (field.options.isForeignKey) { if (field.options.isForeignKey) {
continue; continue;
} }

View File

@ -27,6 +27,9 @@ import {
useDesignable, useDesignable,
useFormBlockContext, useFormBlockContext,
useRecord, useRecord,
useCollection,
useDataSourceHeaders,
useDataSourceKey,
} from '@nocobase/client'; } from '@nocobase/client';
import { App, Button } from 'antd'; import { App, Button } from 'antd';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
@ -87,6 +90,7 @@ export const DuplicateAction = observer(
const { duplicateFields, duplicateMode = 'quickDulicate', duplicateCollection } = fieldSchema['x-component-props']; const { duplicateFields, duplicateMode = 'quickDulicate', duplicateCollection } = fieldSchema['x-component-props'];
const record = useRecord(); const record = useRecord();
const parentRecordData: any = useCollectionParentRecordData(); const parentRecordData: any = useCollectionParentRecordData();
const collection = useCollection();
const { id, __collection } = record; const { id, __collection } = record;
const ctx = useActionContext(); const ctx = useActionContext();
const { name } = useCollection_deprecated(); const { name } = useCollection_deprecated();
@ -95,6 +99,16 @@ export const DuplicateAction = observer(
const collectionFields = getCollectionFields(__collection || name); const collectionFields = getCollectionFields(__collection || name);
const formctx = useFormBlockContext(); const formctx = useFormBlockContext();
const aclCtx = useACLActionParamsContext(); const aclCtx = useACLActionParamsContext();
const dataSource = useDataSourceKey();
const headers = useDataSourceHeaders(dataSource);
const dataId = Array.isArray(collection.filterTargetKey)
? Object.assign(
{},
...collection.filterTargetKey.map((v) => {
return { [v]: record[v] };
}),
)
: record[collection.filterTargetKey] || id;
const buttonStyle = useMemo(() => { const buttonStyle = useMemo(() => {
return { return {
opacity: designable && (field?.data?.hidden || !aclCtx) && 0.1, opacity: designable && (field?.data?.hidden || !aclCtx) && 0.1,
@ -102,7 +116,7 @@ export const DuplicateAction = observer(
}, [designable, field?.data?.hidden]); }, [designable, field?.data?.hidden]);
const template = { const template = {
key: 'duplicate', key: 'duplicate',
dataId: id, dataId,
default: true, default: true,
fields: fields:
duplicateFields?.filter((v) => { duplicateFields?.filter((v) => {
@ -114,7 +128,7 @@ export const DuplicateAction = observer(
const handelQuickDuplicate = async () => { const handelQuickDuplicate = async () => {
setLoading(true); setLoading(true);
try { try {
const data = await fetchTemplateData(api, template, t); const data = await fetchTemplateData(api, template, headers);
await resource['create']({ await resource['create']({
values: { values: {
...data, ...data,