Compare commits
5 Commits
v4.9.5-alp
...
v4.9.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b943d05d5a | ||
|
|
2af3cd83f2 | ||
|
|
ea74c669ee | ||
|
|
38597d8f04 | ||
|
|
88ed019717 |
292
.github/workflows/fastgpt-build-image.yml
vendored
292
.github/workflows/fastgpt-build-image.yml
vendored
@@ -1,12 +1,14 @@
|
||||
name: Build FastGPT images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'projects/app/**'
|
||||
- 'packages/**'
|
||||
- "projects/app/**"
|
||||
- "packages/**"
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build-fastgpt-images:
|
||||
permissions:
|
||||
@@ -14,260 +16,156 @@ jobs:
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
sub_routes:
|
||||
- repo: fastgpt
|
||||
base_url: ""
|
||||
- repo: fastgpt-sub-route
|
||||
base_url: "/fastai"
|
||||
- repo: fastgpt-sub-route-gchat
|
||||
base_url: "/gchat"
|
||||
archs:
|
||||
- arch: amd64
|
||||
- arch: arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.archs.runs-on || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
# install env
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y nodejs npm
|
||||
- name: Set up QEMU (optional)
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: network=host
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
key: ${{ runner.os }}-${{ matrix.sub_routes.repo }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
${{ runner.os }}-${{ matrix.sub_routes.repo }}-buildx-
|
||||
|
||||
# login docker
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to Ali Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALI_HUB_USERNAME }}
|
||||
password: ${{ secrets.ALI_HUB_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
# Set tag
|
||||
- name: Set image name and tag
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt:latest" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Build for ${{ matrix.archs.arch }}
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: projects/app/Dockerfile
|
||||
platforms: linux/${{ matrix.archs.arch }}
|
||||
build-args: |
|
||||
${{ matrix.sub_routes.base_url && format('base_url={0}', matrix.sub_routes.base_url) || '' }}
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }}
|
||||
org.opencontainers.image.description=${{ matrix.sub_routes.repo }} image
|
||||
outputs: type=image,"name=ghcr.io/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }},${{ secrets.ALI_IMAGE_NAME }}/${{ matrix.sub_routes.repo }},${{ secrets.DOCKER_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}",push-by-digest=true,push=true
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
|
||||
- name: Build and publish image for main branch or tag push event
|
||||
env:
|
||||
DOCKER_REPO_TAGGED: ${{ env.DOCKER_REPO_TAGGED }}
|
||||
- name: Export digest
|
||||
run: |
|
||||
docker buildx build \
|
||||
-f projects/app/Dockerfile \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
|
||||
--label "org.opencontainers.image.description=fastgpt image" \
|
||||
--push \
|
||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache \
|
||||
-t ${Git_Tag} \
|
||||
-t ${Git_Latest} \
|
||||
-t ${Ali_Tag} \
|
||||
-t ${Ali_Latest} \
|
||||
-t ${Docker_Hub_Tag} \
|
||||
-t ${Docker_Hub_Latest} \
|
||||
.
|
||||
build-fastgpt-images-sub-route:
|
||||
mkdir -p ${{ runner.temp }}/digests/${{ matrix.sub_routes.repo }}
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${{ matrix.sub_routes.repo }}/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ matrix.sub_routes.repo }}-${{ github.sha }}-${{ matrix.archs.arch }}
|
||||
path: ${{ runner.temp }}/digests/${{ matrix.sub_routes.repo }}/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
release-fastgpt-images:
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-20.04
|
||||
needs: build-fastgpt-images
|
||||
strategy:
|
||||
matrix:
|
||||
sub_routes:
|
||||
- repo: fastgpt
|
||||
- repo: fastgpt-sub-route
|
||||
- repo: fastgpt-sub-route-gchat
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
# install env
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y nodejs npm
|
||||
- name: Set up QEMU (optional)
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: network=host
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
# login docker
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to Ali Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALI_HUB_USERNAME }}
|
||||
password: ${{ secrets.ALI_HUB_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
# Set tag
|
||||
- name: Set image name and tag
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route:latest" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Build and publish image for main branch or tag push event
|
||||
env:
|
||||
DOCKER_REPO_TAGGED: ${{ env.DOCKER_REPO_TAGGED }}
|
||||
run: |
|
||||
docker buildx build \
|
||||
-f projects/app/Dockerfile \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--build-arg base_url=/fastai \
|
||||
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
|
||||
--label "org.opencontainers.image.description=fastgpt image" \
|
||||
--push \
|
||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache \
|
||||
-t ${Git_Tag} \
|
||||
-t ${Git_Latest} \
|
||||
-t ${Ali_Tag} \
|
||||
-t ${Ali_Latest} \
|
||||
-t ${Docker_Hub_Tag} \
|
||||
-t ${Docker_Hub_Latest} \
|
||||
.
|
||||
build-fastgpt-images-sub-route-gchat:
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
# install env
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y nodejs npm
|
||||
- name: Set up QEMU (optional)
|
||||
uses: docker/setup-qemu-action@v2
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-${{ matrix.sub_routes.repo }}-${{ github.sha }}-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver-opts: network=host
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# login docker
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to Ali Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALI_HUB_USERNAME }}
|
||||
password: ${{ secrets.ALI_HUB_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
# Set tag
|
||||
- name: Set image name and tag
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route-gchat:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route-gchat:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route-gchat:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sub-route-gchat:latest" >> $GITHUB_ENV
|
||||
echo "Git_Tag=ghcr.io/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }}:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Git_Latest=ghcr.io/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Ali_Tag=${{ secrets.ALI_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Ali_Latest=${{ secrets.ALI_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Tag=${{ secrets.DOCKER_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/${{ matrix.sub_routes.repo }}:latest" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Build and publish image for main branch or tag push event
|
||||
env:
|
||||
DOCKER_REPO_TAGGED: ${{ env.DOCKER_REPO_TAGGED }}
|
||||
- name: Create manifest list and push
|
||||
working-directory: ${{ runner.temp }}/digests
|
||||
run: |
|
||||
docker buildx build \
|
||||
-f projects/app/Dockerfile \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--build-arg base_url=/gchat \
|
||||
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/FastGPT" \
|
||||
--label "org.opencontainers.image.description=fastgpt-sub-route-gchat image" \
|
||||
--push \
|
||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache \
|
||||
-t ${Git_Tag} \
|
||||
-t ${Git_Latest} \
|
||||
-t ${Ali_Tag} \
|
||||
-t ${Ali_Latest} \
|
||||
-t ${Docker_Hub_Tag} \
|
||||
-t ${Docker_Hub_Latest} \
|
||||
.
|
||||
TAGS="$(echo -e "${Git_Tag}\n${Git_Latest}\n${Ali_Tag}\n${Ali_Latest}\n${Docker_Hub_Tag}\n${Docker_Hub_Latest}")"
|
||||
for TAG in $TAGS; do
|
||||
docker buildx imagetools create -t $TAG \
|
||||
$(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.sub_routes.repo }}@sha256:%s ' *)
|
||||
sleep 5
|
||||
done
|
||||
|
||||
122
.github/workflows/sandbox-build-image.yml
vendored
122
.github/workflows/sandbox-build-image.yml
vendored
@@ -13,50 +13,115 @@ jobs:
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
- arch: arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runs-on || 'ubuntu-24.04' }}
|
||||
steps:
|
||||
# install env
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y nodejs npm
|
||||
- name: Set up QEMU (optional)
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: network=host
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
key: ${{ runner.os }}-sandbox-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
${{ runner.os }}-sandbox-buildx-
|
||||
|
||||
# login docker
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to Ali Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALI_HUB_USERNAME }}
|
||||
password: ${{ secrets.ALI_HUB_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
# Set tag
|
||||
- name: Build for ${{ matrix.arch }}
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: projects/sandbox/Dockerfile
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/fastgpt-sandbox
|
||||
org.opencontainers.image.description=fastgpt-sandbox image
|
||||
outputs: type=image,"name=ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox,${{ secrets.ALI_IMAGE_NAME }}/fastgpt-sandbox,${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sandbox",push-by-digest=true,push=true
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-fastgpt-sandbox-${{ github.sha }}-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
release-fastgpt-sandbox-images:
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
attestations: write
|
||||
id-token: write
|
||||
needs: build-fastgpt-sandbox-images
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Login to Ali Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-hangzhou.aliyuncs.com
|
||||
username: ${{ secrets.ALI_HUB_USERNAME }}
|
||||
password: ${{ secrets.ALI_HUB_PASSWORD }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_NAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-fastgpt-sandbox-${{ github.sha }}-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set image name and tag
|
||||
run: |
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
@@ -75,27 +140,12 @@ jobs:
|
||||
echo "Docker_Hub_Latest=${{ secrets.DOCKER_IMAGE_NAME }}/fastgpt-sandbox:latest" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Build and publish image for main branch or tag push event
|
||||
env:
|
||||
Git_Tag: ${{ env.Git_Tag }}
|
||||
Git_Latest: ${{ env.Git_Latest }}
|
||||
Ali_Tag: ${{ env.Ali_Tag }}
|
||||
Ali_Latest: ${{ env.Ali_Latest }}
|
||||
Docker_Hub_Tag: ${{ env.Docker_Hub_Tag }}
|
||||
Docker_Hub_Latest: ${{ env.Docker_Hub_Latest }}
|
||||
- name: Create manifest list and push
|
||||
working-directory: ${{ runner.temp }}/digests
|
||||
run: |
|
||||
docker buildx build \
|
||||
-f projects/sandbox/Dockerfile \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--label "org.opencontainers.image.source=https://github.com/${{ github.repository_owner }}/fastgpt-sandbox" \
|
||||
--label "org.opencontainers.image.description=fastgpt-sandbox image" \
|
||||
--push \
|
||||
--cache-from=type=local,src=/tmp/.buildx-cache \
|
||||
--cache-to=type=local,dest=/tmp/.buildx-cache \
|
||||
-t ${Git_Tag} \
|
||||
-t ${Git_Latest} \
|
||||
-t ${Ali_Tag} \
|
||||
-t ${Ali_Latest} \
|
||||
-t ${Docker_Hub_Tag} \
|
||||
-t ${Docker_Hub_Latest} \
|
||||
.
|
||||
TAGS="$(echo -e "${Git_Tag}\n${Git_Latest}\n${Ali_Tag}\n${Ali_Latest}\n${Docker_Hub_Tag}\n${Docker_Hub_Latest}")"
|
||||
for TAG in $TAGS; do
|
||||
docker buildx imagetools create -t $TAG \
|
||||
$(printf 'ghcr.io/${{ github.repository_owner }}/fastgpt-sandbox@sha256:%s ' *)
|
||||
sleep 5
|
||||
done
|
||||
|
||||
@@ -13,6 +13,7 @@ weight: 795
|
||||
1. 团队成员权限细分,可分别控制是否可创建在根目录应用/知识库以及 API Key
|
||||
2. 支持交互节点在嵌套工作流中使用。
|
||||
3. 团队成员操作日志。
|
||||
4. 用户输入节点支持多选框。
|
||||
|
||||
## ⚙️ 优化
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ export enum FlowNodeInputTypeEnum { // render ui
|
||||
numberInput = 'numberInput',
|
||||
switch = 'switch', // true/false
|
||||
select = 'select',
|
||||
multipleSelect = 'multipleSelect',
|
||||
|
||||
// editor
|
||||
JSONEditor = 'JSONEditor',
|
||||
@@ -46,6 +47,9 @@ export const FlowNodeInputMap: Record<
|
||||
[FlowNodeInputTypeEnum.select]: {
|
||||
icon: 'core/workflow/inputType/option'
|
||||
},
|
||||
[FlowNodeInputTypeEnum.multipleSelect]: {
|
||||
icon: 'core/workflow/inputType/option'
|
||||
},
|
||||
[FlowNodeInputTypeEnum.switch]: {
|
||||
icon: 'core/workflow/inputType/switch'
|
||||
},
|
||||
|
||||
@@ -132,6 +132,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
externalProvider,
|
||||
stream = false,
|
||||
version = 'v1',
|
||||
responseDetail = true,
|
||||
...props
|
||||
} = data;
|
||||
|
||||
@@ -638,7 +639,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
!props.isToolCall &&
|
||||
isRootRuntime &&
|
||||
formatResponseData &&
|
||||
!(!props.responseDetail && filterModuleTypeList.includes(formatResponseData.moduleType))
|
||||
!(responseDetail === false && filterModuleTypeList.includes(formatResponseData.moduleType))
|
||||
) {
|
||||
props.workflowStreamResponse?.({
|
||||
event: SseResponseEventEnum.flowNodeResponse,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonProps,
|
||||
Checkbox,
|
||||
Flex,
|
||||
@@ -26,13 +27,14 @@ export type SelectProps<T = any> = {
|
||||
}[];
|
||||
value: T[];
|
||||
isSelectAll: boolean;
|
||||
setIsSelectAll: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setIsSelectAll?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
||||
placeholder?: string;
|
||||
maxH?: number;
|
||||
itemWrap?: boolean;
|
||||
onSelect: (val: T[]) => void;
|
||||
closeable?: boolean;
|
||||
isDisabled?: boolean;
|
||||
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||
} & Omit<ButtonProps, 'onSelect'>;
|
||||
|
||||
@@ -47,6 +49,7 @@ const MultipleSelect = <T = any,>({
|
||||
ScrollData,
|
||||
isSelectAll,
|
||||
setIsSelectAll,
|
||||
isDisabled = false,
|
||||
...props
|
||||
}: SelectProps<T>) => {
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
@@ -70,7 +73,7 @@ const MultipleSelect = <T = any,>({
|
||||
// 全选状态下,value 实际上上空。
|
||||
if (isSelectAll) {
|
||||
onSelect(list.map((item) => item.value).filter((i) => i !== val));
|
||||
setIsSelectAll(false);
|
||||
setIsSelectAll?.(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,7 +90,7 @@ const MultipleSelect = <T = any,>({
|
||||
const hasSelected = isSelectAll || value.length > 0;
|
||||
onSelect(hasSelected ? [] : list.map((item) => item.value));
|
||||
|
||||
setIsSelectAll((state) => !state);
|
||||
setIsSelectAll?.((state) => !state);
|
||||
}, [value, list, setIsSelectAll, onSelect]);
|
||||
|
||||
const ListRender = useMemo(() => {
|
||||
@@ -126,11 +129,11 @@ const MultipleSelect = <T = any,>({
|
||||
}, [value, list, isSelectAll]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box h={'100%'} w={'100%'}>
|
||||
<Menu
|
||||
autoSelect={false}
|
||||
isOpen={isOpen}
|
||||
onOpen={onOpen}
|
||||
isOpen={isOpen && !isDisabled}
|
||||
onOpen={isDisabled ? undefined : onOpen}
|
||||
onClose={onClose}
|
||||
strategy={'fixed'}
|
||||
matchWidth
|
||||
@@ -138,21 +141,23 @@ const MultipleSelect = <T = any,>({
|
||||
>
|
||||
<MenuButton
|
||||
as={Flex}
|
||||
h={'100%'}
|
||||
alignItems={'center'}
|
||||
ref={ref}
|
||||
px={3}
|
||||
borderRadius={'md'}
|
||||
border={'base'}
|
||||
userSelect={'none'}
|
||||
cursor={'pointer'}
|
||||
cursor={isDisabled ? 'not-allowed' : 'pointer'}
|
||||
_active={{
|
||||
transform: 'none'
|
||||
}}
|
||||
_hover={{
|
||||
borderColor: 'primary.300'
|
||||
borderColor: isDisabled ? 'myGray.200' : 'primary.300'
|
||||
}}
|
||||
opacity={isDisabled ? 0.6 : 1}
|
||||
{...props}
|
||||
{...(isOpen
|
||||
{...(isOpen && !isDisabled
|
||||
? {
|
||||
boxShadow: '0px 0px 4px #A8DBFF',
|
||||
borderColor: 'primary.500',
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"ifelse.Input value": "Input Value",
|
||||
"ifelse.Select value": "Select Value",
|
||||
"input_description": "Field Description",
|
||||
"input_type_multiple_select": "Multiple selection boxes",
|
||||
"input_variable_list": "Type / to invoke variable list",
|
||||
"intro_assigned_reply": "This module can directly reply with a specified content. Commonly used for guidance or prompts. Non-string content will be converted to string for output.",
|
||||
"intro_custom_feedback": "When this module is triggered, a feedback will be added to the current conversation record. It can be used to automatically record conversation effects, etc.",
|
||||
@@ -152,6 +153,7 @@
|
||||
"response.read files": "Read Files",
|
||||
"select_an_application": "Select an Application",
|
||||
"select_another_application_to_call": "You can choose another application to call",
|
||||
"select_default_option": "Select the default value",
|
||||
"special_array_format": "Special array format, returns an empty array when the search result is empty.",
|
||||
"start_with": "Starts With",
|
||||
"support_code_language": "Support import list: pandas,numpy",
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"ifelse.Input value": "输入值",
|
||||
"ifelse.Select value": "选择值",
|
||||
"input_description": "字段描述",
|
||||
"input_type_multiple_select": "多选框",
|
||||
"input_variable_list": "可输入 / 唤起变量列表",
|
||||
"intro_assigned_reply": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
|
||||
"intro_custom_feedback": "该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。",
|
||||
@@ -152,6 +153,7 @@
|
||||
"response.read files": "解析的文档",
|
||||
"select_an_application": "选择一个应用",
|
||||
"select_another_application_to_call": "可以选择一个其他应用进行调用",
|
||||
"select_default_option": "选择默认值",
|
||||
"special_array_format": "特殊数组格式,搜索结果为空时,返回空数组。",
|
||||
"start_with": "开始为",
|
||||
"support_code_language": "支持import列表:pandas,numpy",
|
||||
@@ -201,4 +203,4 @@
|
||||
"workflow.Switch_success": "切换成功",
|
||||
"workflow.Team cloud": "团队云端",
|
||||
"workflow.exit_tips": "您的更改尚未保存,「直接退出」将不会保存您的编辑记录。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"ifelse.Input value": "輸入值",
|
||||
"ifelse.Select value": "選擇值",
|
||||
"input_description": "欄位描述",
|
||||
"input_type_multiple_select": "多選框",
|
||||
"input_variable_list": "輸入 / 叫出變數清單",
|
||||
"intro_assigned_reply": "這個模組可以直接回覆指定的內容。常用於引導、提示。非字串內容傳入時,會轉換成字串輸出。",
|
||||
"intro_custom_feedback": "當這個模組被觸發時,會在目前的對話紀錄中新增一條回饋。可以用於自動記錄對話效果等等。",
|
||||
@@ -152,6 +153,7 @@
|
||||
"response.read files": "解析的檔案",
|
||||
"select_an_application": "選擇一個應用程式",
|
||||
"select_another_application_to_call": "可以選擇另一個應用程式來呼叫",
|
||||
"select_default_option": "選擇默認值",
|
||||
"special_array_format": "特殊陣列格式,搜尋結果為空時,回傳空陣列。",
|
||||
"start_with": "開頭為",
|
||||
"support_code_language": "支援 import 列表:pandas,numpy",
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
UserSelectInteractive,
|
||||
UserSelectOptionItemType
|
||||
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||
import MultipleSelect from '@fastgpt/web/components/common/MySelect/MultipleSelect';
|
||||
|
||||
const DescriptionBox = React.memo(function DescriptionBox({
|
||||
description
|
||||
@@ -173,6 +174,30 @@ export const FormInputComponent = React.memo(function FormInputComponent({
|
||||
}}
|
||||
/>
|
||||
);
|
||||
case FlowNodeInputTypeEnum.multipleSelect:
|
||||
return (
|
||||
<Controller
|
||||
key={label}
|
||||
control={control}
|
||||
name={label}
|
||||
rules={{ required: required }}
|
||||
render={({ field: { ref, value } }) => {
|
||||
if (!list) return <></>;
|
||||
return (
|
||||
<MultipleSelect<string>
|
||||
width={'100%'}
|
||||
bg={'white'}
|
||||
py={2}
|
||||
list={list}
|
||||
value={value}
|
||||
isDisabled={submitted}
|
||||
onSelect={(e) => setValue(label, e)}
|
||||
isSelectAll={value.length === list.length}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import {
|
||||
Td,
|
||||
Th,
|
||||
Thead,
|
||||
Tr
|
||||
Tr,
|
||||
HStack
|
||||
} from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
|
||||
import { getOperationLogs } from '@/web/support/user/team/operantionLog/api';
|
||||
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
|
||||
@@ -21,28 +21,125 @@ import { operationLogI18nMap } from '@fastgpt/service/support/operationLog/const
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time';
|
||||
import UserBox from '@fastgpt/web/components/common/UserBox';
|
||||
import MultipleSelect, {
|
||||
useMultipleSelect
|
||||
} from '@fastgpt/web/components/common/MySelect/MultipleSelect';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
import { getTeamMembers } from '@/web/support/user/team/api';
|
||||
|
||||
function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
|
||||
const { t } = useTranslation();
|
||||
const [searchParams, setSearchParams] = useState<{
|
||||
tmbIds?: string[];
|
||||
events?: OperationLogEventEnum[];
|
||||
}>({});
|
||||
|
||||
const { data: members, ScrollData } = useScrollPagination(getTeamMembers, {});
|
||||
const tmbList = useMemo(
|
||||
() =>
|
||||
members.map((item) => ({
|
||||
label: (
|
||||
<HStack spacing={1} color={'myGray.500'}>
|
||||
<Avatar src={item.avatar} w={'1.2rem'} mr={1} rounded={'full'} />
|
||||
<Box>{item.memberName}</Box>
|
||||
</HStack>
|
||||
),
|
||||
value: item.tmbId
|
||||
})),
|
||||
[members]
|
||||
);
|
||||
|
||||
const eventOptions = useMemo(
|
||||
() =>
|
||||
Object.values(OperationLogEventEnum).map((event) => ({
|
||||
label: t(operationLogI18nMap[event].typeLabel),
|
||||
value: event
|
||||
})),
|
||||
[t]
|
||||
);
|
||||
|
||||
const [searchKey, setSearchKey] = useState<string>('');
|
||||
const {
|
||||
data: operationLogs = [],
|
||||
isLoading: loadingLogs,
|
||||
ScrollData: LogScrollData
|
||||
} = useScrollPagination(getOperationLogs, {
|
||||
pageSize: 20,
|
||||
refreshDeps: [searchKey],
|
||||
throttleWait: 500,
|
||||
debounceWait: 200
|
||||
refreshDeps: [searchParams],
|
||||
params: searchParams
|
||||
});
|
||||
|
||||
const {
|
||||
value: selectedTmbIds,
|
||||
setValue: setSelectedTmbIds,
|
||||
isSelectAll: isSelectAllTmb,
|
||||
setIsSelectAll: setIsSelectAllTmb
|
||||
} = useMultipleSelect<string>(
|
||||
tmbList.map((item) => item.value),
|
||||
true
|
||||
);
|
||||
|
||||
const {
|
||||
value: selectedEvents,
|
||||
setValue: setSelectedEvents,
|
||||
isSelectAll: isSelectAllEvent,
|
||||
setIsSelectAll: setIsSelectAllEvent
|
||||
} = useMultipleSelect<OperationLogEventEnum>(
|
||||
eventOptions.map((item) => item.value),
|
||||
true
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setSearchParams({
|
||||
...(isSelectAllTmb ? {} : { tmbIds: selectedTmbIds }),
|
||||
...(isSelectAllEvent ? {} : { events: selectedEvents })
|
||||
});
|
||||
}, [selectedTmbIds, selectedEvents, isSelectAllTmb, isSelectAllEvent]);
|
||||
|
||||
const isLoading = loadingLogs;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex justify={'space-between'} align={'center'} pb={'1rem'}>
|
||||
<Flex justify={'flex-start'} align={'center'} pb={'1rem'} gap={2} wrap="wrap">
|
||||
{Tabs}
|
||||
<Flex alignItems={'center'} gap={2}>
|
||||
<Box fontSize={'mini'} fontWeight={'medium'} color={'myGray.900'}>
|
||||
{t('account_team:log_user')}
|
||||
</Box>
|
||||
<Box>
|
||||
<MultipleSelect<string>
|
||||
list={tmbList}
|
||||
value={selectedTmbIds}
|
||||
onSelect={(val) => {
|
||||
setSelectedTmbIds(val as string[]);
|
||||
}}
|
||||
itemWrap={false}
|
||||
height={'32px'}
|
||||
bg={'myGray.50'}
|
||||
w={'160px'}
|
||||
ScrollData={ScrollData}
|
||||
isSelectAll={isSelectAllTmb}
|
||||
setIsSelectAll={setIsSelectAllTmb}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex alignItems={'center'} gap={2}>
|
||||
<Box fontSize={'mini'} fontWeight={'medium'} color={'myGray.900'}>
|
||||
{t('account_team:log_type')}
|
||||
</Box>
|
||||
<Box>
|
||||
<MultipleSelect
|
||||
list={eventOptions}
|
||||
value={selectedEvents}
|
||||
onSelect={setSelectedEvents}
|
||||
isSelectAll={isSelectAllEvent}
|
||||
setIsSelectAll={setIsSelectAllEvent}
|
||||
itemWrap={false}
|
||||
height={'32px'}
|
||||
bg={'myGray.50'}
|
||||
w={'160px'}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<MyBox isLoading={isLoading} flex={'1 0 0'} overflow={'auto'}>
|
||||
|
||||
@@ -64,6 +64,12 @@ const InputFormEditModal = ({
|
||||
label: t('common:core.workflow.inputType.select'),
|
||||
value: FlowNodeInputTypeEnum.select,
|
||||
defaultValueType: WorkflowIOValueTypeEnum.string
|
||||
},
|
||||
{
|
||||
icon: 'core/workflow/inputType/option',
|
||||
label: t('workflow:input_type_multiple_select'),
|
||||
value: FlowNodeInputTypeEnum.multipleSelect,
|
||||
defaultValueType: WorkflowIOValueTypeEnum.arrayString
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ const InputTypeConfig = ({
|
||||
FlowNodeInputTypeEnum.numberInput,
|
||||
FlowNodeInputTypeEnum.switch,
|
||||
FlowNodeInputTypeEnum.select,
|
||||
FlowNodeInputTypeEnum.multipleSelect,
|
||||
VariableInputEnum.custom
|
||||
];
|
||||
|
||||
@@ -157,7 +158,8 @@ const InputTypeConfig = ({
|
||||
FlowNodeInputTypeEnum.input,
|
||||
FlowNodeInputTypeEnum.numberInput,
|
||||
FlowNodeInputTypeEnum.switch,
|
||||
FlowNodeInputTypeEnum.select
|
||||
FlowNodeInputTypeEnum.select,
|
||||
FlowNodeInputTypeEnum.multipleSelect
|
||||
];
|
||||
return type === 'plugin' && list.includes(inputType as FlowNodeInputTypeEnum);
|
||||
}, [inputType, type]);
|
||||
@@ -363,6 +365,27 @@ const InputTypeConfig = ({
|
||||
w={'200px'}
|
||||
/>
|
||||
)}
|
||||
{inputType === FlowNodeInputTypeEnum.multipleSelect && (
|
||||
<MultipleSelect<string>
|
||||
flex={'1 0 0'}
|
||||
itemWrap={true}
|
||||
bg={'myGray.50'}
|
||||
list={listValue
|
||||
.filter((item: any) => item.label !== '')
|
||||
.map((item: any) => ({
|
||||
label: item.label,
|
||||
value: item.value
|
||||
}))}
|
||||
placeholder={t('workflow:select_default_option')}
|
||||
value={defaultValue || []}
|
||||
onSelect={(val) => setValue('defaultValue', val)}
|
||||
isSelectAll={
|
||||
defaultValue &&
|
||||
defaultValue.length ===
|
||||
listValue.filter((item: any) => item.label !== '').length
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
@@ -390,7 +413,8 @@ const InputTypeConfig = ({
|
||||
</>
|
||||
)}
|
||||
|
||||
{inputType === FlowNodeInputTypeEnum.select && (
|
||||
{(inputType === FlowNodeInputTypeEnum.select ||
|
||||
inputType == FlowNodeInputTypeEnum.multipleSelect) && (
|
||||
<>
|
||||
<DndDrag<{ id: string; value: string }>
|
||||
onDragEndCb={(list) => {
|
||||
|
||||
@@ -25,6 +25,9 @@ const RenderList: Record<
|
||||
[FlowNodeInputTypeEnum.select]: {
|
||||
Component: dynamic(() => import('./templates/Select'))
|
||||
},
|
||||
[FlowNodeInputTypeEnum.multipleSelect]: {
|
||||
Component: dynamic(() => import('./templates/SelectMulti'))
|
||||
},
|
||||
[FlowNodeInputTypeEnum.numberInput]: {
|
||||
Component: dynamic(() => import('./templates/NumberInput'))
|
||||
},
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import MultipleSelect from '@fastgpt/web/components/common/MySelect/MultipleSelect';
|
||||
import { RenderInputProps } from '../type';
|
||||
import { WorkflowContext } from '@/pageComponents/app/detail/WorkflowComponents/context';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import React from 'react';
|
||||
|
||||
const SelectMultiRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
return (
|
||||
<MultipleSelect<string>
|
||||
width={'100%'}
|
||||
value={item.value}
|
||||
list={item.list || []}
|
||||
onSelect={(e) =>
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
})
|
||||
}
|
||||
isSelectAll={item.value.length === item?.list?.length}
|
||||
setIsSelectAll={(all) => {
|
||||
if (all) {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: item?.list?.map((item) => item.value)
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SelectMultiRender);
|
||||
@@ -184,7 +184,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
stream: true,
|
||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES,
|
||||
workflowStreamResponse: workflowResponseWrite,
|
||||
version: 'v2'
|
||||
version: 'v2',
|
||||
responseDetail: true
|
||||
});
|
||||
|
||||
workflowResponseWrite({
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { GET, POST, PUT } from '@/web/common/api/request';
|
||||
import type { PaginationProps, PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||
import type { OperationListItemType } from '@fastgpt/global/support/operationLog/type';
|
||||
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
|
||||
|
||||
export const getOperationLogs = (props: PaginationProps<PaginationProps>) =>
|
||||
export const getOperationLogs = (
|
||||
props: PaginationProps & {
|
||||
tmbIds?: string[];
|
||||
events?: OperationLogEventEnum[];
|
||||
}
|
||||
) =>
|
||||
POST<PaginationResponse<OperationListItemType>>(
|
||||
`/proApi/support/user/team/operationLog/list`,
|
||||
props
|
||||
|
||||
Reference in New Issue
Block a user