Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion local/LOCAL_DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,54 @@ In a Terminal, run `docker compose up --build`
> The Be sure to compile a `requirements.txt` file before running the docker compose command, or you might miss some important dependencies.


Once these steps are complete you can visit http://localhost:8080/docs to see your Action Runner's browsable API.
Once these steps are complete you can visit:
- http://localhost:8080/docs to see your Action Runner's browsable API
- **http://localhost:3000** to access the web UI for a friendly interface to execute actions

## Authentication

The web UI now includes OpenID Connect authentication to access the Gundi API. By default, the app will redirect to a login page since authentication is required.

### Configuration

To configure authentication, edit `local/web-ui/src/config/auth.js` and update:

- `authority`: Your OIDC provider URL
- `client_id`: Your registered OIDC client ID
- `apiBaseUrl`: The Gundi API base URL

### Features

- **Login/Logout**: Secure authentication with the Gundi API
- **Protected Routes**: All main features require authentication
- **Token Management**: Automatic token renewal and management
- **API Integration**: Access to Gundi API connections and data
- **User Profile**: Display user information in the header

For detailed setup instructions, see `local/web-ui/AUTHENTICATION.md`.

## Web UI

The local deployment now includes a React-based web UI that provides a user-friendly interface for:
- Viewing all available actions
- Executing actions with custom parameters
- Viewing execution results in real-time

The web UI is automatically built and served when you run `docker compose up --build`.

### Troubleshooting Web UI

If you see a blank page at http://localhost:3000:

1. **Check container status**: `docker compose ps`
2. **View web UI logs**: `docker compose logs web-ui`
3. **Verify FastAPI is running**: `curl http://localhost:8080/v1/actions/`
4. **Rebuild if needed**: `docker compose build web-ui && docker compose up -d web-ui`

## Notes

- This example uses configuration from https://stage.gundiservice.org.
- The web UI connects to the FastAPI service running on port 8080



Expand Down
27 changes: 23 additions & 4 deletions local/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:

pubsub_emulator:
image: google/cloud-sdk:latest
platform: linux/amd64
container_name: pubsub_emulator
entrypoint: ["gcloud", "beta", "emulators", "pubsub", "start", "--project=local-project", "--host-port=0.0.0.0:8085"]
environment:
Expand Down Expand Up @@ -59,7 +60,25 @@ services:
pubsub_topic_initializer:
condition: service_completed_successfully
healthcheck:
test: ["CMD-SHELL", "curl -f http://0.0.0.0:8080/"]
interval: 15s
timeout: 15s
retries: 10
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://0.0.0.0:8080/')\""]
interval: 5s
timeout: 5s
retries: 5

web-ui:
build:
context: ./web-ui
dockerfile: Dockerfile
container_name: web_ui
ports:
- "3000:3000"
depends_on:
fastapi:
condition: service_started # service_healthy
environment:
- REACT_APP_API_URL=http://localhost:8080
Comment on lines +72 to +79
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Docker Compose, setting REACT_APP_API_URL as a runtime environment variable will not affect a CRA static build served by serve unless the value is baked in at build time or you implement runtime config injection. As-is, this env var is misleading. Consider using build args, generating a runtime config file, or switching the code to use relative URLs.

Suggested change
container_name: web_ui
ports:
- "3000:3000"
depends_on:
fastapi:
condition: service_started # service_healthy
environment:
- REACT_APP_API_URL=http://localhost:8080
args:
- REACT_APP_API_URL=http://localhost:8080
container_name: web_ui
ports:
- "3000:3000"
depends_on:
fastapi:
condition: service_started # service_healthy

Copilot uses AI. Check for mistakes.
healthcheck:
test: ["CMD-SHELL", "wget --spider -q http://0.0.0.0:3000/ || exit 1"]
interval: 5s
timeout: 5s
retries: 5
21 changes: 21 additions & 0 deletions local/web-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Dependencies
/node_modules
/.pnp
.pnp.js

# Testing
/coverage

# Production
/build

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
157 changes: 157 additions & 0 deletions local/web-ui/AUTHENTICATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Authentication Setup

This web UI now includes OpenID Connect authentication to access the Gundi API. Follow these steps to configure authentication.

## Prerequisites

1. Access to the Gundi API OIDC provider
2. Ability to register a new OIDC client
3. Knowledge of the OIDC authority URL

## Configuration Steps

### 1. Update Authentication Configuration

Edit `src/config/auth.js` and update the following values:

```javascript
export const authConfig = {
// Update this to your actual OIDC authority URL
authority: 'https://api.stage.gundiservice.org',

// Register this client ID in your OIDC provider
client_id: 'gundi-integration-ui',

// These URLs should be registered in your OIDC provider
redirect_uri: `${window.location.origin}/callback`,
post_logout_redirect_uri: `${window.location.origin}/`,
silent_redirect_uri: `${window.location.origin}/silent-callback`,

// API base URL for making authenticated requests
apiBaseUrl: 'https://api.stage.gundiservice.org/v2'
};
Comment on lines +17 to +32
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example configuration (authority/client_id) doesn't match the defaults committed in src/config/auth.js (currently cdip-auth... / cdip-oauth2). This inconsistency will confuse setup. Align the docs with the shipped defaults or explicitly mark the snippet as placeholder values.

Copilot uses AI. Check for mistakes.
```

### 2. Register OIDC Client

In your OIDC provider (likely part of the Gundi API), register a new client with:

- **Client ID**: `gundi-integration-ui` (or update the config to match)
- **Client Type**: Public client (SPA - Single Page Application)
- **Redirect URIs**:
- `http://localhost:3000/callback` (for local development)
- `https://your-domain.com/callback` (for production)
- **Post Logout Redirect URIs**:
- `http://localhost:3000/` (for local development)
- `https://your-domain.com/` (for production)
- **Allowed Scopes**: `openid`, `profile`, `email`
- **Response Types**: `code`
- **Grant Types**: `authorization_code`, `refresh_token`

### 3. Environment-Specific Configuration

For different environments, you may want to use environment variables. Update `src/config/auth.js`:

```javascript
export const authConfig = {
authority: process.env.REACT_APP_OIDC_AUTHORITY || 'https://api.stage.gundiservice.org',
client_id: process.env.REACT_APP_OIDC_CLIENT_ID || 'cdip-oauth2',
apiBaseUrl: process.env.REACT_APP_API_BASE_URL || 'https://api.stage.gundiservice.org/v2',
// ... other config
};
```

Then create environment files:
- `.env.local` for local development
- `.env.production` for production

### 4. Test Authentication

1. Start the web UI: `npm start` or `docker compose up`
2. Navigate to `http://localhost:3000`
3. You should be redirected to the login page
4. Click "Sign in with Gundi" to test the OIDC flow
5. After successful authentication, you should see the main interface
6. Navigate to "Configurations" to test API access

## Features

### Authentication Flow
- **Login**: Redirects to OIDC provider for authentication
- **Silent Renewal**: Automatically renews tokens in the background
- **Logout**: Properly signs out from both the app and OIDC provider
- **Token Management**: Handles access tokens for API requests

### Protected Routes
- All main application routes require authentication
- Unauthenticated users are redirected to the login page
- Loading states during authentication checks

### API Integration
- Automatic token inclusion in API requests
- Error handling for expired tokens
- Configuration viewer for Gundi API data

## Troubleshooting

### Common Issues

1. **"Invalid redirect URI" error**
- Ensure the redirect URIs in your OIDC client match exactly
- Check for trailing slashes and protocol (http vs https)

2. **"Client not found" error**
- Verify the client_id in your configuration
- Ensure the client is properly registered in the OIDC provider

3. **CORS errors**
- The OIDC provider needs to allow requests from your domain
- Check the OIDC provider's CORS configuration

4. **Token expiration issues**
- Ensure silent renewal is properly configured
- Check that the silent redirect URI is registered

### Debug Mode

Enable debug logging by adding to your browser's console:
```javascript
localStorage.setItem('oidc.debug', 'true');
```

### Manual Token Inspection

You can inspect stored tokens in the browser's developer tools:
```javascript
// In browser console
JSON.parse(localStorage.getItem('oidc.user:https://api.stage.gundiservice.org:gundi-integration-ui'))
```

## Security Considerations

1. **Client ID**: The client ID is public and can be exposed in the frontend
2. **Token Storage**: Tokens are stored in localStorage (consider httpOnly cookies for production)
3. **HTTPS**: Always use HTTPS in production
4. **Token Expiration**: Tokens are automatically renewed, but users will need to re-authenticate if renewal fails

## API Usage

Once authenticated, the app can make requests to the Gundi API:

```javascript
import { useAuth } from '../contexts/AuthContext';

const MyComponent = () => {
const { getApiHeaders } = useAuth();

const fetchData = async () => {
const headers = await getApiHeaders();
const response = await axios.get('https://api.stage.gundiservice.org/v2/configurations/', {
headers
});
return response.data;
};
};
```

The `getApiHeaders()` function automatically includes the Bearer token for authenticated requests.
24 changes: 24 additions & 0 deletions local/web-ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM node:18-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy source code
COPY . .

# Build the app
RUN npm run build

# Install serve to run the built app
RUN npm install -g serve

# Expose port
EXPOSE 3000

# Start the app
CMD ["serve", "-s", "build", "-l", "3000"]
Loading
Loading