← Back to Home

View SDK

The bridge between your platform's backend logic and rich, interactive user experiences. Inject custom React interfaces directly into platform contexts — Process Job Results and Database Records — without complex API fetching logic.

Installation

npm install @juggernautlabs/views

Project Setup

Add these scripts to your package.json. The SDK includes a CLI for local development and deployment.

{
  "scripts": {
    "dev": "npx @juggernautlabs/views dev index.tsx",
    "build": "vite build",
    "deploy": "npx @juggernautlabs/views deploy ./index.tsx"
  }
}

Usage: Process Jobs

Build interactive interfaces for the results of a Process Job. Essential for workflows requiring manual review or distinct "next steps" based on job output.

The Hooks

| Hook | Returns | |---|---| | useJuggernautJob() | The job context. Output keys are flattened directly onto the object — not nested under output. | | useJuggernautActions() | Available follow-up actions defined in the process Outputs tab. |

Job Data Structure

useJuggernautJob() returns an object where each output key from the job is a top-level property. There is no job.output wrapper.

// If your process outputs "deepAnalysis" and "summary":
const job = useJuggernautJob();

// Access outputs DIRECTLY — not via job.output
job.deepAnalysis      // => { ... }
job.summary           // => { ... }

// Also available:
job.id                // => "job_123"
job.status            // => "completed"
job.title             // => "Job Title"
Important: Always account for potential null or undefined values when building interfaces. Job outputs may be missing, partially populated, or still loading depending on execution state. Defensive checks prevent runtime crashes.

Implementation Example

import { useJuggernautJob, useJuggernautActions } from '@juggernautlabs/views';

export const JobResultView = () => {
  const job = useJuggernautJob();
  const actions = useJuggernautActions();

  // Guard against missing outputs before rendering
  if (!job || !job.deepAnalysis) {
    return <div>Loading job data...</div>;
  }

  // "approve_curriculum" corresponds to the API Name of the action
  // defined in your Juggernaut output settings.
  const handleApprove = () => {
    if (actions?.approve_curriculum) {
      actions.approve_curriculum.execute({
        inputs: {
          jobId: job.id,
          status: 'approved',
          reviewerNotes: 'Curriculum meets all standards.'
        },
        metadata: {
          source: 'reviewer_dashboard_v1'
        }
      });
    }
  };

  return (
    <div className="review-container">
      <h1>Reviewing: {job.title}</h1>

      {/* Access outputs directly — job.deepAnalysis, not job.output.deepAnalysis */}
      <div className="analysis">
        <h2>Deep Analysis</h2>
        <pre>{JSON.stringify(job.deepAnalysis, null, 2)}</pre>
      </div>

      {job.summary && (
        <div className="summary">
          <h2>Summary</h2>
          <p>{job.summary}</p>
        </div>
      )}

      <div className="footer">
        <button onClick={handleApprove}>
          Approve & Publish
        </button>
      </div>
    </div>
  );
};

Configuration Note: For an action to appear in useJuggernautActions, it must be explicitly added to the Trigger Actions section within the Outputs tab of your Process configuration.


Usage: Database Records

Create custom visual layers for database records. Render distinct UIs based on record content.

The Hook

| Hook | Returns | |---|---| | useJuggernautRecord() | The full data object for the current database record context. |

Null Safety: Database records may have missing fields, especially for new or incomplete entries. Always validate fields exist before rendering dependent UI elements (images, embeds, nested data).

Implementation Example

import { useJuggernautRecord } from '@juggernautlabs/views';

export const MovieRecordView = () => {
  const movie = useJuggernautRecord();

  // Guard against null/undefined record data
  if (!movie) {
    return <div>Loading record...</div>;
  }

  return (
    <div className="movie-card">
      <div
        className="header"
        style={{
          backgroundImage: movie.backdrop ? `url(${movie.backdrop})` : undefined
        }}
      >
        <h1>{movie.title || 'Untitled'}</h1>
      </div>
      <div className="content">
        <p>{movie.description || 'No description available.'}</p>

        {/* Conditional rendering with null check */}
        {movie.trailerId && (
          <iframe src={`https://youtube.com/embed/${movie.trailerId}`} />
        )}
      </div>
    </div>
  );
};

Local Development (Mocking Data)

Develop UI with realistic data using a .demo.json file in your component directory.

.demo.json Structure

{
  "job": {
    "id": "job_123",
    "status": "completed",
    "title": "Curriculum Review Job",
    "deepAnalysis": {
      "modules": 5,
      "readabilityScore": 87,
      "topics": ["React", "TypeScript", "State Management"]
    },
    "summary": "Curriculum is well-structured and ready for deployment."
  },
  "record": {
    "id": "rec_456",
    "title": "Inception",
    "backdrop": "https://example.com/inception-backdrop.jpg",
    "description": "A thief who steals corporate secrets...",
    "trailerId": "8hP9D6kZseM"
  },
  "actions": {
    "approve_curriculum": {
      "type": "process_trigger",
      "label": "Approve"
    }
  }
}

When you run npm run dev, the CLI reads this file and hydrates:

  • useJuggernautJob() with the job object (outputs flattened)
  • useJuggernautRecord() with the record object
  • useJuggernautActions() with the actions object
Tip: Include incomplete or null-valued mock data in .demo.json to test your null-safety guards during development.

Deployment

Bundle and upload your view to the Juggernaut platform:

npm run deploy

This uploads to the view configuration specified in your index.tsx.


API Reference

useJuggernautJob()

const job = useJuggernautJob();

Returns the job context object. Output keys are top-level properties — access them directly (e.g., job.deepAnalysis), not via job.output.

| Property | Type | Description | |---|---|---| | id | string | Job identifier. | | status | string | Execution status (pending, running, completed, failed). | | title | string | Job display title. | | [outputKey] | any | Flattened output keys from the process. Varies per job. |

useJuggernautRecord()

const record = useJuggernautRecord();

Returns the database record object. Fields match your collection schema. Always handle potential null values.

useJuggernautActions()

const actions = useJuggernautActions();

Returns an object keyed by action API Names. Each action exposes an .execute() method.

action.execute(payload)

| Property | Type | Required | Description | |---|---|---|---| | inputs | object | Yes | Key-value pairs matching input variables in the target process. | | metadata | object | No | Additional context for logging/auditing. |

actions.approve_curriculum.execute({
  inputs: { jobId: job.id, status: 'approved' },
  metadata: { source: 'reviewer_dashboard_v1' }
});

Best Practices

  1. Always null-check outputs. Job and record data may be incomplete. Use optional chaining (job?.deepAnalysis) or explicit guards before rendering.
  2. Mock edge cases in `.demo.json`. Test with missing fields, empty arrays, and null values to ensure UI resilience.
  3. Use action API Names consistently. The key in useJuggernautActions() must match the API Name set in the process Outputs tab.
  4. Keep views stateless where possible. Rely on platform data via hooks rather than local state for core rendering logic.