Skip to content

Commit c6044b3

Browse files
author
Matthew Valancy
committed
fix: replace all hardcoded GraphQL endpoints with nginx proxy path
Fixed database admin page showing "Error" on all statistics by updating all direct GraphQL endpoint calls to use nginx proxy path (/api/graphql). Changes: - apollo.ts: Updated getGraphQLUrl() and getWebSocketUrl() to use /api/graphql - Admin.tsx: Fixed 9 fetch('/graphql') calls to use /api/graphql - Backend.tsx: Fixed 7 fetch('/graphql') calls to use /api/graphql - Signup.tsx: Fixed 1 fetch('/graphql') call to use /api/graphql Testing: - Added comprehensive admin-database-tab.spec.ts with 8 test cases - Added test to PR validation suite at priority 9 - Test verifies correct API endpoint usage and stats display - Added root-level playwright.config.ts for proper HTTPS testing Total: 17 hardcoded endpoint instances fixed across 3 files
1 parent 7ac1e38 commit c6044b3

7 files changed

Lines changed: 278 additions & 32 deletions

File tree

packages/web/src/lib/apollo.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ const getGraphQLUrl = () => {
1010
if (import.meta.env.VITE_GRAPHQL_URL) {
1111
return import.meta.env.VITE_GRAPHQL_URL;
1212
}
13-
// Use same hostname but port 4127 for GraphQL
14-
const protocol = window.location.protocol === 'https:' ? 'https:' : 'http:';
15-
return `${protocol}//${window.location.hostname}:4127/graphql`;
13+
// Use /api/graphql through nginx proxy (works with Docker deployment)
14+
return `/api/graphql`;
1615
};
1716

1817
const getWebSocketUrl = () => {
1918
if (import.meta.env.VITE_GRAPHQL_WS_URL) {
2019
return import.meta.env.VITE_GRAPHQL_WS_URL;
2120
}
22-
// Use same hostname but port 4127 for WebSocket
21+
// Use /api/graphql for WebSocket through nginx proxy
2322
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
24-
return `${protocol}//${window.location.hostname}:4127/graphql`;
23+
return `${protocol}//${window.location.host}/api/graphql`;
2524
};
2625

2726
const httpLink = createHttpLink({

packages/web/src/pages/Admin.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ function DatabaseManagement() {
576576
const updateDatabaseStats = async (debug: string[]) => {
577577
try {
578578
debug.push('📊 Fetching graph count...');
579-
const graphResponse = await fetch('/graphql', {
579+
const graphResponse = await fetch('/api/graphql', {
580580
method: 'POST',
581581
headers: { 'Content-Type': 'application/json' },
582582
body: JSON.stringify({ query: 'query { graphs { id } }' })
@@ -587,7 +587,7 @@ function DatabaseManagement() {
587587
debug.push(`✅ Found ${graphCount} graphs`);
588588

589589
debug.push('📊 Fetching node count...');
590-
const nodeResponse = await fetch('/graphql', {
590+
const nodeResponse = await fetch('/api/graphql', {
591591
method: 'POST',
592592
headers: { 'Content-Type': 'application/json' },
593593
body: JSON.stringify({ query: 'query { workItems { id } }' })
@@ -598,7 +598,7 @@ function DatabaseManagement() {
598598
debug.push(`✅ Found ${nodeCount} nodes`);
599599

600600
debug.push('📊 Fetching edge count...');
601-
const edgeResponse = await fetch('/graphql', {
601+
const edgeResponse = await fetch('/api/graphql', {
602602
method: 'POST',
603603
headers: { 'Content-Type': 'application/json' },
604604
body: JSON.stringify({ query: 'query { edges { id } }' })
@@ -622,7 +622,7 @@ function DatabaseManagement() {
622622

623623
try {
624624
// Check for graphs with invalid types
625-
const graphResponse = await fetch('/graphql', {
625+
const graphResponse = await fetch('/api/graphql', {
626626
method: 'POST',
627627
headers: { 'Content-Type': 'application/json' },
628628
body: JSON.stringify({ query: 'query { graphs { id name } }' })
@@ -673,7 +673,7 @@ function DatabaseManagement() {
673673

674674
try {
675675
// Get all graphs to identify test data
676-
const graphResponse = await fetch('/graphql', {
676+
const graphResponse = await fetch('/api/graphql', {
677677
method: 'POST',
678678
headers: { 'Content-Type': 'application/json' },
679679
body: JSON.stringify({ query: 'query { graphs { id name } }' })
@@ -696,7 +696,7 @@ function DatabaseManagement() {
696696

697697
for (const graph of testGraphs.slice(0, 50)) { // Limit to 50 at a time to avoid timeout
698698
try {
699-
const deleteResponse = await fetch('/graphql', {
699+
const deleteResponse = await fetch('/api/graphql', {
700700
method: 'POST',
701701
headers: { 'Content-Type': 'application/json' },
702702
body: JSON.stringify({
@@ -918,7 +918,7 @@ mutation DeleteGraph($id: ID!) {
918918
debug.push(`🔍 Executing GraphQL query...`);
919919
debug.push(`📝 Query: ${query.substring(0, 100)}${query.length > 100 ? '...' : ''}`);
920920

921-
const response = await fetch('/graphql', {
921+
const response = await fetch('/api/graphql', {
922922
method: 'POST',
923923
headers: { 'Content-Type': 'application/json' },
924924
body: JSON.stringify({ query })
@@ -1153,7 +1153,7 @@ function SecurityManagement() {
11531153
addDebugMessage('📡 Nginx reverse proxy detected');
11541154

11551155
// Test backend connectivity through proxy
1156-
const graphqlResponse = await fetch('/graphql', {
1156+
const graphqlResponse = await fetch('/api/graphql', {
11571157
method: 'POST',
11581158
headers: { 'Content-Type': 'application/json' },
11591159
body: JSON.stringify({ query: '{ __typename }' })
@@ -1789,7 +1789,7 @@ For more details, see: /docs/tls-ssl-setup.md
17891789

17901790
try {
17911791
const gqlStart = Date.now();
1792-
const gqlResponse = await fetch('/graphql', {
1792+
const gqlResponse = await fetch('/api/graphql', {
17931793
method: 'POST',
17941794
headers: { 'Content-Type': 'application/json' },
17951795
body: JSON.stringify({ query: '{ __typename }' })

packages/web/src/pages/Backend.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ export function Backend() {
266266
const updateDatabaseStats = async (debug: string[]) => {
267267
try {
268268
debug.push('📊 Fetching graph count...');
269-
const graphResponse = await fetch('/graphql', {
269+
const graphResponse = await fetch('/api/graphql', {
270270
method: 'POST',
271271
headers: { 'Content-Type': 'application/json' },
272272
body: JSON.stringify({ query: 'query { graphs { id } }' })
@@ -277,7 +277,7 @@ export function Backend() {
277277
debug.push(`✅ Found ${graphCount} graphs`);
278278

279279
debug.push('📊 Fetching node count...');
280-
const nodeResponse = await fetch('/graphql', {
280+
const nodeResponse = await fetch('/api/graphql', {
281281
method: 'POST',
282282
headers: { 'Content-Type': 'application/json' },
283283
body: JSON.stringify({ query: 'query { workItems { id } }' })
@@ -288,7 +288,7 @@ export function Backend() {
288288
debug.push(`✅ Found ${nodeCount} nodes`);
289289

290290
debug.push('📊 Fetching edge count...');
291-
const edgeResponse = await fetch('/graphql', {
291+
const edgeResponse = await fetch('/api/graphql', {
292292
method: 'POST',
293293
headers: { 'Content-Type': 'application/json' },
294294
body: JSON.stringify({ query: 'query { edges { id } }' })
@@ -312,7 +312,7 @@ export function Backend() {
312312

313313
try {
314314
// Check for graphs with invalid types
315-
const graphResponse = await fetch('/graphql', {
315+
const graphResponse = await fetch('/api/graphql', {
316316
method: 'POST',
317317
headers: { 'Content-Type': 'application/json' },
318318
body: JSON.stringify({ query: 'query { graphs { id name } }' })
@@ -363,7 +363,7 @@ export function Backend() {
363363

364364
try {
365365
// Get all graphs to identify test data
366-
const graphResponse = await fetch('/graphql', {
366+
const graphResponse = await fetch('/api/graphql', {
367367
method: 'POST',
368368
headers: { 'Content-Type': 'application/json' },
369369
body: JSON.stringify({ query: 'query { graphs { id name } }' })
@@ -386,7 +386,7 @@ export function Backend() {
386386

387387
for (const graph of testGraphs.slice(0, 50)) { // Limit to 50 at a time to avoid timeout
388388
try {
389-
const deleteResponse = await fetch('/graphql', {
389+
const deleteResponse = await fetch('/api/graphql', {
390390
method: 'POST',
391391
headers: { 'Content-Type': 'application/json' },
392392
body: JSON.stringify({
@@ -1026,7 +1026,7 @@ mutation DeleteGraph($id: ID!) {
10261026
debug.push(`🔍 Executing GraphQL query...`);
10271027
debug.push(`📝 Query: ${query.substring(0, 100)}${query.length > 100 ? '...' : ''}`);
10281028

1029-
const response = await fetch('/graphql', {
1029+
const response = await fetch('/api/graphql', {
10301030
method: 'POST',
10311031
headers: { 'Content-Type': 'application/json' },
10321032
body: JSON.stringify({ query })

packages/web/src/pages/Signup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export function Signup() {
108108
setIsChecking({ ...isChecking, [field]: true });
109109

110110
try {
111-
const response = await fetch('/graphql', {
111+
const response = await fetch('/api/graphql', {
112112
method: 'POST',
113113
headers: { 'Content-Type': 'application/json' },
114114
body: JSON.stringify({

playwright.config.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
/**
4+
* @see https://playwright.dev/docs/test-configuration
5+
*/
6+
export default defineConfig({
7+
testDir: './tests/e2e',
8+
/* Run tests in files in parallel */
9+
fullyParallel: true,
10+
/* Fail the build on CI if you accidentally left test.only in the source code. */
11+
forbidOnly: !!process.env.CI,
12+
/* Retry on CI only */
13+
retries: process.env.CI ? 2 : 0,
14+
/* Opt out of parallel tests on CI. */
15+
workers: process.env.CI ? 1 : undefined,
16+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
17+
reporter: [['html', { outputFolder: 'test-artifacts/reports/playwright-report' }]],
18+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
19+
use: {
20+
/* Base URL to use in actions like `await page.goto('/')`. */
21+
baseURL: process.env.TEST_URL || 'https://localhost:3128',
22+
23+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
24+
trace: 'on-first-retry',
25+
26+
/* Screenshot options */
27+
screenshot: { mode: 'only-on-failure', fullPage: true },
28+
29+
/* Ignore HTTPS errors for self-signed certificates in development */
30+
ignoreHTTPSErrors: true,
31+
},
32+
33+
/* Configure projects for major browsers */
34+
projects: [
35+
{
36+
name: 'GraphDone-Core/dev-neo4j/chromium',
37+
use: { ...devices['Desktop Chrome'] },
38+
},
39+
40+
{
41+
name: 'GraphDone-Core/dev-neo4j/firefox',
42+
use: { ...devices['Desktop Firefox'] },
43+
},
44+
45+
{
46+
name: 'GraphDone-Core/dev-neo4j/webkit',
47+
use: { ...devices['Desktop Safari'] },
48+
},
49+
50+
/* Test against mobile viewports. */
51+
// {
52+
// name: 'Mobile Chrome',
53+
// use: { ...devices['Pixel 5'] },
54+
// },
55+
// {
56+
// name: 'Mobile Safari',
57+
// use: { ...devices['iPhone 12'] },
58+
// },
59+
60+
/* Test against branded browsers. */
61+
// {
62+
// name: 'Microsoft Edge',
63+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
64+
// },
65+
// {
66+
// name: 'Google Chrome',
67+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
68+
// },
69+
],
70+
71+
/* Run your local dev server before starting the tests */
72+
webServer: {
73+
command: 'npm run dev',
74+
url: 'http://localhost:3127',
75+
reuseExistingServer: !process.env.CI,
76+
},
77+
});

0 commit comments

Comments
 (0)