mirror of
https://github.com/onyx-dot-app/onyx.git
synced 2026-02-20 01:05:46 +00:00
Compare commits
6 Commits
header-fix
...
header
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e9c3ec0b9 | ||
|
|
1457ca2a20 | ||
|
|
edc390edc6 | ||
|
|
022624cb5a | ||
|
|
f301257130 | ||
|
|
9eecc71cda |
694
.github/workflows/deployment.yml
vendored
694
.github/workflows/deployment.yml
vendored
@@ -79,138 +79,23 @@ jobs:
|
||||
echo "sanitized-tag=$SANITIZED_TAG"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
build-web-amd64:
|
||||
build-web:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-web == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=4cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-web-amd64
|
||||
- run-id=${{ github.run_id }}-web-build
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: onyxdotapp/onyx-web-server
|
||||
DEPLOYMENT: standalone
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push AMD64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./web
|
||||
file: ./web/Dockerfile
|
||||
platforms: linux/amd64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:web-cache-amd64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:web-cache-amd64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
build-web-arm64:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-web == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=4cpu-linux-arm64
|
||||
- run-id=${{ github.run_id }}-web-arm64
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: onyxdotapp/onyx-web-server
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push ARM64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./web
|
||||
file: ./web/Dockerfile
|
||||
platforms: linux/arm64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:web-cache-arm64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:web-cache-arm64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
merge-web:
|
||||
needs:
|
||||
- determine-builds
|
||||
- build-web-amd64
|
||||
- build-web-arm64
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-merge-web
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
REGISTRY_IMAGE: onyxdotapp/onyx-web-server
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
@@ -224,161 +109,51 @@ jobs:
|
||||
type=raw,value=${{ github.event_name != 'workflow_dispatch' && env.EDGE_TAG == 'true' && 'edge' || '' }}
|
||||
type=raw,value=${{ github.event_name != 'workflow_dispatch' && needs.determine-builds.outputs.is-beta == 'true' && 'beta' || '' }}
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
IMAGES="${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-web-amd64.outputs.digest }} ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-web-arm64.outputs.digest }}"
|
||||
docker buildx imagetools create \
|
||||
$(printf '%s\n' "${{ steps.meta.outputs.tags }}" | xargs -I {} echo -t {}) \
|
||||
$IMAGES
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
build-web-cloud-amd64:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./web
|
||||
file: ./web/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:web-${{ env.DEPLOYMENT }}-cache
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:web-${{ env.DEPLOYMENT }}-cache,mode=max
|
||||
|
||||
build-web-cloud:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-web-cloud == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=4cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-web-cloud-amd64
|
||||
- run-id=${{ github.run_id }}-web-cloud-build
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: onyxdotapp/onyx-web-server-cloud
|
||||
DEPLOYMENT: cloud
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push AMD64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./web
|
||||
file: ./web/Dockerfile
|
||||
platforms: linux/amd64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
NEXT_PUBLIC_CLOUD_ENABLED=true
|
||||
NEXT_PUBLIC_POSTHOG_KEY=${{ secrets.POSTHOG_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_HOST=${{ secrets.POSTHOG_HOST }}
|
||||
NEXT_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${{ secrets.STRIPE_PUBLISHABLE_KEY }}
|
||||
NEXT_PUBLIC_GTM_ENABLED=true
|
||||
NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=true
|
||||
NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=true
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:cloudweb-cache-amd64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:cloudweb-cache-amd64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
build-web-cloud-arm64:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-web-cloud == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=4cpu-linux-arm64
|
||||
- run-id=${{ github.run_id }}-web-cloud-arm64
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: onyxdotapp/onyx-web-server-cloud
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push ARM64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./web
|
||||
file: ./web/Dockerfile
|
||||
platforms: linux/arm64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
NEXT_PUBLIC_CLOUD_ENABLED=true
|
||||
NEXT_PUBLIC_POSTHOG_KEY=${{ secrets.POSTHOG_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_HOST=${{ secrets.POSTHOG_HOST }}
|
||||
NEXT_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${{ secrets.STRIPE_PUBLISHABLE_KEY }}
|
||||
NEXT_PUBLIC_GTM_ENABLED=true
|
||||
NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=true
|
||||
NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=true
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:cloudweb-cache-arm64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:cloudweb-cache-arm64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
merge-web-cloud:
|
||||
needs:
|
||||
- determine-builds
|
||||
- build-web-cloud-amd64
|
||||
- build-web-cloud-arm64
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-merge-web-cloud
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
REGISTRY_IMAGE: onyxdotapp/onyx-web-server-cloud
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
@@ -389,143 +164,59 @@ jobs:
|
||||
tags: |
|
||||
type=raw,value=${{ github.event_name == 'workflow_dispatch' && format('web-cloud-{0}', needs.determine-builds.outputs.sanitized-tag) || github.ref_name }}
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
IMAGES="${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-web-cloud-amd64.outputs.digest }} ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-web-cloud-arm64.outputs.digest }}"
|
||||
docker buildx imagetools create \
|
||||
$(printf '%s\n' "${{ steps.meta.outputs.tags }}" | xargs -I {} echo -t {}) \
|
||||
$IMAGES
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
build-backend-amd64:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./web
|
||||
file: ./web/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
NEXT_PUBLIC_CLOUD_ENABLED=true
|
||||
NEXT_PUBLIC_POSTHOG_KEY=${{ secrets.POSTHOG_KEY }}
|
||||
NEXT_PUBLIC_POSTHOG_HOST=${{ secrets.POSTHOG_HOST }}
|
||||
NEXT_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${{ secrets.STRIPE_PUBLISHABLE_KEY }}
|
||||
NEXT_PUBLIC_GTM_ENABLED=true
|
||||
NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=true
|
||||
NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=true
|
||||
NODE_OPTIONS=--max-old-space-size=8192
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:cloudweb-${{ env.DEPLOYMENT }}-cache
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:cloudweb-${{ env.DEPLOYMENT }}-cache,mode=max
|
||||
|
||||
build-backend:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-backend == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-backend-amd64
|
||||
- run-id=${{ github.run_id }}-backend-build
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: ${{ contains(github.ref_name, 'cloud') && 'onyxdotapp/onyx-backend-cloud' || 'onyxdotapp/onyx-backend' }}
|
||||
DEPLOYMENT: ${{ contains(github.ref_name, 'cloud') && 'cloud' || 'standalone' }}
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push AMD64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./backend
|
||||
file: ./backend/Dockerfile
|
||||
platforms: linux/amd64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:backend-cache-amd64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:backend-cache-amd64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
build-backend-arm64:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-backend == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-arm64
|
||||
- run-id=${{ github.run_id }}-backend-arm64
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: ${{ contains(github.ref_name, 'cloud') && 'onyxdotapp/onyx-backend-cloud' || 'onyxdotapp/onyx-backend' }}
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push ARM64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./backend
|
||||
file: ./backend/Dockerfile
|
||||
platforms: linux/arm64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:backend-cache-arm64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:backend-cache-arm64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
merge-backend:
|
||||
needs:
|
||||
- determine-builds
|
||||
- build-backend-amd64
|
||||
- build-backend-arm64
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-merge-backend
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
REGISTRY_IMAGE: ${{ contains(github.ref_name, 'cloud') && 'onyxdotapp/onyx-backend-cloud' || 'onyxdotapp/onyx-backend' }}
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
@@ -539,40 +230,6 @@ jobs:
|
||||
type=raw,value=${{ github.event_name != 'workflow_dispatch' && env.EDGE_TAG == 'true' && 'edge' || '' }}
|
||||
type=raw,value=${{ github.event_name != 'workflow_dispatch' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta' || '' }}
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
IMAGES="${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-backend-amd64.outputs.digest }} ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-backend-arm64.outputs.digest }}"
|
||||
docker buildx imagetools create \
|
||||
$(printf '%s\n' "${{ steps.meta.outputs.tags }}" | xargs -I {} echo -t {}) \
|
||||
$IMAGES
|
||||
|
||||
build-model-server-amd64:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-model-server == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-model-server-amd64
|
||||
- volume=40gb
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: ${{ contains(github.ref_name, 'cloud') && 'onyxdotapp/onyx-model-server-cloud' || 'onyxdotapp/onyx-model-server' }}
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
@@ -582,102 +239,44 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push AMD64
|
||||
id: build
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./backend
|
||||
file: ./backend/Dockerfile.model_server
|
||||
platforms: linux/amd64
|
||||
file: ./backend/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:model-server-cache-amd64
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:backend-${{ env.DEPLOYMENT }}-cache
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:model-server-cache-amd64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:backend-${{ env.DEPLOYMENT }}-cache,mode=max
|
||||
|
||||
build-model-server-arm64:
|
||||
build-model-server:
|
||||
needs: determine-builds
|
||||
if: needs.determine-builds.outputs.build-model-server == 'true'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-arm64
|
||||
- run-id=${{ github.run_id }}-model-server-arm64
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-model-server-build
|
||||
- volume=40gb
|
||||
- extras=ecr-cache
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
env:
|
||||
REGISTRY_IMAGE: ${{ contains(github.ref_name, 'cloud') && 'onyxdotapp/onyx-model-server-cloud' || 'onyxdotapp/onyx-model-server' }}
|
||||
DOCKER_BUILDKIT: 1
|
||||
BUILDKIT_PROGRESS: plain
|
||||
DEPLOYMENT: ${{ contains(github.ref_name, 'cloud') && 'cloud' || 'standalone' }}
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # ratchet:actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push ARM64
|
||||
id: build
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./backend
|
||||
file: ./backend/Dockerfile.model_server
|
||||
platforms: linux/arm64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:model-server-cache-arm64
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:model-server-cache-arm64,mode=max
|
||||
outputs: type=image,name=${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
merge-model-server:
|
||||
needs:
|
||||
- determine-builds
|
||||
- build-model-server-amd64
|
||||
- build-model-server-arm64
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-merge-model-server
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
REGISTRY_IMAGE: ${{ contains(github.ref_name, 'cloud') && 'onyxdotapp/onyx-model-server-cloud' || 'onyxdotapp/onyx-model-server' }}
|
||||
steps:
|
||||
- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e # ratchet:runs-on/action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # ratchet:docker/metadata-action@v5
|
||||
@@ -691,21 +290,43 @@ jobs:
|
||||
type=raw,value=${{ github.event_name != 'workflow_dispatch' && env.EDGE_TAG == 'true' && 'edge' || '' }}
|
||||
type=raw,value=${{ github.event_name != 'workflow_dispatch' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta' || '' }}
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
IMAGES="${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-model-server-amd64.outputs.digest }} ${{ github.event_name == 'workflow_dispatch' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }}@${{ needs.build-model-server-arm64.outputs.digest }}"
|
||||
docker buildx imagetools create \
|
||||
$(printf '%s\n' "${{ steps.meta.outputs.tags }}" | xargs -I {} echo -t {}) \
|
||||
$IMAGES
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # ratchet:docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:latest
|
||||
network=host
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # ratchet:docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # ratchet:docker/build-push-action@v6
|
||||
with:
|
||||
context: ./backend
|
||||
file: ./backend/Dockerfile.model_server
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
ONYX_VERSION=${{ github.ref_name }}
|
||||
cache-from: |
|
||||
type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:model-server-${{ env.DEPLOYMENT }}-cache
|
||||
cache-to: |
|
||||
type=inline
|
||||
type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:model-server-${{ env.DEPLOYMENT }}-cache,mode=max
|
||||
|
||||
trivy-scan-web:
|
||||
needs:
|
||||
- determine-builds
|
||||
- merge-web
|
||||
if: needs.merge-web.result == 'success'
|
||||
needs: [determine-builds, build-web]
|
||||
if: needs.build-web.result == 'success'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-arm64
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-trivy-scan-web
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
@@ -738,13 +359,11 @@ jobs:
|
||||
${SCAN_IMAGE}
|
||||
|
||||
trivy-scan-web-cloud:
|
||||
needs:
|
||||
- determine-builds
|
||||
- merge-web-cloud
|
||||
if: needs.merge-web-cloud.result == 'success'
|
||||
needs: [determine-builds, build-web-cloud]
|
||||
if: needs.build-web-cloud.result == 'success'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-arm64
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-trivy-scan-web-cloud
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
@@ -777,13 +396,11 @@ jobs:
|
||||
${SCAN_IMAGE}
|
||||
|
||||
trivy-scan-backend:
|
||||
needs:
|
||||
- determine-builds
|
||||
- merge-backend
|
||||
if: needs.merge-backend.result == 'success'
|
||||
needs: [determine-builds, build-backend]
|
||||
if: needs.build-backend.result == 'success'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-arm64
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-trivy-scan-backend
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
@@ -821,13 +438,11 @@ jobs:
|
||||
${SCAN_IMAGE}
|
||||
|
||||
trivy-scan-model-server:
|
||||
needs:
|
||||
- determine-builds
|
||||
- merge-model-server
|
||||
if: needs.merge-model-server.result == 'success'
|
||||
needs: [determine-builds, build-model-server]
|
||||
if: needs.build-model-server.result == 'success'
|
||||
runs-on:
|
||||
- runs-on
|
||||
- runner=2cpu-linux-arm64
|
||||
- runner=2cpu-linux-x64
|
||||
- run-id=${{ github.run_id }}-trivy-scan-model-server
|
||||
- extras=ecr-cache
|
||||
env:
|
||||
@@ -860,21 +475,8 @@ jobs:
|
||||
${SCAN_IMAGE}
|
||||
|
||||
notify-slack-on-failure:
|
||||
needs:
|
||||
- build-web-amd64
|
||||
- build-web-arm64
|
||||
- merge-web
|
||||
- build-web-cloud-amd64
|
||||
- build-web-cloud-arm64
|
||||
- merge-web-cloud
|
||||
- build-backend-amd64
|
||||
- build-backend-arm64
|
||||
- merge-backend
|
||||
- build-model-server-amd64
|
||||
- build-model-server-arm64
|
||||
- merge-model-server
|
||||
if: always() && (needs.build-web-amd64.result == 'failure' || needs.build-web-arm64.result == 'failure' || needs.merge-web.result == 'failure' || needs.build-web-cloud-amd64.result == 'failure' || needs.build-web-cloud-arm64.result == 'failure' || needs.merge-web-cloud.result == 'failure' || needs.build-backend-amd64.result == 'failure' || needs.build-backend-arm64.result == 'failure' || needs.merge-backend.result == 'failure' || needs.build-model-server-amd64.result == 'failure' || needs.build-model-server-arm64.result == 'failure' || needs.merge-model-server.result == 'failure') && github.event_name != 'workflow_dispatch'
|
||||
# NOTE: Github-hosted runners have about 20s faster queue times and are preferred here.
|
||||
needs: [build-web, build-web-cloud, build-backend, build-model-server]
|
||||
if: always() && (needs.build-web.result == 'failure' || needs.build-web-cloud.result == 'failure' || needs.build-backend.result == 'failure' || needs.build-model-server.result == 'failure') && github.event_name != 'workflow_dispatch'
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -885,41 +487,17 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
FAILED_JOBS=""
|
||||
if [ "${{ needs.build-web-amd64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-web-amd64\\n"
|
||||
if [ "${{ needs.build-web.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-web\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-web-arm64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-web-arm64\\n"
|
||||
if [ "${{ needs.build-web-cloud.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-web-cloud\\n"
|
||||
fi
|
||||
if [ "${{ needs.merge-web.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• merge-web\\n"
|
||||
if [ "${{ needs.build-backend.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-backend\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-web-cloud-amd64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-web-cloud-amd64\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-web-cloud-arm64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-web-cloud-arm64\\n"
|
||||
fi
|
||||
if [ "${{ needs.merge-web-cloud.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• merge-web-cloud\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-backend-amd64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-backend-amd64\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-backend-arm64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-backend-arm64\\n"
|
||||
fi
|
||||
if [ "${{ needs.merge-backend.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• merge-backend\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-model-server-amd64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-model-server-amd64\\n"
|
||||
fi
|
||||
if [ "${{ needs.build-model-server-arm64.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-model-server-arm64\\n"
|
||||
fi
|
||||
if [ "${{ needs.merge-model-server.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• merge-model-server\\n"
|
||||
if [ "${{ needs.build-model-server.result }}" == "failure" ]; then
|
||||
FAILED_JOBS="${FAILED_JOBS}• build-model-server\\n"
|
||||
fi
|
||||
# Remove trailing \n and set output
|
||||
FAILED_JOBS=$(printf '%s' "$FAILED_JOBS" | sed 's/\\n$//')
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import AgentsPage from "@/refresh-pages/AgentsPage";
|
||||
import { fetchSettingsSS } from "@/components/settings/lib";
|
||||
import AppPage from "@/refresh-components/layouts/AppPage";
|
||||
|
||||
export default function Page() {
|
||||
return <AgentsPage />;
|
||||
export default async function Page() {
|
||||
const settings = await fetchSettingsSS();
|
||||
|
||||
const appPageProps = {
|
||||
chatSession: null,
|
||||
settings,
|
||||
};
|
||||
|
||||
return (
|
||||
<AppPage {...appPageProps}>
|
||||
<AgentsPage />
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,12 @@ import {
|
||||
} from "react";
|
||||
import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { SEARCH_PARAM_NAMES } from "@/app/chat/services/searchParams";
|
||||
import { useFederatedConnectors, useFilters, useLlmManager } from "@/lib/hooks";
|
||||
import {
|
||||
useFederatedConnectors,
|
||||
useFilters,
|
||||
useLlmManager,
|
||||
useShowCenteredInput,
|
||||
} from "@/lib/hooks";
|
||||
import { OnyxInitializingLoader } from "@/components/OnyxInitializingLoader";
|
||||
import { FiArrowDown } from "react-icons/fi";
|
||||
import { OnyxDocument, MinimalOnyxDocument } from "@/lib/search/interfaces";
|
||||
@@ -52,12 +57,8 @@ import {
|
||||
} from "@/app/chat/stores/useChatSessionStore";
|
||||
import {
|
||||
useCurrentChatState,
|
||||
useSubmittedMessage,
|
||||
useLoadingError,
|
||||
useIsReady,
|
||||
useIsFetching,
|
||||
useCurrentMessageTree,
|
||||
useCurrentMessageHistory,
|
||||
useHasPerformedInitialScroll,
|
||||
useDocumentSidebarVisible,
|
||||
useHasSentLocalUserMessage,
|
||||
@@ -405,14 +406,10 @@ export default function ChatPage({
|
||||
// Access chat state directly from the store
|
||||
const currentChatState = useCurrentChatState();
|
||||
const chatSessionId = useChatSessionStore((state) => state.currentSessionId);
|
||||
const submittedMessage = useSubmittedMessage();
|
||||
const loadingError = useLoadingError();
|
||||
const uncaughtError = useUncaughtError();
|
||||
const isReady = useIsReady();
|
||||
const maxTokens = useMaxTokens();
|
||||
const isFetchingChatMessages = useIsFetching();
|
||||
const completeMessageTree = useCurrentMessageTree();
|
||||
const messageHistory = useCurrentMessageHistory();
|
||||
const hasPerformedInitialScroll = useHasPerformedInitialScroll();
|
||||
const currentSessionHasSentLocalUserMessage = useHasSentLocalUserMessage();
|
||||
const documentSidebarVisible = useDocumentSidebarVisible();
|
||||
@@ -422,6 +419,8 @@ export default function ChatPage({
|
||||
const updateCurrentDocumentSidebarVisible = useChatSessionStore(
|
||||
(state) => state.updateCurrentDocumentSidebarVisible
|
||||
);
|
||||
const { messageHistory, loadingError, showCenteredInput } =
|
||||
useShowCenteredInput();
|
||||
|
||||
const clientScrollToBottom = useCallback(
|
||||
(fast?: boolean) => {
|
||||
@@ -622,13 +621,6 @@ export default function ChatPage({
|
||||
setTimeout(() => updateCurrentDocumentSidebarVisible(false), 300);
|
||||
}, [updateCurrentDocumentSidebarVisible]);
|
||||
|
||||
// Determine whether to show the centered input (no messages yet)
|
||||
const showCenteredInput =
|
||||
messageHistory.length === 0 &&
|
||||
!isFetchingChatMessages &&
|
||||
!loadingError &&
|
||||
!submittedMessage;
|
||||
|
||||
// Only show the centered hero layout when there is NO project selected
|
||||
// and there are no messages yet. If a project is selected, prefer a top layout.
|
||||
const showCenteredHero = currentProjectId === null && showCenteredInput;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
"use client";
|
||||
import { fetchSettingsSS } from "@/components/settings/lib";
|
||||
import InputPrompts from "@/app/chat/input-prompts/InputPrompts";
|
||||
import AppPage from "@/refresh-components/layouts/AppPage";
|
||||
|
||||
import InputPrompts from "./InputPrompts";
|
||||
export default async function InputPromptsPage() {
|
||||
const settings = await fetchSettingsSS();
|
||||
|
||||
const appPageProps = {
|
||||
chatSession: null,
|
||||
settings,
|
||||
};
|
||||
|
||||
export default function InputPromptsPage() {
|
||||
return (
|
||||
<div className="w-full py-16">
|
||||
<div className="px-32">
|
||||
<div className="mx-auto container">
|
||||
<InputPrompts />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AppPage {...appPageProps} className="w-full px-32 py-16 mx-auto container">
|
||||
<InputPrompts />
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -162,17 +162,20 @@ export interface BackendChatSession {
|
||||
packets: Packet[][];
|
||||
}
|
||||
|
||||
export function toChatSession(backend: BackendChatSession): ChatSession {
|
||||
export function toChatSession(
|
||||
backendChatSession: BackendChatSession
|
||||
): ChatSession {
|
||||
return {
|
||||
id: backend.chat_session_id,
|
||||
name: backend.description,
|
||||
persona_id: backend.persona_id,
|
||||
time_created: backend.time_created,
|
||||
time_updated: backend.time_updated,
|
||||
shared_status: backend.shared_status,
|
||||
project_id: null,
|
||||
current_alternate_model: backend.current_alternate_model ?? "",
|
||||
current_temperature_override: backend.current_temperature_override,
|
||||
id: backendChatSession.chat_session_id,
|
||||
name: backendChatSession.description,
|
||||
persona_id: backendChatSession.persona_id,
|
||||
time_created: backendChatSession.time_created,
|
||||
time_updated: backendChatSession.time_updated,
|
||||
shared_status: backendChatSession.shared_status,
|
||||
project_id: null, // or whatever source provides
|
||||
current_alternate_model: backendChatSession.current_alternate_model ?? "",
|
||||
current_temperature_override:
|
||||
backendChatSession.current_temperature_override,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import { fetchChatData } from "@/lib/chat/fetchChatData";
|
||||
import { ChatProvider } from "@/refresh-components/contexts/ChatContext";
|
||||
import { ProjectsProvider } from "./projects/ProjectsContext";
|
||||
import AppSidebar from "@/sections/sidebar/AppSidebar";
|
||||
import AppLayout from "@/refresh-components/layouts/AppLayout";
|
||||
import { HeaderActionsProvider } from "@/refresh-components/contexts/HeaderActionsContext";
|
||||
|
||||
export interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
@@ -21,9 +19,7 @@ export default async function Layout({ children }: LayoutProps) {
|
||||
safeSearchParams as { [key: string]: string }
|
||||
);
|
||||
|
||||
if ("redirect" in data) {
|
||||
redirect(data.redirect);
|
||||
}
|
||||
if ("redirect" in data) redirect(data.redirect);
|
||||
|
||||
const {
|
||||
chatSessions,
|
||||
@@ -62,9 +58,7 @@ export default async function Layout({ children }: LayoutProps) {
|
||||
<ProjectsProvider initialProjects={projects}>
|
||||
<div className="flex flex-row w-full h-full">
|
||||
<AppSidebar />
|
||||
<HeaderActionsProvider>
|
||||
<AppLayout>{children}</AppLayout>
|
||||
</HeaderActionsProvider>
|
||||
{children}
|
||||
</div>
|
||||
</ProjectsProvider>
|
||||
</ChatProvider>
|
||||
|
||||
@@ -3,18 +3,25 @@ import { InstantSSRAutoRefresh } from "@/components/SSRAutoRefresh";
|
||||
import { cookies } from "next/headers";
|
||||
import NRFPage from "./NRFPage";
|
||||
import { NRFPreferencesProvider } from "../../../components/context/NRFPreferencesContext";
|
||||
import { fetchSettingsSS } from "@/components/settings/lib";
|
||||
import AppPage from "@/refresh-components/layouts/AppPage";
|
||||
|
||||
export default async function Page() {
|
||||
noStore();
|
||||
const requestCookies = await cookies();
|
||||
const settings = await fetchSettingsSS();
|
||||
|
||||
const appPageProps = {
|
||||
settings,
|
||||
chatSession: null,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full h-full bg-black">
|
||||
<AppPage {...appPageProps}>
|
||||
<InstantSSRAutoRefresh />
|
||||
|
||||
<NRFPreferencesProvider>
|
||||
<NRFPage requestCookies={requestCookies} />
|
||||
</NRFPreferencesProvider>
|
||||
</div>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
import ChatSessionLayout from "@/refresh-components/layouts/ChatSessionLayout";
|
||||
import ChatPage from "./components/ChatPage";
|
||||
import AppPage from "@/refresh-components/layouts/AppPage";
|
||||
import ChatPage from "@/app/chat/components/ChatPage";
|
||||
import { SEARCH_PARAM_NAMES } from "./services/searchParams";
|
||||
import { fetchSS } from "@/lib/utilsSS";
|
||||
import { BackendChatSession, ChatSession, toChatSession } from "./interfaces";
|
||||
import { fetchSettingsSS } from "@/components/settings/lib";
|
||||
import { fetchChatSessionSS } from "@/lib/chat/fetchChatSessionSS";
|
||||
|
||||
export interface PageProps {
|
||||
searchParams: Promise<{ [key: string]: string }>;
|
||||
}
|
||||
|
||||
async function fetchChatSession(
|
||||
chatSessionId: string
|
||||
): Promise<ChatSession | null> {
|
||||
try {
|
||||
const response = await fetchSS(`/chat/get-chat-session/${chatSessionId}`);
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
const backendSession: BackendChatSession = await response.json();
|
||||
return toChatSession(backendSession);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch chat session:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default async function Page(props: PageProps) {
|
||||
const searchParams = await props.searchParams;
|
||||
const firstMessage = searchParams.firstMessage;
|
||||
const chatSessionId = searchParams[SEARCH_PARAM_NAMES.CHAT_ID] ?? null;
|
||||
const settings = await fetchSettingsSS();
|
||||
const chatSession = chatSessionId
|
||||
? await fetchChatSession(chatSessionId)
|
||||
? await fetchChatSessionSS(chatSessionId)
|
||||
: null;
|
||||
|
||||
const appPageProps = {
|
||||
chatSession,
|
||||
settings,
|
||||
};
|
||||
|
||||
return (
|
||||
<ChatSessionLayout chatSession={chatSession}>
|
||||
<AppPage {...appPageProps}>
|
||||
<ChatPage firstMessage={firstMessage} />
|
||||
</ChatSessionLayout>
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { fetchSS } from "@/lib/utilsSS";
|
||||
import { redirect } from "next/navigation";
|
||||
import { requireAuth } from "@/lib/auth/requireAuth";
|
||||
import { SharedChatDisplay } from "@/app/chat/shared/[chatId]/SharedChatDisplay";
|
||||
import { SharedChatDisplay } from "./SharedChatDisplay";
|
||||
import { Persona } from "@/app/admin/assistants/interfaces";
|
||||
import { constructMiniFiedPersona } from "@/lib/assistantIconUtils";
|
||||
|
||||
async function getSharedChat(chatId: string) {
|
||||
const response = await fetchSS(
|
||||
`/chat/get-chat-session/${chatId}?is_shared=True`
|
||||
);
|
||||
if (response.ok) {
|
||||
return await response.json();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
import AppPage from "@/refresh-components/layouts/AppPage";
|
||||
import { fetchSettingsSS } from "@/components/settings/lib";
|
||||
import { fetchBackendChatSessionSS } from "@/lib/chat/fetchChatSessionSS";
|
||||
import { toChatSession } from "@/app/chat/interfaces";
|
||||
|
||||
export interface PageProps {
|
||||
params: Promise<{ chatId: string }>;
|
||||
@@ -29,14 +22,29 @@ export default async function Page(props: PageProps) {
|
||||
|
||||
// Catch cases where backend is completely unreachable
|
||||
// Allows render instead of throwing an exception and crashing
|
||||
const chatSession = await getSharedChat(params.chatId).catch(() => null);
|
||||
|
||||
const backendChatSession = await fetchBackendChatSessionSS(
|
||||
params.chatId,
|
||||
true
|
||||
).catch(() => null);
|
||||
const settings = await fetchSettingsSS();
|
||||
const persona: Persona = constructMiniFiedPersona(
|
||||
chatSession?.persona_icon_color ?? null,
|
||||
chatSession?.persona_icon_shape ?? null,
|
||||
chatSession?.persona_name ?? "",
|
||||
chatSession?.persona_id ?? 0
|
||||
backendChatSession?.persona_icon_color ?? null,
|
||||
backendChatSession?.persona_icon_shape ?? null,
|
||||
backendChatSession?.persona_name ?? "",
|
||||
backendChatSession?.persona_id ?? 0
|
||||
);
|
||||
const chatSession = backendChatSession
|
||||
? toChatSession(backendChatSession)
|
||||
: null;
|
||||
|
||||
return <SharedChatDisplay chatSession={chatSession} persona={persona} />;
|
||||
const appPageProps = {
|
||||
settings,
|
||||
chatSession,
|
||||
};
|
||||
|
||||
return (
|
||||
<AppPage {...appPageProps}>
|
||||
<SharedChatDisplay chatSession={backendChatSession} persona={persona} />
|
||||
</AppPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@ import {
|
||||
ValidSources,
|
||||
} from "@/lib/types";
|
||||
import { ChatSession, InputPrompt } from "@/app/chat/interfaces";
|
||||
import { Persona } from "@/app/admin/assistants/interfaces";
|
||||
import { FullEmbeddingModelResponse } from "@/components/embedding/interfaces";
|
||||
import { Settings } from "@/app/admin/settings/interfaces";
|
||||
import { fetchLLMProvidersSS } from "@/lib/llm/fetchLLMs";
|
||||
import { LLMProviderDescriptor } from "@/app/admin/configuration/llm/interfaces";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
30
web/src/lib/chat/fetchChatSessionSS.ts
Normal file
30
web/src/lib/chat/fetchChatSessionSS.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import {
|
||||
BackendChatSession,
|
||||
ChatSession,
|
||||
toChatSession,
|
||||
} from "@/app/chat/interfaces";
|
||||
import { fetchSS } from "@/lib/utilsSS";
|
||||
|
||||
export async function fetchBackendChatSessionSS(
|
||||
chatSessionId: string,
|
||||
shared?: boolean
|
||||
): Promise<BackendChatSession | null> {
|
||||
const url = `/chat/get-chat-session/${chatSessionId}?${
|
||||
shared ? "is_shared=True" : ""
|
||||
}`;
|
||||
const response = await fetchSS(url);
|
||||
if (!response.ok) return null;
|
||||
return (await response.json()) as BackendChatSession;
|
||||
}
|
||||
|
||||
export async function fetchChatSessionSS(
|
||||
chatSessionId: string,
|
||||
shared?: boolean
|
||||
): Promise<ChatSession | null> {
|
||||
const backendChatSession = await fetchBackendChatSessionSS(
|
||||
chatSessionId,
|
||||
shared
|
||||
);
|
||||
if (!backendChatSession) return null;
|
||||
return toChatSession(backendChatSession);
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
import { DateRangePickerValue } from "@/components/dateRangeSelectors/AdminDateRangeSelector";
|
||||
import { SourceMetadata } from "./search/interfaces";
|
||||
import { parseLlmDescriptor } from "./llm/utils";
|
||||
import { ChatSession } from "@/app/chat/interfaces";
|
||||
import { ChatSession, Message } from "@/app/chat/interfaces";
|
||||
import { AllUsersResponse } from "./types";
|
||||
import { Credential } from "./connectors/credentials";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
||||
@@ -43,6 +43,12 @@ import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { SEARCH_PARAM_NAMES } from "@/app/chat/services/searchParams";
|
||||
import { useLLMProviders } from "./hooks/useLLMProviders";
|
||||
import { useChatContext } from "@/refresh-components/contexts/ChatContext";
|
||||
import {
|
||||
useCurrentMessageHistory,
|
||||
useIsFetching,
|
||||
useLoadingError,
|
||||
useSubmittedMessage,
|
||||
} from "@/app/chat/stores/useChatSessionStore";
|
||||
|
||||
export function useIsMounted() {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
@@ -1276,3 +1282,33 @@ export function useSourcePreferences({
|
||||
isSourceEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
export interface ShowCenteredInput {
|
||||
isFetchingChatMessages: boolean;
|
||||
loadingError: string | null;
|
||||
messageHistory: Message[];
|
||||
submittedMessage: string;
|
||||
showCenteredInput: boolean;
|
||||
}
|
||||
|
||||
// Determine whether to show the centered input (no messages yet)
|
||||
export function useShowCenteredInput(): ShowCenteredInput {
|
||||
const isFetchingChatMessages = useIsFetching();
|
||||
const loadingError = useLoadingError();
|
||||
const messageHistory = useCurrentMessageHistory();
|
||||
const submittedMessage = useSubmittedMessage();
|
||||
|
||||
const showCenteredInput =
|
||||
messageHistory.length === 0 &&
|
||||
!isFetchingChatMessages &&
|
||||
!loadingError &&
|
||||
!submittedMessage;
|
||||
|
||||
return {
|
||||
isFetchingChatMessages,
|
||||
loadingError,
|
||||
messageHistory,
|
||||
submittedMessage,
|
||||
showCenteredInput,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,17 +8,12 @@ import {
|
||||
} from "@/components/ui/popover";
|
||||
|
||||
export interface SimplePopoverProps
|
||||
extends Omit<
|
||||
React.ComponentPropsWithoutRef<typeof PopoverContent>,
|
||||
"children"
|
||||
> {
|
||||
extends React.ComponentPropsWithoutRef<typeof PopoverContent> {
|
||||
trigger: React.ReactNode | ((open: boolean) => React.ReactNode);
|
||||
children: React.ReactNode | ((close: () => void) => React.ReactNode);
|
||||
}
|
||||
|
||||
export default function SimplePopover({
|
||||
trigger,
|
||||
children,
|
||||
...rest
|
||||
}: SimplePopoverProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -28,11 +23,7 @@ export default function SimplePopover({
|
||||
<PopoverTrigger asChild>
|
||||
<div>{typeof trigger === "function" ? trigger(open) : trigger}</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start" side="top" {...rest}>
|
||||
{typeof children === "function"
|
||||
? children(() => setOpen(false))
|
||||
: children}
|
||||
</PopoverContent>
|
||||
<PopoverContent align="start" side="top" {...rest} />
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
} from "@/lib/types";
|
||||
import { useAssistantPreferences } from "@/app/chat/hooks/useAssistantPreferences";
|
||||
import { useSession } from "@/app/chat/stores/useChatSessionStore";
|
||||
import { BackendChatSession } from "@/app/chat/interfaces";
|
||||
|
||||
async function fetchAllAgents(): Promise<MinimalPersonaSnapshot[]> {
|
||||
try {
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import React, {
|
||||
ReactNode,
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
interface HeaderActionsState {
|
||||
node: ReactNode | null;
|
||||
reserveSpace: boolean;
|
||||
}
|
||||
|
||||
interface HeaderActionsContextValue extends HeaderActionsState {
|
||||
setHeaderActions: (node: ReactNode | null) => void;
|
||||
reserveHeaderSpace: () => void;
|
||||
clearHeaderActions: () => void;
|
||||
}
|
||||
|
||||
const HeaderActionsContext = createContext<HeaderActionsContextValue | null>(
|
||||
null
|
||||
);
|
||||
|
||||
export function HeaderActionsProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [state, setState] = useState<HeaderActionsState>({
|
||||
node: null,
|
||||
reserveSpace: false,
|
||||
});
|
||||
|
||||
const setHeaderActions = useCallback<
|
||||
HeaderActionsContextValue["setHeaderActions"]
|
||||
>((node) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
node,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const reserveHeaderSpace = useCallback(() => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
reserveSpace: true,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const clearHeaderActions = useCallback(() => {
|
||||
setState({
|
||||
node: null,
|
||||
reserveSpace: false,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const value = useMemo<HeaderActionsContextValue>(
|
||||
() => ({
|
||||
...state,
|
||||
setHeaderActions,
|
||||
reserveHeaderSpace,
|
||||
clearHeaderActions,
|
||||
}),
|
||||
[state, setHeaderActions, reserveHeaderSpace, clearHeaderActions]
|
||||
);
|
||||
|
||||
return (
|
||||
<HeaderActionsContext.Provider value={value}>
|
||||
{children}
|
||||
</HeaderActionsContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useHeaderActions() {
|
||||
const context = useContext(HeaderActionsContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useHeaderActions must be used within a HeaderActionsProvider"
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
setHeaderActions: context.setHeaderActions,
|
||||
reserveHeaderSpace: context.reserveHeaderSpace,
|
||||
clearHeaderActions: context.clearHeaderActions,
|
||||
};
|
||||
}
|
||||
|
||||
export function useHeaderActionsValue() {
|
||||
const context = useContext(HeaderActionsContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useHeaderActionsValue must be used within a HeaderActionsProvider"
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
headerNode: context.node,
|
||||
reserveSpace: context.reserveSpace,
|
||||
};
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useSettingsContext } from "@/components/settings/SettingsProvider";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Text from "@/refresh-components/texts/Text";
|
||||
import { FOLDED_SIZE } from "@/refresh-components/Logo";
|
||||
import { useHeaderActionsValue } from "@/refresh-components/contexts/HeaderActionsContext";
|
||||
|
||||
export default function AppLayout({
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}: React.HtmlHTMLAttributes<HTMLDivElement>) {
|
||||
const settings = useSettingsContext();
|
||||
const customHeaderContent =
|
||||
settings.enterpriseSettings?.custom_header_content;
|
||||
const customFooterContent =
|
||||
settings.enterpriseSettings?.custom_lower_disclaimer_content;
|
||||
const customLogo = settings.enterpriseSettings?.use_custom_logo;
|
||||
|
||||
const { headerNode, reserveSpace } = useHeaderActionsValue();
|
||||
const shouldRenderHeader =
|
||||
!!customHeaderContent || reserveSpace || !!headerNode;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full w-full">
|
||||
{/* Header */}
|
||||
{shouldRenderHeader && (
|
||||
<header className="w-full flex flex-row justify-center items-center py-3 px-4 h-16">
|
||||
<div className="flex-1" />
|
||||
<div className="flex-1 flex flex-col items-center justify-center">
|
||||
{customHeaderContent && <Text text03>{customHeaderContent}</Text>}
|
||||
</div>
|
||||
<div className="flex-1 flex flex-row items-center justify-end px-1">
|
||||
{headerNode}
|
||||
</div>
|
||||
</header>
|
||||
)}
|
||||
|
||||
<div className={cn("flex-1 overflow-auto", className)} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
{(customLogo || customFooterContent) && (
|
||||
<footer className="w-full flex flex-row justify-center items-center gap-2 py-3">
|
||||
{customLogo && (
|
||||
<img
|
||||
src="/api/enterprise-settings/logo"
|
||||
alt="Logo"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
height: FOLDED_SIZE,
|
||||
width: FOLDED_SIZE,
|
||||
}}
|
||||
className="flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
{customFooterContent && (
|
||||
<Text text03 secondaryBody>
|
||||
{customFooterContent}
|
||||
</Text>
|
||||
)}
|
||||
</footer>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
96
web/src/refresh-components/layouts/AppPage.tsx
Normal file
96
web/src/refresh-components/layouts/AppPage.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import Text from "@/refresh-components/texts/Text";
|
||||
import { FOLDED_SIZE } from "@/refresh-components/Logo";
|
||||
import Button from "@/refresh-components/buttons/Button";
|
||||
import SvgShare from "@/icons/share";
|
||||
import { useState } from "react";
|
||||
import ShareChatSessionModal from "@/app/chat/components/modal/ShareChatSessionModal";
|
||||
import { CombinedSettings } from "@/app/admin/settings/interfaces";
|
||||
import { ChatSession } from "@/app/chat/interfaces";
|
||||
import { useShowCenteredInput } from "@/lib/hooks";
|
||||
|
||||
export interface AppPageProps extends React.HtmlHTMLAttributes<HTMLDivElement> {
|
||||
settings: CombinedSettings | null;
|
||||
chatSession: ChatSession | null;
|
||||
}
|
||||
|
||||
export default function AppPage({
|
||||
settings,
|
||||
chatSession,
|
||||
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}: AppPageProps) {
|
||||
const customHeaderContent =
|
||||
settings?.enterpriseSettings?.custom_header_content;
|
||||
const customFooterContent =
|
||||
settings?.enterpriseSettings?.custom_lower_disclaimer_content;
|
||||
const customLogo = settings?.enterpriseSettings?.use_custom_logo;
|
||||
const [showShareModal, setShowShareModal] = useState(false);
|
||||
const { showCenteredInput } = useShowCenteredInput();
|
||||
|
||||
return (
|
||||
<>
|
||||
{chatSession && showShareModal && (
|
||||
<ShareChatSessionModal
|
||||
chatSession={chatSession}
|
||||
onClose={() => setShowShareModal(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col h-full w-full">
|
||||
{/* Header */}
|
||||
{(customHeaderContent || !showCenteredInput) && (
|
||||
<header className="w-full flex flex-row justify-center items-center py-3 px-4">
|
||||
<div className="flex-1" />
|
||||
<div className="flex-1 flex flex-col items-center">
|
||||
<Text text03 className={cn(!customHeaderContent && "invisible")}>
|
||||
{customHeaderContent}
|
||||
</Text>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-row items-center justify-end px-1">
|
||||
<Button
|
||||
rightIcon={SvgShare}
|
||||
transient={showShareModal}
|
||||
tertiary
|
||||
onClick={() => setShowShareModal(true)}
|
||||
className={cn(showCenteredInput && !chatSession && "invisible")}
|
||||
>
|
||||
Share Chat
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
)}
|
||||
|
||||
<div className={cn("flex-1 overflow-auto", className)} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
{(customLogo || customFooterContent) && (
|
||||
<footer className="w-full flex flex-row justify-center items-center gap-2 py-3">
|
||||
{customLogo && (
|
||||
<img
|
||||
src="/api/enterprise-settings/logo"
|
||||
alt="Logo"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
height: FOLDED_SIZE,
|
||||
width: FOLDED_SIZE,
|
||||
}}
|
||||
className="flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
{customFooterContent && (
|
||||
<Text text03 secondaryBody>
|
||||
{customFooterContent}
|
||||
</Text>
|
||||
)}
|
||||
</footer>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ChatSession } from "@/app/chat/interfaces";
|
||||
import {
|
||||
useHeaderActions,
|
||||
useHeaderActionsValue,
|
||||
} from "@/refresh-components/contexts/HeaderActionsContext";
|
||||
import Button from "@/refresh-components/buttons/Button";
|
||||
import SvgShare from "@/icons/share";
|
||||
import ShareChatSessionModal from "@/app/chat/components/modal/ShareChatSessionModal";
|
||||
import SimplePopover from "@/refresh-components/SimplePopover";
|
||||
import IconButton from "@/refresh-components/buttons/IconButton";
|
||||
import SvgMoreHorizontal from "@/icons/more-horizontal";
|
||||
import MenuButton from "@/refresh-components/buttons/MenuButton";
|
||||
import SvgFolderIn from "@/icons/folder-in";
|
||||
import SvgTrash from "@/icons/trash";
|
||||
import { useProjectsContext } from "@/app/chat/projects/ProjectsContext";
|
||||
import { useChatContext } from "@/refresh-components/contexts/ChatContext";
|
||||
import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { deleteChatSession } from "@/app/chat/services/lib";
|
||||
import {
|
||||
handleMoveOperation,
|
||||
shouldShowMoveModal,
|
||||
showErrorNotification,
|
||||
} from "@/sections/sidebar/sidebarUtils";
|
||||
import { LOCAL_STORAGE_KEYS } from "@/sections/sidebar/constants";
|
||||
import MoveCustomAgentChatModal from "@/components/modals/MoveCustomAgentChatModal";
|
||||
import ConfirmationModalLayout from "@/refresh-components/layouts/ConfirmationModalLayout";
|
||||
import { Modal } from "@/components/Modal";
|
||||
import Text from "@/refresh-components/texts/Text";
|
||||
|
||||
interface ChatSessionLayoutProps {
|
||||
chatSession: ChatSession | null;
|
||||
children: React.ReactNode;
|
||||
reserveHeaderSpace?: boolean;
|
||||
}
|
||||
|
||||
export default function ChatSessionLayout({
|
||||
chatSession,
|
||||
children,
|
||||
reserveHeaderSpace = true,
|
||||
}: ChatSessionLayoutProps) {
|
||||
const {
|
||||
setHeaderActions,
|
||||
reserveHeaderSpace: reserveSlot,
|
||||
clearHeaderActions,
|
||||
} = useHeaderActions();
|
||||
const { reserveSpace } = useHeaderActionsValue();
|
||||
const [showShareModal, setShowShareModal] = useState(false);
|
||||
const [moveModalOpen, setMoveModalOpen] = useState(false);
|
||||
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
||||
const [pendingMoveProjectId, setPendingMoveProjectId] = useState<
|
||||
number | null
|
||||
>(null);
|
||||
const [showMoveCustomAgentModal, setShowMoveCustomAgentModal] =
|
||||
useState(false);
|
||||
|
||||
const {
|
||||
projects,
|
||||
fetchProjects,
|
||||
refreshCurrentProjectDetails,
|
||||
currentProjectId,
|
||||
} = useProjectsContext();
|
||||
const { refreshChatSessions } = useChatContext();
|
||||
const { popup, setPopup } = usePopup();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!reserveHeaderSpace) {
|
||||
return;
|
||||
}
|
||||
reserveSlot();
|
||||
return () => {
|
||||
clearHeaderActions();
|
||||
};
|
||||
}, [reserveHeaderSpace, reserveSlot, clearHeaderActions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chatSession) {
|
||||
setHeaderActions(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const actions = (
|
||||
<div className="flex flex-row items-center">
|
||||
<Button
|
||||
leftIcon={SvgShare}
|
||||
transient={showShareModal}
|
||||
tertiary
|
||||
onClick={() => setShowShareModal(true)}
|
||||
>
|
||||
Share Chat
|
||||
</Button>
|
||||
<SimplePopover
|
||||
trigger={(open) => (
|
||||
<IconButton icon={SvgMoreHorizontal} tertiary transient={open} />
|
||||
)}
|
||||
>
|
||||
{(close) => (
|
||||
<div className="flex flex-col gap-1 min-w-[12rem]">
|
||||
<MenuButton
|
||||
icon={SvgFolderIn}
|
||||
onClick={() => {
|
||||
close();
|
||||
setMoveModalOpen(true);
|
||||
}}
|
||||
>
|
||||
Move to Project
|
||||
</MenuButton>
|
||||
<MenuButton
|
||||
icon={SvgTrash}
|
||||
danger
|
||||
onClick={() => {
|
||||
close();
|
||||
setDeleteModalOpen(true);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</MenuButton>
|
||||
</div>
|
||||
)}
|
||||
</SimplePopover>
|
||||
</div>
|
||||
);
|
||||
|
||||
setHeaderActions(actions);
|
||||
return () => {
|
||||
setHeaderActions(null);
|
||||
};
|
||||
}, [chatSession, showShareModal, setHeaderActions, reserveSpace]);
|
||||
|
||||
const performMove = useCallback(
|
||||
async (targetProjectId: number) => {
|
||||
if (!chatSession) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await handleMoveOperation(
|
||||
{
|
||||
chatSession,
|
||||
targetProjectId,
|
||||
refreshChatSessions,
|
||||
refreshCurrentProjectDetails,
|
||||
fetchProjects,
|
||||
currentProjectId,
|
||||
},
|
||||
setPopup
|
||||
);
|
||||
setMoveModalOpen(false);
|
||||
} catch (error) {
|
||||
console.error("Failed to move chat session:", error);
|
||||
} finally {
|
||||
setPendingMoveProjectId(null);
|
||||
setShowMoveCustomAgentModal(false);
|
||||
}
|
||||
},
|
||||
[
|
||||
chatSession,
|
||||
refreshChatSessions,
|
||||
refreshCurrentProjectDetails,
|
||||
fetchProjects,
|
||||
currentProjectId,
|
||||
setPopup,
|
||||
]
|
||||
);
|
||||
|
||||
const handleMoveSelection = useCallback(
|
||||
(projectId: number) => {
|
||||
if (!chatSession) return;
|
||||
if (shouldShowMoveModal(chatSession)) {
|
||||
setPendingMoveProjectId(projectId);
|
||||
setShowMoveCustomAgentModal(true);
|
||||
return;
|
||||
}
|
||||
void performMove(projectId);
|
||||
},
|
||||
[chatSession, performMove]
|
||||
);
|
||||
|
||||
const handleDeleteChat = useCallback(async () => {
|
||||
if (!chatSession) return;
|
||||
try {
|
||||
const response = await deleteChatSession(chatSession.id);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to delete chat session");
|
||||
}
|
||||
await Promise.all([refreshChatSessions(), fetchProjects()]);
|
||||
router.replace("/chat");
|
||||
setDeleteModalOpen(false);
|
||||
} catch (error) {
|
||||
console.error("Failed to delete chat:", error);
|
||||
showErrorNotification(
|
||||
setPopup,
|
||||
"Failed to delete chat. Please try again."
|
||||
);
|
||||
}
|
||||
}, [chatSession, refreshChatSessions, fetchProjects, router, setPopup]);
|
||||
|
||||
const handleMoveModalClose = useCallback(() => {
|
||||
setMoveModalOpen(false);
|
||||
setPendingMoveProjectId(null);
|
||||
setShowMoveCustomAgentModal(false);
|
||||
}, []);
|
||||
|
||||
const projectsWithoutCurrent = useMemo(() => {
|
||||
if (!projects) return [];
|
||||
return projects.filter((project) => project.id !== currentProjectId);
|
||||
}, [projects, currentProjectId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{popup}
|
||||
{chatSession && showShareModal && (
|
||||
<ShareChatSessionModal
|
||||
chatSession={chatSession}
|
||||
onClose={() => setShowShareModal(false)}
|
||||
/>
|
||||
)}
|
||||
{moveModalOpen && (
|
||||
<Modal
|
||||
title="Move Chat to Project"
|
||||
onOutsideClick={handleMoveModalClose}
|
||||
width="max-w-md"
|
||||
hideDividerForTitle
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Text text03>
|
||||
Choose a project to move <b>{chatSession?.name || "this chat"}</b>{" "}
|
||||
into.
|
||||
</Text>
|
||||
<div className="flex flex-col gap-1">
|
||||
{projectsWithoutCurrent.length === 0 && (
|
||||
<Text text03>No available projects.</Text>
|
||||
)}
|
||||
{projectsWithoutCurrent.map((project) => (
|
||||
<MenuButton
|
||||
key={project.id}
|
||||
icon={SvgFolderIn}
|
||||
onClick={() => handleMoveSelection(project.id)}
|
||||
>
|
||||
{project.name}
|
||||
</MenuButton>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<Button tertiary onClick={handleMoveModalClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
{showMoveCustomAgentModal && (
|
||||
<MoveCustomAgentChatModal
|
||||
onCancel={handleMoveModalClose}
|
||||
onConfirm={async (doNotShowAgain: boolean) => {
|
||||
if (doNotShowAgain && typeof window !== "undefined") {
|
||||
window.localStorage.setItem(
|
||||
LOCAL_STORAGE_KEYS.HIDE_MOVE_CUSTOM_AGENT_MODAL,
|
||||
"true"
|
||||
);
|
||||
}
|
||||
if (pendingMoveProjectId != null) {
|
||||
await performMove(pendingMoveProjectId);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{deleteModalOpen && (
|
||||
<ConfirmationModalLayout
|
||||
title="Delete Chat"
|
||||
icon={SvgTrash}
|
||||
onClose={() => setDeleteModalOpen(false)}
|
||||
submit={
|
||||
<Button danger onClick={handleDeleteChat}>
|
||||
Delete
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
Are you sure you want to delete this chat? This action cannot be
|
||||
undone.
|
||||
</ConfirmationModalLayout>
|
||||
)}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import Button from "@/refresh-components/buttons/Button";
|
||||
import DefaultModalLayout, {
|
||||
ModalProps,
|
||||
} from "@/refresh-components/layouts/DefaultModalLayout";
|
||||
import SimpleLoader from "@/refresh-components/loaders/SimpleLoader";
|
||||
import { useModal } from "@/refresh-components/contexts/ModalContext";
|
||||
|
||||
interface ProviderModalProps extends ModalProps {
|
||||
// Footer props
|
||||
onSubmit?: () => void;
|
||||
submitDisabled?: boolean;
|
||||
isSubmitting?: boolean;
|
||||
submitLabel?: string;
|
||||
cancelLabel?: string;
|
||||
}
|
||||
|
||||
export default function ProviderModalLayout({
|
||||
onSubmit,
|
||||
submitDisabled = false,
|
||||
isSubmitting = false,
|
||||
submitLabel = "Connect",
|
||||
cancelLabel = "Cancel",
|
||||
|
||||
children,
|
||||
...rest
|
||||
}: ProviderModalProps) {
|
||||
const modal = useModal();
|
||||
|
||||
return (
|
||||
<DefaultModalLayout {...rest}>
|
||||
<div className="flex flex-col h-full max-h-[calc(100dvh-9rem)]">
|
||||
<div className="flex-1 overflow-scroll">{children}</div>
|
||||
{onSubmit && (
|
||||
<div className="sticky bottom-0">
|
||||
<div className="flex justify-end gap-2 w-full p-4">
|
||||
<Button
|
||||
type="button"
|
||||
secondary
|
||||
onClick={() => modal.toggle(false)}
|
||||
>
|
||||
{cancelLabel}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={onSubmit}
|
||||
disabled={submitDisabled || isSubmitting}
|
||||
leftIcon={isSubmitting ? SimpleLoader : undefined}
|
||||
>
|
||||
{submitLabel}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DefaultModalLayout>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user