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/viewsProject 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 potentialnullorundefinedvalues 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 thejobobject (outputs flattened)useJuggernautRecord()with therecordobjectuseJuggernautActions()with theactionsobject
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 deployThis 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
- Always null-check outputs. Job and record data may be incomplete. Use optional chaining (
job?.deepAnalysis) or explicit guards before rendering. - Mock edge cases in `.demo.json`. Test with missing fields, empty arrays, and
nullvalues to ensure UI resilience. - Use action API Names consistently. The key in
useJuggernautActions()must match the API Name set in the process Outputs tab. - Keep views stateless where possible. Rely on platform data via hooks rather than local state for core rendering logic.