Skip to content

Conversation

@amcaplan
Copy link
Contributor

@amcaplan amcaplan commented Nov 6, 2025

WHY are these changes introduced?

This PR adds custom React hooks for server health monitoring and data fetching. This is the sixth PR in the 8-PR migration stack.

Context: The current template-based GraphiQL implementation uses vanilla JavaScript with setInterval to poll the server for health status and app installation state. By creating reusable React hooks, we can:

  • Integrate polling with React's component lifecycle
  • Automatically clean up intervals when components unmount
  • Use React state management for server status
  • Make polling logic testable and reusable
  • Handle errors gracefully without breaking the UI

WHAT is this pull request doing?

This PR adds two custom hooks that replace vanilla JavaScript polling with React-based data fetching.

Key Changes:

1. usePolling Hook (src/hooks/usePolling.ts):
A generic hook for interval-based polling with proper cleanup and error handling.

Features:

  • Calls a callback function at regular intervals
  • Supports async functions (returns Promise)
  • Handles both sync and async errors gracefully (logs but doesn't crash)
  • Uses useRef to avoid stale closure issues
  • Calls callback immediately on mount, then at intervals
  • Automatically cleans up interval on unmount
  • Can be enabled/disabled dynamically

Usage:

usePolling(async () => {
  await checkServerHealth()
}, {
  interval: 2000,       // Poll every 2 seconds
  enabled: isActive     // Optional: control polling
})

2. useServerStatus Hook (src/hooks/useServerStatus.ts):
Monitors server health and app installation status by polling two endpoints.

Two Polling Mechanisms:

Ping Polling (/graphiql/ping - every 2 seconds by default):

  • Checks if dev server is running
  • Uses timeout mechanism: marks server dead if no response within 3 seconds
  • Clears pending timeouts on successful response
  • Updates serverIsLive state

Status Polling (/graphiql/status - every 5 seconds by default):

  • Checks if app is installed in store
  • Fetches store information (storeFqdn, appName, appUrl)
  • Updates appIsInstalled state and store info

Return Value:

interface ServerStatus {
  serverIsLive: boolean      // Server is responding to pings
  appIsInstalled: boolean    // App is installed in store
  storeFqdn?: string        // e.g., "my-store.myshopify.com"
  appName?: string          // e.g., "My Test App"
  appUrl?: string           // e.g., "http://localhost:3000"
}

Usage:

const status = useServerStatus({
  baseUrl: 'http://localhost:3457',
  pingInterval: 2000,     // Optional: default 2000ms
  statusInterval: 5000,   // Optional: default 5000ms
  pingTimeout: 3000,      // Optional: default 3000ms
})

// Use status in components
<StatusBadge status={status} />
<ErrorBanner isVisible={!status.serverIsLive} />
<LinkPills status={status} />

Error Handling:

  • Network errors are caught and treated as "server down" or "app not installed"
  • Polling continues even if individual requests fail
  • No errors are thrown to crash the application
  • Uses intentional catch-all blocks (with eslint disable comments)

Replaces:

  • Vanilla JavaScript setInterval polling logic
  • Manual timeout tracking and cleanup
  • Direct DOM manipulation based on server status

Testing:

  • 386 lines of comprehensive tests (176 for usePolling, 210 for useServerStatus)
  • Tests interval execution
  • Tests error handling
  • Tests cleanup on unmount
  • Tests timeout behavior
  • Tests state updates

Files Added:

  • src/hooks/usePolling.ts - Generic polling hook (46 lines)
  • src/hooks/usePolling.test.ts - Tests (176 lines)
  • src/hooks/useServerStatus.ts - Server status hook (102 lines)
  • src/hooks/useServerStatus.test.ts - Tests (210 lines)
  • src/hooks/index.ts - Barrel exports

Dependencies

Builds on:

Used by:

How to test your changes?

# Run hook tests
pnpm --filter @shopify/graphiql-console test usePolling.test.ts
pnpm --filter @shopify/graphiql-console test useServerStatus.test.ts

# Type check
pnpm --filter @shopify/graphiql-console tsc --noEmit

# All 386 lines of tests should pass, covering:
# - Polling interval execution
# - Immediate first call on mount
# - Interval cleanup on unmount
# - Error handling (sync and async)
# - Enabled/disabled toggling
# - Server ping timeout behavior
# - Status endpoint response parsing
# - Network error handling

Manual Testing:
You can test the hooks in the App component:

import {useServerStatus} from './hooks'

const status = useServerStatus({
  baseUrl: 'http://localhost:3457'
})

console.log('Server status:', status)

// Stop the dev server and watch serverIsLive change to false
// Restart it and watch it change back to true

Measuring impact

  • n/a - these are foundational data fetching hooks

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

Copy link
Contributor Author

amcaplan commented Nov 6, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Nov 6, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
79.36% (+0.02% 🔼)
13737/17309
🟡 Branches
73.27% (-0% 🔻)
6721/9173
🟡 Functions
79.38% (-0.03% 🔻)
3545/4466
🟡 Lines
79.73% (+0.03% 🔼)
12969/16267
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / usePolling.ts
100% 100% 83.33% 100%
🟢
... / useServerStatus.ts
82.35% 57.14% 66.67% 88.46%

Test suite run success

3437 tests passing in 1399 suites.

Report generated by 🧪jest coverage report action from eeb9b92

@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch from f1c8933 to b9ab875 Compare November 6, 2025 16:53
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch 2 times, most recently from 3b8bbcc to 2e1b3ee Compare November 6, 2025 17:27
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch from b9ab875 to 5b82f74 Compare November 6, 2025 17:27
@amcaplan amcaplan changed the base branch from 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration to graphite-base/6583 November 6, 2025 21:21
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from 2e1b3ee to 8ade16e Compare November 6, 2025 21:21
@amcaplan amcaplan changed the base branch from graphite-base/6583 to 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration November 6, 2025 21:21
@amcaplan amcaplan changed the base branch from 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration to graphite-base/6583 November 6, 2025 21:28
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from 8ade16e to 70c73e5 Compare November 6, 2025 21:29
@amcaplan amcaplan changed the base branch from graphite-base/6583 to 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration November 6, 2025 21:29
@amcaplan amcaplan changed the base branch from 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration to graphite-base/6583 November 6, 2025 21:44
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from 70c73e5 to a6fca5f Compare November 6, 2025 22:14
@amcaplan amcaplan changed the base branch from graphite-base/6583 to 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration November 6, 2025 22:14
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from a6fca5f to f6b80c1 Compare November 6, 2025 22:27
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch from 3e5ff33 to 7479a72 Compare November 6, 2025 22:27
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from f6b80c1 to f574269 Compare November 6, 2025 22:46
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch 2 times, most recently from ba4433a to 34f9d5e Compare November 6, 2025 22:55
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from f574269 to 1e4b9d5 Compare November 6, 2025 22:55
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch from 34f9d5e to 4ff7e34 Compare November 6, 2025 23:17
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch 2 times, most recently from 33e19e2 to fa9758f Compare November 6, 2025 23:21
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch from 4ff7e34 to 9cccb15 Compare November 6, 2025 23:21
Adds custom React hooks for server status polling and data fetching.

- Add usePolling hook for generic interval-based polling
- Add useServerStatus hook for checking server health
- Include comprehensive tests (386 lines)

All hook tests pass
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_graphiql_editor_with_monaco_integration branch from 9cccb15 to fbbce5d Compare November 6, 2025 23:34
@amcaplan amcaplan force-pushed the 11-06-feat_graphiql_add_data_fetching_hooks branch from fa9758f to eeb9b92 Compare November 6, 2025 23:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant