-
Notifications
You must be signed in to change notification settings - Fork 1.9k
fix: missing connectors section #5387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
727a105
6a2dc4e
06f0e4e
ab00050
2f9ca82
cbd078a
53ba481
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,10 +2,10 @@ | |||||
"cookies": [ | ||||||
{ | ||||||
"name": "fastapiusersauth", | ||||||
"value": "h3qhacpHbE4_09HcOLlVW4lSee48m1UbjYTUiKYwNiw", | ||||||
"value": "AAdfmA4NT0BXdlg80K3xVuLGVPPPqH7JfzVk82otIw0", | ||||||
|
"value": "AAdfmA4NT0BXdlg80K3xVuLGVPPPqH7JfzVk82otIw0", | |
"value": "<redacted>", |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ import { | |
import { usePopup } from "@/components/admin/connectors/Popup"; | ||
import { SEARCH_PARAM_NAMES } from "../services/searchParams"; | ||
import { useFederatedConnectors, useFilters, useLlmManager } from "@/lib/hooks"; | ||
import { useFederatedOAuthStatus } from "@/lib/hooks/useFederatedOAuthStatus"; | ||
import { FeedbackType } from "@/app/chat/interfaces"; | ||
import { OnyxInitializingLoader } from "@/components/OnyxInitializingLoader"; | ||
import { FeedbackModal } from "./modal/FeedbackModal"; | ||
|
@@ -161,6 +162,10 @@ export function ChatPage({ | |
|
||
// Also fetch federated connectors for the sources list | ||
const { data: federatedConnectorsData } = useFederatedConnectors(); | ||
const { | ||
connectors: federatedConnectorOAuthStatus, | ||
refetch: refetchFederatedConnectors, | ||
} = useFederatedOAuthStatus(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant fetch: useFederatedOAuthStatus is invoked here and again inside FederatedOAuthModal, leading to duplicate network requests. Consider lifting the hook to ChatPage and passing data to the modal, or memoizing/centralizing the fetch. Prompt for AI agents
|
||
|
||
const { user, isAdmin } = useUser(); | ||
const existingChatIdRaw = searchParams?.get("chatId"); | ||
|
@@ -796,6 +801,9 @@ export function ChatPage({ | |
updateCurrentLlm={llmManager.updateCurrentLlm} | ||
defaultModel={user?.preferences.default_model!} | ||
llmProviders={llmProviders} | ||
ccPairs={ccPairs} | ||
federatedConnectors={federatedConnectorOAuthStatus} | ||
refetchFederatedConnectors={refetchFederatedConnectors} | ||
onClose={() => { | ||
setUserSettingsToggled(false); | ||
setSettingsToggled(false); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { test, expect } from "@chromatic-com/playwright"; | ||
import type { Page } from "@playwright/test"; | ||
import { loginAs, loginAsRandomUser } from "../utils/auth"; | ||
|
||
test.use({ storageState: "admin_auth.json" }); | ||
|
||
const SLACK_CLIENT_ID = process.env.SLACK_CLIENT_ID || ""; | ||
|
||
const SLACK_CLIENT_SECRET = process.env.SLACK_CLIENT_SECRET || ""; | ||
|
||
async function createFederatedSlackConnector(page: Page) { | ||
// Navigate to add connector page | ||
await page.goto("http://localhost:3000/admin/add-connector"); | ||
await page.waitForLoadState("networkidle"); | ||
|
||
// Click on Slack connector tile (specifically the one with "Logo Slack" text, not "Slack Bots") | ||
await page.getByRole("link", { name: "Logo Slack" }).first().click(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Selector depends on icon alt text; prefer a text-based matcher that remains stable and avoids coupling to alt values. Prompt for AI agents
|
||
await page.waitForLoadState("networkidle"); | ||
|
||
// Fill in the client ID and client secret | ||
await page.getByLabel(/client id/i).fill(SLACK_CLIENT_ID); | ||
await page.getByLabel(/client secret/i).fill(SLACK_CLIENT_SECRET); | ||
|
||
// Submit the form to create or update the federated connector | ||
const createOrUpdateButton = await page.getByRole("button", { | ||
name: /create|update/i, | ||
}); | ||
await createOrUpdateButton.click(); | ||
|
||
// Wait for success message or redirect | ||
await page.waitForTimeout(2000); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed wait introduces flakiness; wait for a deterministic condition (e.g., success UI, navigation, or network idle) instead. Prompt for AI agents
|
||
} | ||
|
||
async function navigateToUserSettings(page: Page) { | ||
// Wait for any existing modals to close | ||
await page.waitForTimeout(1000); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid fixed delay; wait for a specific element/state signaling the UI is ready. Prompt for AI agents
|
||
|
||
// Wait for potential modal backdrop to disappear | ||
await page | ||
.waitForSelector(".fixed.inset-0.bg-neutral-950\\/50", { | ||
state: "detached", | ||
timeout: 5000, | ||
}) | ||
.catch(() => {}); | ||
|
||
// Click on user dropdown/settings button | ||
await page.locator("#onyx-user-dropdown").click(); | ||
|
||
// Click on settings option | ||
await page.getByText("User Settings").click(); | ||
|
||
// Wait for settings modal to appear | ||
await expect(page.locator("h2", { hasText: "User Settings" })).toBeVisible(); | ||
} | ||
|
||
async function openConnectorsTab(page: Page) { | ||
// Click on the Connectors tab in user settings | ||
await page.getByRole("button", { name: "Connectors" }).click(); | ||
|
||
// Wait for connectors section to be visible | ||
// Allow multiple instances of "Connected Services" to be visible | ||
const connectedServicesLocators = page.getByText("Connected Services"); | ||
await expect(connectedServicesLocators.first()).toBeVisible(); | ||
} | ||
|
||
test("Federated Slack Connector - Create, OAuth Modal, and User Settings Flow", async ({ | ||
page, | ||
}) => { | ||
// Setup: Clear cookies and log in as admin | ||
await page.context().clearCookies(); | ||
await loginAs(page, "admin"); | ||
|
||
// Create a federated Slack connector in admin panel | ||
await createFederatedSlackConnector(page); | ||
|
||
// Log in as a random user | ||
await page.context().clearCookies(); | ||
await loginAsRandomUser(page); | ||
|
||
// Navigate back to main page and verify OAuth modal appears | ||
await page.goto("http://localhost:3000/chat"); | ||
await page.waitForLoadState("networkidle"); | ||
|
||
// Check if the OAuth modal appears | ||
await expect( | ||
page.getByText(/improve answer quality by letting/i) | ||
|
||
).toBeVisible({ timeout: 10000 }); | ||
await expect(page.getByText(/slack/i)).toBeVisible(); | ||
|
||
// Decline the OAuth connection | ||
await page.getByRole("button", { name: "Skip for now" }).click(); | ||
|
||
// Wait for modal to disappear | ||
await expect( | ||
page.getByText(/improve answer quality by letting/i) | ||
).not.toBeVisible(); | ||
|
||
// Go to user settings and verify the connector appears | ||
await navigateToUserSettings(page); | ||
await openConnectorsTab(page); | ||
|
||
// Verify Slack connector appears in the federated connectors section | ||
await expect(page.getByText("Federated Connectors")).toBeVisible(); | ||
await expect(page.getByText("Slack")).toBeVisible(); | ||
await expect(page.getByText("Not connected")).toBeVisible(); | ||
|
||
// Verify there's a Connect button available | ||
await expect(page.locator("button", { hasText: /^Connect$/ })).toBeVisible(); | ||
}); |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secrets are defined at workflow-level env, exposing them to every step and action; scope them to the Playwright test step to minimize exposure.
Prompt for AI agents