mirror of
https://github.com/onyx-dot-app/onyx.git
synced 2026-02-16 23:35:46 +00:00
Compare commits
53 Commits
experiment
...
feature/op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7203cc76ba | ||
|
|
483a37354b | ||
|
|
3c8c1ab00d | ||
|
|
7fd9a2cc96 | ||
|
|
2ca3c81ea4 | ||
|
|
0d90e285a4 | ||
|
|
d5394bcb88 | ||
|
|
84b45c9366 | ||
|
|
dd8594031b | ||
|
|
91a5e1c843 | ||
|
|
eb0bb8a668 | ||
|
|
59f4910fc6 | ||
|
|
a4edf73897 | ||
|
|
6361aad1b1 | ||
|
|
4812be01bb | ||
|
|
cca178c2fd | ||
|
|
762d03b764 | ||
|
|
fc5c7644ca | ||
|
|
b4dd67ede1 | ||
|
|
67216d8634 | ||
|
|
22d8c05225 | ||
|
|
05af5d08a9 | ||
|
|
881f6abe1e | ||
|
|
fdad15eb22 | ||
|
|
3b55284b76 | ||
|
|
e34ede8e81 | ||
|
|
6ef4f3325a | ||
|
|
f23ecb3683 | ||
|
|
a46a397444 | ||
|
|
b6bb74dc90 | ||
|
|
5c95e8b066 | ||
|
|
11da426af0 | ||
|
|
d9e239f07f | ||
|
|
d04f120556 | ||
|
|
46c49f6f43 | ||
|
|
c12cd29666 | ||
|
|
c08b8ee7a7 | ||
|
|
a82c28b8b5 | ||
|
|
719b587c03 | ||
|
|
7f45c4b10b | ||
|
|
6ddb90661d | ||
|
|
68c54249fd | ||
|
|
7a93cab338 | ||
|
|
be5336fc8f | ||
|
|
4a44989850 | ||
|
|
f5bc749379 | ||
|
|
f37dde0da2 | ||
|
|
2e9151e6ed | ||
|
|
b0b3101dd1 | ||
|
|
a662d0001b | ||
|
|
36fed441cd | ||
|
|
6341149b05 | ||
|
|
1e84e0f0d7 |
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
|
||||
2
.github/workflows/pr-integration-tests.yml
vendored
2
.github/workflows/pr-integration-tests.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
||||
env:
|
||||
PYTHONPATH: "."
|
||||
run: |
|
||||
python scripts/onyx_openapi_schema.py --filename generated/openapi.json
|
||||
python scripts/onyx_openapi_schema.py -f generated/openapi.json
|
||||
|
||||
- name: Generate OpenAPI Python client
|
||||
working-directory: ./backend
|
||||
|
||||
@@ -31,6 +31,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# we still install ee because the schema generator needs it
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
@@ -42,6 +43,7 @@ jobs:
|
||||
- run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/default.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/ee.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/dev.txt
|
||||
|
||||
- name: Generate OpenAPI schema
|
||||
@@ -49,7 +51,7 @@ jobs:
|
||||
env:
|
||||
PYTHONPATH: "."
|
||||
run: |
|
||||
python scripts/onyx_openapi_schema.py --filename generated/openapi.json
|
||||
python scripts/onyx_openapi_schema.py -f generated/openapi.json
|
||||
|
||||
- name: Generate OpenAPI Python client
|
||||
working-directory: ./backend
|
||||
|
||||
10
.github/workflows/pr-playwright-tests.yml
vendored
10
.github/workflows/pr-playwright-tests.yml
vendored
@@ -42,9 +42,17 @@ jobs:
|
||||
- run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/default.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/ee.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/dev.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/model_server.txt
|
||||
|
||||
- name: Generate OpenAPI schema
|
||||
working-directory: ./backend
|
||||
env:
|
||||
PYTHONPATH: "."
|
||||
run: |
|
||||
python scripts/onyx_openapi_schema.py -f generated/openapi.json
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -53,7 +61,7 @@ jobs:
|
||||
- name: Install node dependencies
|
||||
working-directory: ./web
|
||||
run: npm ci
|
||||
|
||||
|
||||
- name: Install playwright browsers
|
||||
working-directory: ./web
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
21
.github/workflows/pr-python-checks.yml
vendored
21
.github/workflows/pr-python-checks.yml
vendored
@@ -28,15 +28,25 @@ jobs:
|
||||
- run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/default.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/ee.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/dev.txt
|
||||
pip install --retries 5 --timeout 30 -r backend/requirements/model_server.txt
|
||||
|
||||
- name: Generate OpenAPI schema
|
||||
- name: OpenAPI - Generate schema
|
||||
working-directory: ./backend
|
||||
env:
|
||||
PYTHONPATH: "."
|
||||
run: |
|
||||
python scripts/onyx_openapi_schema.py --filename generated/openapi.json
|
||||
python scripts/onyx_openapi_schema.py -f generated/openapi.json
|
||||
|
||||
- name: OpenAPI - Compare backend and web schemas
|
||||
run: |
|
||||
ls -l backend/generated/openapi.json
|
||||
ls -l web/openapi/openapi.json
|
||||
diff backend/generated/openapi.json web/openapi/openapi.json || {
|
||||
echo "::error file=web/openapi/openapi.json is out of date. Please regenerate the schema."
|
||||
exit 1
|
||||
}
|
||||
|
||||
- name: Generate OpenAPI Python client
|
||||
working-directory: ./backend
|
||||
@@ -68,3 +78,10 @@ jobs:
|
||||
run: |
|
||||
cd backend
|
||||
black --check .
|
||||
|
||||
- name: Upload OpenAPI schema
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: openapi-schema
|
||||
path: ${{ github.workspace }}/backend/generated/openapi.json
|
||||
|
||||
54
.github/workflows/pr-vercel.yml
vendored
Normal file
54
.github/workflows/pr-vercel.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
# https://vercel.com/guides/how-can-i-use-github-actions-with-vercel
|
||||
name: Deploy Vercel Preview
|
||||
|
||||
on: push
|
||||
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy
|
||||
|
||||
# See https://runs-on.com/runners/linux/
|
||||
runs-on:
|
||||
[
|
||||
runs-on,
|
||||
runner=8cpu-linux-x64,
|
||||
disk=large,
|
||||
"run-id=${{ github.run_id }}",
|
||||
]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install node dependencies
|
||||
working-directory: ./web
|
||||
run: npm ci
|
||||
|
||||
- name: Generate OpenAPI TypeScript Client (orval)
|
||||
working-directory: ./web
|
||||
run: |
|
||||
npx orval --config orval.config.js
|
||||
|
||||
# NOTE: Vercel pulls the working directory (web) from the project dashboard settings
|
||||
- name: Install vercel globally
|
||||
run: |
|
||||
npm install --global vercel
|
||||
|
||||
- name: Pull Vercel Environment Information
|
||||
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
|
||||
|
||||
- name: Build Project Artifacts
|
||||
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
|
||||
|
||||
- name: Deploy Project Artifacts to Vercel
|
||||
run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,3 +26,4 @@ jira_test_env
|
||||
/deployment/data/nginx/app.conf
|
||||
*.sw?
|
||||
/backend/tests/regression/answer_quality/search_test_config.yaml
|
||||
/generated
|
||||
|
||||
77
.vscode/launch.template.jsonc
vendored
77
.vscode/launch.template.jsonc
vendored
@@ -412,46 +412,47 @@
|
||||
"group": "3"
|
||||
}
|
||||
},
|
||||
{
|
||||
// script to generate the openapi schema
|
||||
"name": "Onyx OpenAPI Schema Generator",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "scripts/onyx_openapi_schema.py",
|
||||
"cwd": "${workspaceFolder}/backend",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"PYTHONPATH": "."
|
||||
{
|
||||
// script to generate the openapi schema
|
||||
"name": "Onyx OpenAPI Schema Generator",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "scripts/onyx_openapi_schema.py",
|
||||
"cwd": "${workspaceFolder}/backend",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"PYTHONPATH": "."
|
||||
},
|
||||
"args": [
|
||||
"-f",
|
||||
"generated/openapi.json",
|
||||
"../web/openapi/openapi.json",
|
||||
]
|
||||
},
|
||||
"args": [
|
||||
"--filename",
|
||||
"generated/openapi.json",
|
||||
]
|
||||
},
|
||||
{
|
||||
// script to debug multi tenant db issues
|
||||
"name": "Onyx DB Manager (Top Chunks)",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "scripts/debugging/onyx_db.py",
|
||||
"cwd": "${workspaceFolder}/backend",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"PYTHONPATH": "."
|
||||
{
|
||||
// script to debug multi tenant db issues
|
||||
"name": "Onyx DB Manager (Top Chunks)",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "scripts/debugging/onyx_db.py",
|
||||
"cwd": "${workspaceFolder}/backend",
|
||||
"envFile": "${workspaceFolder}/.env",
|
||||
"env": {
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"PYTHONPATH": "."
|
||||
},
|
||||
"args": [
|
||||
"--password",
|
||||
"your_password_here",
|
||||
"--port",
|
||||
"5433",
|
||||
"--report",
|
||||
"top-chunks",
|
||||
"--filename",
|
||||
"generated/tenants_by_num_docs.csv"
|
||||
]
|
||||
},
|
||||
"args": [
|
||||
"--password",
|
||||
"your_password_here",
|
||||
"--port",
|
||||
"5433",
|
||||
"--report",
|
||||
"top-chunks",
|
||||
"--filename",
|
||||
"generated/tenants_by_num_docs.csv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Debug React Web App in Chrome",
|
||||
"type": "chrome",
|
||||
|
||||
2
.vscode/tasks.template.jsonc
vendored
2
.vscode/tasks.template.jsonc
vendored
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
/*
|
||||
{
|
||||
"type": "austin",
|
||||
"label": "Profile celery beat",
|
||||
@@ -20,6 +21,7 @@
|
||||
"--loglevel=INFO"
|
||||
]
|
||||
},
|
||||
*/
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "Generate Onyx OpenAPI Python client",
|
||||
|
||||
@@ -354,7 +354,7 @@ class FailedConnectorIndexingStatus(BaseModel):
|
||||
class ConnectorStatus(BaseModel):
|
||||
"""
|
||||
Represents the status of a connector,
|
||||
including indexing status elated information
|
||||
including indexing status related information
|
||||
"""
|
||||
|
||||
cc_pair_id: int
|
||||
|
||||
@@ -4,28 +4,35 @@
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
|
||||
from onyx.main import app as app_fn
|
||||
# Force full enterprise edition schema to be generated
|
||||
os.environ["ENABLE_PAID_ENTERPRISE_EDITION_FEATURES"] = "True"
|
||||
|
||||
# NOTE(rkuo): we're conditionally including endpoints based on auth type
|
||||
# looks like a time bomb / bad design
|
||||
os.environ["AUTH_TYPE"] = "basic"
|
||||
|
||||
if True: # noqa: E402
|
||||
from onyx.main import app as app_fn
|
||||
|
||||
|
||||
def go(filename: str) -> None:
|
||||
with open(filename, "w") as f:
|
||||
app: FastAPI = app_fn()
|
||||
json.dump(
|
||||
get_openapi(
|
||||
title=app.title,
|
||||
version=app.version,
|
||||
openapi_version=app.openapi_version,
|
||||
description=app.description,
|
||||
routes=app.routes,
|
||||
),
|
||||
f,
|
||||
)
|
||||
|
||||
print(f"Wrote OpenAPI schema to {filename}.")
|
||||
def go(filenames: list[str]) -> None:
|
||||
app: FastAPI = app_fn()
|
||||
openapi_schema = get_openapi(
|
||||
title=app.title,
|
||||
version=app.version,
|
||||
openapi_version=app.openapi_version,
|
||||
description=app.description,
|
||||
routes=app.routes,
|
||||
)
|
||||
for filename in filenames:
|
||||
with open(filename, "w") as f:
|
||||
json.dump(openapi_schema, f, indent=2)
|
||||
print(f"Wrote OpenAPI schema to {filename}.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -33,11 +40,15 @@ def main() -> None:
|
||||
description="Export OpenAPI schema for Onyx API (does not require starting API server)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--filename", "-f", help="Filename to write to", default="openapi.json"
|
||||
"--filenames",
|
||||
"-f",
|
||||
help="Filenames to write to. Can specify multiple delimited by spaces.",
|
||||
nargs="+",
|
||||
default=["openapi.json"],
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
go(args.filename)
|
||||
go(args.filenames)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
2
generated/README.md
Normal file
2
generated/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
- Generated Files
|
||||
* Generated files live here.
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals",
|
||||
"plugins": ["unused-imports"],
|
||||
"plugins": ["unused-imports", "@typescript-eslint"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"rules": {
|
||||
"@next/next/no-img-element": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
@@ -18,4 +19,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ COPY . .
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
RUN npx orval --config orval.config.js
|
||||
|
||||
# needed to get the `standalone` dir we expect later
|
||||
ENV NEXT_PRIVATE_STANDALONE=true
|
||||
|
||||
2
web/openapi/README.md
Normal file
2
web/openapi/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
This openapi.json schema is generated from the backend directory and must be kept
|
||||
in sync. GitHub build actions enforce this on pull requests.
|
||||
33755
web/openapi/openapi.json
Normal file
33755
web/openapi/openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
21
web/orval.config.js
Normal file
21
web/orval.config.js
Normal file
@@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
onyx: {
|
||||
input: {
|
||||
target: "openapi/openapi.json",
|
||||
},
|
||||
output: {
|
||||
mode: "tags-split",
|
||||
target: "src/lib/generated/onyx-api/api.ts",
|
||||
schemas: "src/lib/generated/onyx-api/model",
|
||||
client: "swr",
|
||||
httpClient: "fetch",
|
||||
baseUrl: "http://localhost:3000",
|
||||
override: {
|
||||
mutator: {
|
||||
path: "./src/lib/orvalFetcher.ts",
|
||||
name: "orvalFetch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
2055
web/package-lock.json
generated
2055
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -100,11 +100,14 @@
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/chrome": "^0.0.287",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
||||
"@typescript-eslint/parser": "^8.33.0",
|
||||
"chromatic": "^11.25.2",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-next": "^14.1.0",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"jest": "^29.7.0",
|
||||
"orval": "^7.9.0",
|
||||
"prettier": "2.8.8",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-unused-exports": "^11.0.1"
|
||||
|
||||
@@ -12,7 +12,6 @@ import { Button } from "@/components/ui/button";
|
||||
import { CCPairStatus, IndexAttemptStatus } from "@/components/Status";
|
||||
import { timeAgo } from "@/lib/time";
|
||||
import {
|
||||
ConnectorIndexingStatus,
|
||||
ConnectorSummary,
|
||||
GroupedConnectorSummaries,
|
||||
ValidSources,
|
||||
@@ -42,6 +41,7 @@ import { TOGGLED_CONNECTORS_COOKIE_NAME } from "@/lib/constants";
|
||||
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
|
||||
import { ConnectorCredentialPairStatus } from "../../connector/[ccPairId]/types";
|
||||
import { FilterComponent, FilterOptions } from "./FilterComponent";
|
||||
import { ConnectorIndexingStatus } from "@/lib/generated/onyx-api/model";
|
||||
|
||||
function SummaryRow({
|
||||
source,
|
||||
@@ -122,7 +122,7 @@ function ConnectorRow({
|
||||
invisible,
|
||||
isEditable,
|
||||
}: {
|
||||
ccPairsIndexingStatus: ConnectorIndexingStatus<any, any>;
|
||||
ccPairsIndexingStatus: ConnectorIndexingStatus;
|
||||
invisible?: boolean;
|
||||
isEditable: boolean;
|
||||
}) {
|
||||
@@ -182,7 +182,9 @@ border border-border dark:border-neutral-700
|
||||
icon={FiRefreshCw}
|
||||
>
|
||||
Inherited from{" "}
|
||||
{getSourceDisplayName(ccPairsIndexingStatus.connector.source)}
|
||||
{getSourceDisplayName(
|
||||
ccPairsIndexingStatus.connector.source as ValidSources
|
||||
)}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant={isEditable ? "private" : "default"} icon={FiLock}>
|
||||
@@ -217,8 +219,8 @@ export function CCPairIndexingStatusTable({
|
||||
ccPairsIndexingStatuses,
|
||||
editableCcPairsIndexingStatuses,
|
||||
}: {
|
||||
ccPairsIndexingStatuses: ConnectorIndexingStatus<any, any>[];
|
||||
editableCcPairsIndexingStatuses: ConnectorIndexingStatus<any, any>[];
|
||||
ccPairsIndexingStatuses: ConnectorIndexingStatus[];
|
||||
editableCcPairsIndexingStatuses: ConnectorIndexingStatus[];
|
||||
}) {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
|
||||
@@ -258,12 +260,12 @@ export function CCPairIndexingStatusTable({
|
||||
groupSummaries,
|
||||
filteredGroupedStatuses,
|
||||
} = useMemo(() => {
|
||||
const grouped: Record<ValidSources, ConnectorIndexingStatus<any, any>[]> =
|
||||
{} as Record<ValidSources, ConnectorIndexingStatus<any, any>[]>;
|
||||
const grouped: Record<ValidSources, ConnectorIndexingStatus[]> =
|
||||
{} as Record<ValidSources, ConnectorIndexingStatus[]>;
|
||||
|
||||
// First, add editable connectors
|
||||
editableCcPairsIndexingStatuses.forEach((status) => {
|
||||
const source = status.connector.source;
|
||||
const source = status.connector.source as ValidSources;
|
||||
if (!grouped[source]) {
|
||||
grouped[source] = [];
|
||||
}
|
||||
@@ -272,7 +274,7 @@ export function CCPairIndexingStatusTable({
|
||||
|
||||
// Then, add non-editable connectors
|
||||
ccPairsIndexingStatuses.forEach((status) => {
|
||||
const source = status.connector.source;
|
||||
const source = status.connector.source as ValidSources;
|
||||
if (!grouped[source]) {
|
||||
grouped[source] = [];
|
||||
}
|
||||
@@ -310,10 +312,8 @@ export function CCPairIndexingStatusTable({
|
||||
});
|
||||
|
||||
// Apply filters to create filtered grouped statuses
|
||||
const filteredGrouped: Record<
|
||||
ValidSources,
|
||||
ConnectorIndexingStatus<any, any>[]
|
||||
> = {} as Record<ValidSources, ConnectorIndexingStatus<any, any>[]>;
|
||||
const filteredGrouped: Record<ValidSources, ConnectorIndexingStatus[]> =
|
||||
{} as Record<ValidSources, ConnectorIndexingStatus[]>;
|
||||
|
||||
sorted.forEach((source) => {
|
||||
const statuses = grouped[source];
|
||||
@@ -495,10 +495,9 @@ export function CCPairIndexingStatusTable({
|
||||
},
|
||||
refresh_freq: 86400,
|
||||
prune_freq: null,
|
||||
indexing_start: new Date("2023-07-01T12:00:00Z"),
|
||||
indexing_start: new Date("2023-07-01T12:00:00Z").toString(),
|
||||
id: 1,
|
||||
credential_ids: [],
|
||||
access_type: "public",
|
||||
time_created: "2023-07-01T12:00:00Z",
|
||||
time_updated: "2023-07-01T12:00:00Z",
|
||||
},
|
||||
@@ -520,6 +519,8 @@ export function CCPairIndexingStatusTable({
|
||||
latest_index_attempt: null,
|
||||
groups: [], // Add this line
|
||||
in_repeated_error_state: false,
|
||||
owner: "",
|
||||
in_progress: false,
|
||||
}}
|
||||
isEditable={false}
|
||||
/>
|
||||
|
||||
@@ -6,22 +6,38 @@ import { CCPairIndexingStatusTable } from "./CCPairIndexingStatusTable";
|
||||
import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import Link from "next/link";
|
||||
import Text from "@/components/ui/text";
|
||||
import { useConnectorCredentialIndexingStatus } from "@/lib/hooks";
|
||||
import { usePopupFromQuery } from "@/components/popup/PopupFromQuery";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
GetConnectorIndexingStatusQueryError,
|
||||
GetConnectorIndexingStatusQueryResult,
|
||||
useGetConnectorIndexingStatus,
|
||||
} from "@/lib/generated/onyx-api/default/default";
|
||||
import { HTTPValidationError } from "@/lib/generated/onyx-api/model";
|
||||
|
||||
function Main() {
|
||||
const {
|
||||
data: indexAttemptData,
|
||||
isLoading: indexAttemptIsLoading,
|
||||
error: indexAttemptError,
|
||||
} = useConnectorCredentialIndexingStatus();
|
||||
} = useGetConnectorIndexingStatus<HTTPValidationError>(undefined, {
|
||||
swr: {
|
||||
refreshInterval: 30000,
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
data: editableIndexAttemptData,
|
||||
isLoading: editableIndexAttemptIsLoading,
|
||||
error: editableIndexAttemptError,
|
||||
} = useConnectorCredentialIndexingStatus(undefined, true);
|
||||
} = useGetConnectorIndexingStatus<HTTPValidationError>(
|
||||
{ get_editable: true }, // or undefined if false
|
||||
{
|
||||
swr: {
|
||||
refreshInterval: undefined,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (indexAttemptIsLoading || editableIndexAttemptIsLoading) {
|
||||
return <LoadingAnimation text="" />;
|
||||
@@ -35,14 +51,46 @@ function Main() {
|
||||
) {
|
||||
return (
|
||||
<div className="text-error">
|
||||
{indexAttemptError?.info?.detail ||
|
||||
editableIndexAttemptError?.info?.detail ||
|
||||
{indexAttemptError?.detail?.[0]?.msg ||
|
||||
editableIndexAttemptError?.detail?.[0]?.msg ||
|
||||
"Error loading indexing history."}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (indexAttemptData.length === 0) {
|
||||
// Handle cases where data from SWR is unexpectedly undefined
|
||||
if (!indexAttemptData || !editableIndexAttemptData) {
|
||||
return (
|
||||
<div className="text-error">
|
||||
Indexing history data is not available. This is an unexpected state.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Handle API errors returned in the response (e.g., status 422)
|
||||
if (indexAttemptData.status !== 200) {
|
||||
const apiError = indexAttemptData.data as HTTPValidationError;
|
||||
const message =
|
||||
apiError.detail?.[0]?.msg ||
|
||||
`API error fetching primary indexing status (Status: ${indexAttemptData.status}).`;
|
||||
return <div className="text-error">{message}</div>;
|
||||
}
|
||||
|
||||
if (editableIndexAttemptData.status !== 200) {
|
||||
const apiError = editableIndexAttemptData.data as HTTPValidationError;
|
||||
const message =
|
||||
apiError.detail?.[0]?.msg ||
|
||||
`API error fetching editable indexing status (Status: ${editableIndexAttemptData.status}).`;
|
||||
return <div className="text-error">{message}</div>;
|
||||
}
|
||||
|
||||
// At this point, both API calls were successful (status 200)
|
||||
// indexAttemptData.data is ConnectorIndexingStatus[]
|
||||
// editableIndexAttemptData.data is ConnectorIndexingStatus[]
|
||||
const actualIndexAttempts = indexAttemptData.data; // No `as ConnectorIndexingStatus[]` needed if TS infers correctly
|
||||
const actualEditableIndexAttempts = editableIndexAttemptData.data;
|
||||
|
||||
if (actualIndexAttempts.length === 0) {
|
||||
return (
|
||||
<Text>
|
||||
It looks like you don't have any connectors setup yet. Visit the{" "}
|
||||
@@ -55,7 +103,7 @@ function Main() {
|
||||
}
|
||||
|
||||
// sort by source name
|
||||
indexAttemptData.sort((a, b) => {
|
||||
actualIndexAttempts.sort((a, b) => {
|
||||
if (a.connector.source < b.connector.source) {
|
||||
return -1;
|
||||
} else if (a.connector.source > b.connector.source) {
|
||||
@@ -67,8 +115,8 @@ function Main() {
|
||||
|
||||
return (
|
||||
<CCPairIndexingStatusTable
|
||||
ccPairsIndexingStatuses={indexAttemptData}
|
||||
editableCcPairsIndexingStatuses={editableIndexAttemptData}
|
||||
ccPairsIndexingStatuses={actualIndexAttempts}
|
||||
editableCcPairsIndexingStatuses={actualEditableIndexAttempts}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,13 +9,14 @@ import {
|
||||
FiMinus,
|
||||
FiPauseCircle,
|
||||
} from "react-icons/fi";
|
||||
import { ConnectorCredentialPairStatus } from "@/app/admin/connector/[ccPairId]/types";
|
||||
// import { ConnectorCredentialPairStatus } from "@/app/admin/connector/[ccPairId]/types";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { ConnectorCredentialPairStatus } from "@/lib/generated/onyx-api/model/connectorCredentialPairStatus";
|
||||
|
||||
export function IndexAttemptStatus({
|
||||
status,
|
||||
|
||||
@@ -78,29 +78,8 @@ export const useObjectState = <T>(
|
||||
return [state, set];
|
||||
};
|
||||
|
||||
const INDEXING_STATUS_URL = "/api/manage/admin/connector/indexing-status";
|
||||
const CONNECTOR_STATUS_URL = "/api/manage/admin/connector/status";
|
||||
|
||||
export const useConnectorCredentialIndexingStatus = (
|
||||
refreshInterval = 30000, // 30 seconds
|
||||
getEditable = false
|
||||
) => {
|
||||
const { mutate } = useSWRConfig();
|
||||
const url = `${INDEXING_STATUS_URL}${
|
||||
getEditable ? "?get_editable=true" : ""
|
||||
}`;
|
||||
const swrResponse = useSWR<ConnectorIndexingStatus<any, any>[]>(
|
||||
url,
|
||||
errorHandlingFetcher,
|
||||
{ refreshInterval: refreshInterval }
|
||||
);
|
||||
|
||||
return {
|
||||
...swrResponse,
|
||||
refreshIndexingStatus: () => mutate(url),
|
||||
};
|
||||
};
|
||||
|
||||
export const useConnectorStatus = (refreshInterval = 30000) => {
|
||||
const { mutate } = useSWRConfig();
|
||||
const url = CONNECTOR_STATUS_URL;
|
||||
|
||||
75
web/src/lib/orvalFetcher.ts
Normal file
75
web/src/lib/orvalFetcher.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
// NOTE: Supports cases where `content-type` is other than `json`
|
||||
const getBody = <T>(c: Response | Request): Promise<T> => {
|
||||
const contentType = c.headers.get("content-type");
|
||||
|
||||
if (contentType && contentType.includes("application/json")) {
|
||||
return c.json();
|
||||
}
|
||||
|
||||
if (contentType && contentType.includes("application/pdf")) {
|
||||
return c.blob() as Promise<T>;
|
||||
}
|
||||
|
||||
return c.text() as Promise<T>;
|
||||
};
|
||||
|
||||
// NOTE(rkuo): we must return a relative URL to get the routes working
|
||||
const getUrl = (contextUrl: string): string => {
|
||||
const url = new URL(contextUrl);
|
||||
const pathname = url.pathname;
|
||||
const search = url.search;
|
||||
const baseUrl = "/api";
|
||||
|
||||
const requestUrl = `${baseUrl}${pathname}${search}`;
|
||||
return requestUrl.toString();
|
||||
};
|
||||
|
||||
// NOTE: Add headers
|
||||
const getHeaders = (headers?: HeadersInit): HeadersInit => {
|
||||
return {
|
||||
...headers,
|
||||
};
|
||||
};
|
||||
|
||||
export const orvalFetch = async <T>(
|
||||
url: string,
|
||||
options: RequestInit
|
||||
): Promise<T> => {
|
||||
const isServer = typeof window === "undefined";
|
||||
const requestUrl = getUrl(url);
|
||||
const requestHeaders = getHeaders(options.headers);
|
||||
|
||||
let requestInit: RequestInit;
|
||||
|
||||
if (isServer) {
|
||||
// Server-side: manually attach cookies
|
||||
const { cookies } = require("next/headers");
|
||||
// const cookieString = cookies().toString();
|
||||
// console.log('Server-side cookies:', cookieString);
|
||||
|
||||
requestInit = {
|
||||
...options,
|
||||
headers: {
|
||||
...requestHeaders,
|
||||
Cookie: cookies().toString(), // Manually attach cookies on server
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Client-side: let browser handle cookies
|
||||
// console.log('Client-side cookies available:', document.cookie ? 'Yes' : 'No');
|
||||
|
||||
requestInit = {
|
||||
...options,
|
||||
headers: requestHeaders,
|
||||
credentials: "include", // Browser will automatically include cookies
|
||||
};
|
||||
}
|
||||
|
||||
// console.log('Request URL:', requestUrl);
|
||||
// console.log('Request headers:', requestInit.headers);
|
||||
|
||||
const response = await fetch(requestUrl, requestInit);
|
||||
const data = await getBody<T>(response);
|
||||
|
||||
return { status: response.status, data, headers: response.headers } as T;
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"target": "es6",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
|
||||
Reference in New Issue
Block a user