Commit a1674a5f by Archer Committed by GitHub

fix: action (#7128)

* fix: action

* perf: modal

* fix: openapi
parent 4f30121d
......@@ -119,6 +119,13 @@ jobs:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Ali Hub
if: matrix.image == 'fastgpt-agent-sandbox-proxy'
uses: docker/login-action@v3
with:
registry: registry.cn-hangzhou.aliyuncs.com
username: ${{ secrets.FASTGPT_ALI_IMAGE_USER }}
password: ${{ secrets.FASTGPT_ALI_IMAGE_PSW }}
- name: Download digests
uses: actions/download-artifact@v4
with:
......@@ -132,9 +139,20 @@ jobs:
- name: Set image name and tag
run: |
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}:${{ matrix.tag }}" >> $GITHUB_ENV
if [[ "${{ matrix.image }}" == "fastgpt-agent-sandbox-proxy" ]]; then
echo "Ali_Tag=${{ secrets.FASTGPT_ALI_IMAGE_PREFIX }}/${{ matrix.image }}:${{ matrix.tag }}" >> $GITHUB_ENV
fi
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create -t "${Git_Tag}" \
$(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}@sha256:%s ' *)
TAGS="${Git_Tag}"
if [[ -n "${Ali_Tag:-}" ]]; then
TAGS="$(echo -e "${TAGS}\n${Ali_Tag}")"
fi
for TAG in $TAGS; do
docker buildx imagetools create -t "${TAG}" \
$(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}@sha256:%s ' *)
sleep 5
done
......@@ -129,5 +129,21 @@ export const GetPreviewNodeQuerySchema = z.union([
export type GetPreviewNodeQuery = z.infer<typeof GetPreviewNodeQuerySchema>;
export const GetPreviewNodeQueryOpenAPISchema = GetPreviewNodeBaseQuerySchema.extend({
versionId: z.string().optional().meta({
example: '68ad85a7463006c963799a05',
description:
'工具版本 ID,与 getLatestVersion 必须二选一。传空字符串时返回最新版节点数据,但响应中的 version 为空'
}),
getLatestVersion: BoolSchema.optional().meta({
example: true,
description:
'是否获取最新版本 ID,与 versionId 必须二选一。只能传 true,表示返回最新版节点数据并带上具体 version'
})
}).meta({
description:
'OpenAPI 文档参数模型。运行时仍由 GetPreviewNodeQuerySchema 校验 versionId/getLatestVersion 的二选一约束。'
});
export const GetPreviewNodeResponseSchema = ToolPreviewNodeResponseSchema;
export type GetPreviewNodeResponse = z.infer<typeof GetPreviewNodeResponseSchema>;
import type { OpenAPIPath } from '../../../type';
import { TagsMap } from '../../../tag';
import {
GetPreviewNodeQuerySchema,
GetPreviewNodeQueryOpenAPISchema,
GetPreviewNodeResponseSchema,
GetSystemToolTemplatesBodySchema,
GetSystemToolTemplatesResponseSchema,
......@@ -61,7 +61,7 @@ export const ToolPath: OpenAPIPath = {
'根据工具 ID 和版本配置生成可插入工作流画布的工具节点模板,支持系统工具和我的工具(MCP、HTTP、工作流工具)',
tags: [TagsMap.appSystemTool, TagsMap.httpTools, TagsMap.mcpTools, TagsMap.pluginTeam],
requestParams: {
query: GetPreviewNodeQuerySchema
query: GetPreviewNodeQueryOpenAPISchema
},
responses: {
200: {
......
import { describe, expect, it } from 'vitest';
import { openAPIDocument } from '@fastgpt/global/openapi';
import { GetPreviewNodeQuerySchema } from '@fastgpt/global/openapi/core/app/tool/api';
describe('GetPreviewNodeQuerySchema', () => {
......@@ -51,4 +52,8 @@ describe('GetPreviewNodeQuerySchema', () => {
}).success
).toBe(false);
});
it('keeps full OpenAPI document generation compatible with query params', () => {
expect(openAPIDocument.paths['/core/app/tool/getPreviewNode']?.get).toBeDefined();
});
});
import React from 'react';
import { ModalBody, useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react';
import { useTheme, ModalFooter, Button, Box, Card, Flex, Grid } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import Avatar from '@fastgpt/web/components/common/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon';
......@@ -9,6 +9,7 @@ import dynamic from 'next/dynamic';
import { type AdminFbkType } from '@fastgpt/global/core/chat/type';
import SelectCollections from '@/web/core/dataset/components/SelectCollections';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
const InputDataModal = dynamic(
() => import('@/pageComponents/dataset/detail/components/InputDataModal')
......@@ -49,49 +50,51 @@ const SelectMarkCollection = ({
isLoading={isFetching}
tips={t('common:core.chat.Select dataset Desc')}
>
<ModalBody flex={'1 0 0'} overflowY={'auto'}>
<Grid
display={'grid'}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
>
{datasets.map((item) =>
(() => {
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
h={'80px'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
onClick={() => {
if (item.type === DatasetTypeEnum.folder) {
setParentId(item._id);
} else {
setAdminMarkData({ ...adminMarkData, datasetId: item._id });
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={item.avatar} w={'2rem'} borderRadius={'sm'}></Avatar>
<Box ml={3}>{item.name}</Box>
</Flex>
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
<MyIcon mr={1} name="kbTest" w={'12px'} />
<Box color={'myGray.500'}>{item.vectorModel.name}</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{datasets.length === 0 && <EmptyTip text={t('chat:empty_directory')}></EmptyTip>}
</ModalBody>
{datasets.length === 0 && <EmptyTip text={t('chat:empty_directory')}></EmptyTip>}
<Grid
display={'grid'}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
gridGap={3}
userSelect={'none'}
>
{datasets.map((item) =>
(() => {
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
h={'80px'}
cursor={'pointer'}
_hover={{
boxShadow: 'md'
}}
onClick={() => {
if (item.type === DatasetTypeEnum.folder) {
setParentId(item._id);
} else {
setAdminMarkData({ ...adminMarkData, datasetId: item._id });
}
}}
>
<Flex alignItems={'center'} h={'38px'}>
<Avatar src={item.avatar} w={'2rem'} borderRadius={'sm'}></Avatar>
<MyTooltip label={item.name} showOnlyWhenOverflow>
<Box ml={3} className="textEllipsis">
{item.name}
</Box>
</MyTooltip>
</Flex>
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
<MyIcon mr={1} name="kbTest" w={'12px'} />
<Box color={'myGray.500'}>{item.vectorModel.name}</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
</DatasetSelectModal>
)}
......@@ -109,20 +112,18 @@ const SelectMarkCollection = ({
});
}}
CustomFooter={
<ModalFooter>
<Button
variant={'whiteBase'}
mr={2}
onClick={() => {
setAdminMarkData({
...adminMarkData,
datasetId: undefined
});
}}
>
{t('common:last_step')}
</Button>
</ModalFooter>
<Button
variant={'whiteBase'}
mr={2}
onClick={() => {
setAdminMarkData({
...adminMarkData,
datasetId: undefined
});
}}
>
{t('common:last_step')}
</Button>
}
/>
)}
......
import { getDatasets, getDatasetPaths } from '@/web/core/dataset/api';
import MyModal from '@fastgpt/web/components/common/MyModal';
import MyModal from '@fastgpt/web/components/v2/common/MyModal';
import React, { type Dispatch, useState } from 'react';
import { useTranslation } from 'next-i18next';
import { Box } from '@chakra-ui/react';
import FolderPath from '@/components/common/folder/Path';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import type {
ParentIdType,
......@@ -32,7 +31,6 @@ const DatasetSelectContainer = ({
return (
<MyModal
iconSrc="/imgs/workflow/db.png"
title={
<Box fontWeight={'normal'}>
<FolderPath
......@@ -58,10 +56,9 @@ const DatasetSelectContainer = ({
w={'100%'}
maxW={['90vw', '900px']}
isCentered
isLoading={isLoading}
>
<MyBox isLoading={isLoading} h={'100%'}>
{children}
</MyBox>
{children}
</MyModal>
);
};
......
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyModal from '@fastgpt/web/components/common/MyModal';
import MyModal from '@fastgpt/web/components/v2/common/MyModal';
import FolderPath from '@/components/common/folder/Path';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import {
......@@ -118,7 +118,7 @@ const SelectCollections = ({
w={'100%'}
h={['90vh', '80vh']}
isCentered
iconSrc="/imgs/modal/move.svg"
isLoading={isLoading}
title={
<Box>
<FolderPath
......@@ -148,72 +148,10 @@ const SelectCollections = ({
/>
</Box>
}
>
<ModalBody flex={'1 0 0'} overflow={'auto'}>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']}
gridGap={3}
userSelect={'none'}
mt={2}
>
{collections.map((item) =>
(() => {
const selected = selectedDatasetCollectionIds.includes(item._id);
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
cursor={'pointer'}
_hover={{
bg: 'primary.50',
borderColor: 'primary.300'
}}
{...(selected
? {
bg: 'primary.200'
}
: {})}
onClick={() => {
if (item.type === DatasetCollectionTypeEnum.folder) {
setParentId(item._id);
} else {
let result: string[] = [];
if (max === 1) {
result = [item._id];
} else if (selected) {
result = selectedDatasetCollectionIds.filter((id) => id !== item._id);
} else if (selectedDatasetCollectionIds.length < max) {
result = [...selectedDatasetCollectionIds, item._id];
}
setSelectedDatasetCollectionIds(result);
onChange?.({ parentId, collectionIds: result });
}
}}
>
<Flex alignItems={'center'} h={'38px'} minW={0}>
<MyIcon name={item.icon as any} w={'18px'} flexShrink={0} />
<Box ml={3} fontSize={'sm'} minW={0} flex={1}>
<MyTooltip label={item.name} showOnlyWhenOverflow>
<Box className="textEllipsis">{item.name}</Box>
</MyTooltip>
</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{collections.length === 0 && (
<EmptyTip pt={'20vh'} text={t('common:no_child_folder')}></EmptyTip>
)}
<Loading loading={isLoading} fixed={false} />
</ModalBody>
{CustomFooter ? (
<>{CustomFooter}</>
) : (
<ModalFooter>
footer={
CustomFooter ? (
<>{CustomFooter}</>
) : (
<Button
isLoading={isResponding}
isDisabled={type === 'collection' && selectedDatasetCollectionIds.length === 0}
......@@ -221,7 +159,66 @@ const SelectCollections = ({
>
{type === 'folder' ? t('common:confirm_move') : t('common:Confirm')}
</Button>
</ModalFooter>
)
}
>
<Grid
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']}
gridGap={3}
userSelect={'none'}
mt={2}
>
{collections.map((item) =>
(() => {
const selected = selectedDatasetCollectionIds.includes(item._id);
return (
<Card
key={item._id}
p={3}
border={theme.borders.base}
boxShadow={'sm'}
cursor={'pointer'}
_hover={{
bg: 'primary.50',
borderColor: 'primary.300'
}}
{...(selected
? {
bg: 'primary.200'
}
: {})}
onClick={() => {
if (item.type === DatasetCollectionTypeEnum.folder) {
setParentId(item._id);
} else {
let result: string[] = [];
if (max === 1) {
result = [item._id];
} else if (selected) {
result = selectedDatasetCollectionIds.filter((id) => id !== item._id);
} else if (selectedDatasetCollectionIds.length < max) {
result = [...selectedDatasetCollectionIds, item._id];
}
setSelectedDatasetCollectionIds(result);
onChange?.({ parentId, collectionIds: result });
}
}}
>
<Flex alignItems={'center'} h={'38px'} minW={0}>
<MyIcon name={item.icon as any} w={'18px'} flexShrink={0} />
<Box ml={3} fontSize={'sm'} minW={0} flex={1}>
<MyTooltip label={item.name} showOnlyWhenOverflow>
<Box className="textEllipsis">{item.name}</Box>
</MyTooltip>
</Box>
</Flex>
</Card>
);
})()
)}
</Grid>
{collections.length === 0 && (
<EmptyTip pt={'20vh'} text={t('common:no_child_folder')}></EmptyTip>
)}
</MyModal>
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment