Documentation Index
Fetch the complete documentation index at: https://docs.skyvexsoftware.com/llms.txt
Use this file to discover all available pages before exploring further.
The UI module is a single React component exported as the default export from src/ui/index.tsx. The shell renders it in the main content area when a pilot selects your plugin in the sidebar.
What the Shell Provides
The shell injects several libraries at runtime — you don’t need to bundle them, and the build system externalises them automatically. Import them directly:
react, react-dom
@tanstack/react-query, @tanstack/react-router
@skyvexsoftware/stratos-sdk (hooks, UI components, types, helpers)
sonner (toast notifications)
socket.io-client
maplibre-gl, react-map-gl/maplibre
Anything else you import — lucide-react, your own utilities, third-party libraries — will be bundled into your plugin’s ui/index.js.
Using usePluginContext()
The primary way to access shell state from any component in your plugin:
import { usePluginContext } from "@skyvexsoftware/stratos-sdk";
function MyComponent() {
const ctx = usePluginContext();
// ctx.pluginId — your plugin's ID string
// ctx.auth — { isAuthenticated, token, user }
// ctx.airline — { id, name, icao, logo_light, logo_dark } or null
// ctx.config — { get<T>(key, default?) }
// ctx.navigation — navigate within/between plugins
// ctx.toast — { success(), error(), info(), warning() }
// ctx.logger — { info(), warn(), error(), debug() }
}
usePluginContext() can be called in any component in your tree — not just the root. The context is provided by the PluginShellProvider that wraps your entire plugin.
Auth
const { auth } = usePluginContext();
if (!auth.isAuthenticated || !auth.user) {
return <p>Please log in to use this plugin.</p>;
}
// auth.user: PluginPilotUser — pilot profile (firstName, lastName, pilotID, rank, avatar, etc.)
// auth.token: string | null — VA auth token for API calls
You can also use the convenience hook:
import { useShellAuth } from "@skyvexsoftware/stratos-sdk";
const { isAuthenticated, token, user } = useShellAuth();
Calling the VA’s API
For HTTP calls to the bound airline’s API, use useVaApi(). It returns a pre-configured axios instance that attaches the bearer, sets the airline’s base_url, and transparently refreshes the access token on 401:
import { useVaApi } from "@skyvexsoftware/stratos-sdk";
const va = useVaApi();
const { data } = await va.get("/pilot/verify");
This is the renderer-side equivalent of ctx.airline.createClient() in background modules.
Config
Read plugin settings declared in your manifest’s availableSettings. Config access in the UI module is synchronous — values are pre-loaded when your plugin mounts:
const { config } = usePluginContext();
const welcomeMsg = config.get<string>("welcome_message", "Hello!");
const links = config.get<QuickLink[]>("quick_links", []);
The second argument to get() is the default value, returned when the setting has not been explicitly set.
Note: config.get() in the UI context reads airline-scoped plugin configuration — settings managed by the VA admin on the Skyvex platform. User-scoped settings (personal preferences like unit system, display toggles, and refresh intervals) are managed through the shell’s settings UI and are not accessible via this API.
Navigation
Navigate within your plugin or jump to other plugins and shell routes:
const { navigation } = usePluginContext();
// Within your plugin (appends to /plugins/my-plugin/)
navigation.navigateTo("roster");
navigation.navigateTo("roster/pilot-123");
// To another plugin
navigation.navigateToPlugin("flight-tracking", "history");
// To a shell page
navigation.navigateToShell("/settings");
// Read the current path
const path = navigation.getCurrentPath();
For multi-page plugins, see the Routing page.
Toast Notifications
const { toast } = usePluginContext();
toast.success("Flight booked successfully");
toast.error("Failed to connect to VA server");
toast.info("New PIREP available");
toast.warning("Low fuel warning");
Or use the dedicated hook:
import { useShellToast } from "@skyvexsoftware/stratos-sdk";
const { success, error, info, warning } = useShellToast();
Styling
Plugins share the shell’s Tailwind CSS theme. Use standard Tailwind utility classes:
<div className="bg-card rounded-lg border p-6">
<h2 className="text-lg font-semibold">Section Title</h2>
<p className="text-muted-foreground mt-2 text-sm">Supporting text</p>
</div>
Key design tokens available via Tailwind classes:
| Class | Usage |
|---|
bg-card | Card and panel backgrounds |
bg-muted | Subtle, secondary backgrounds |
text-muted-foreground | Secondary and supporting text |
border | Standard dividers and outlines |
bg-primary / text-primary | Accent colour (configured per-airline) |
bg-background | Page-level background |
text-foreground | Primary text |
The shell switches between light and dark Tailwind themes automatically — your components inherit the correct variables without any additional work.
SDK UI Components
Import pre-built shadcn/ui components from the SDK to stay consistent with the shell’s design:
import {
Button,
Card,
CardHeader,
CardTitle,
CardContent,
Badge,
Input,
Label,
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
Tabs,
TabsList,
TabsTrigger,
TabsContent,
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
Separator,
Switch,
Slider,
} from "@skyvexsoftware/stratos-sdk";
See UI Components for the full reference.
Minimal Example
import { usePluginContext, Card, CardContent } from "@skyvexsoftware/stratos-sdk";
export default function MyPlugin() {
const { auth, airline, toast } = usePluginContext();
if (!auth.isAuthenticated || !auth.user) {
return (
<div className="flex h-full items-center justify-center">
<p className="text-muted-foreground">Please log in to continue.</p>
</div>
);
}
return (
<div className="p-6 space-y-4">
<h1 className="text-2xl font-bold">
Welcome, {auth.user.firstName}
</h1>
<Card>
<CardContent className="p-4">
<p className="text-muted-foreground text-sm">
Connected to {airline?.name ?? "your VA"}
</p>
</CardContent>
</Card>
<button
className="text-sm text-primary underline"
onClick={() => toast.success("Hello from My Plugin!")}
>
Send toast
</button>
</div>
);
}