Skip to main content
Version: 57.2.0

@terreno/admin-frontend

React Native components for building admin panels that connect to @terreno/admin-backend.

Quick Start

// app/admin/index.tsx
import {AdminModelList} from "@terreno/admin-frontend";
import {api} from "@/store/openApiSdk";

export default function AdminScreen() {
return <AdminModelList baseUrl="/admin" api={api} />;
}

Components

AdminModelList

Entry screen showing all available models as cards.

<AdminModelList
baseUrl="/admin"
api={api}
/>

Fetches config from {baseUrl}/config and displays clickable model cards.

AdminModelTable

Table view for a specific model with pagination, sorting, and actions.

<AdminModelTable
baseUrl="/admin"
api={api}
modelName="User"
/>

Features:

  • DataTable with columns from backend listFields
  • Click row to edit
  • "Create New" button
  • Pagination controls
  • Reference fields render as clickable links

AdminModelForm

Create or edit form for a model instance.

<AdminModelForm
baseUrl="/admin"
api={api}
modelName="User"
id="507f1f77bcf86cd799439011" // Optional for edit mode
/>

Auto-generates fields from model schema:

  • string → TextField
  • boolean → BooleanField
  • number → NumberField
  • date → DateTimeField
  • objectid (ref) → SelectField
  • enum → SelectField with options

System fields (_id, __v, created, updated, deleted) are automatically skipped.

AdminRolesList

Role editing starts with a dedicated Admin page toggle for admin:access. That is the only permission that opens the admin panel. Grant it first; model and tool permissions do nothing until the role can enter.

Standard admin model permissions then use one access-level selector:

  • No access
  • Read only
  • Read + write owned
  • Read + write all

Other application and screen permissions remain individual toggles. Saving writes the same permission JSON used by rbacRouter, so no separate configuration format is required.

AdminFieldRenderer

Renders field values in table cells with formatting.

<AdminFieldRenderer
value={value}
field={fieldConfig}
modelName="User"
baseUrl="/admin"
/>

Handles booleans, dates, ObjectId refs, arrays, objects, and null/undefined.

AdminRefField

Renders reference fields as clickable links.

<AdminRefField
value={userId}
refModel="User"
baseUrl="/admin"
/>

Hooks

useAdminConfig

Fetches admin configuration from backend.

const {config, isLoading, error} = useAdminConfig(api, baseUrl);

Returns model metadata from {baseUrl}/config.

useAdminApi

Generates RTK Query hooks for CRUD operations.

const {
useListQuery,
useGetQuery,
useCreateMutation,
useUpdateMutation,
useDeleteMutation,
} = useAdminApi(api, baseUrl, modelName);

const {data, isLoading} = useListQuery({limit: 20, page: 1});
const [create] = useCreateMutation();
await create({email: "user@example.com"}).unwrap();

Expo Router Setup

// app/admin/_layout.tsx
import {Stack} from "expo-router";

export default function AdminLayout() {
return <Stack screenOptions={{headerShown: false}} />;
}

// app/admin/index.tsx - Model list
import {AdminModelList} from "@terreno/admin-frontend";
export default () => <AdminModelList baseUrl="/admin" api={api} />;

// app/admin/[modelName]/index.tsx - Model table
import {AdminModelTable} from "@terreno/admin-frontend";
export default () => {
const {modelName} = useLocalSearchParams();
return <AdminModelTable baseUrl="/admin" api={api} modelName={modelName} />;
};

// app/admin/[modelName]/new.tsx - Create form
import {AdminModelForm} from "@terreno/admin-frontend";
export default () => {
const {modelName} = useLocalSearchParams();
return <AdminModelForm baseUrl="/admin" api={api} modelName={modelName} />;
};

// app/admin/[modelName]/[id].tsx - Edit form
import {AdminModelForm} from "@terreno/admin-frontend";
export default () => {
const {modelName, id} = useLocalSearchParams();
return <AdminModelForm baseUrl="/admin" api={api} modelName={modelName} id={id} />;
};

Protecting Admin Routes

// app/_layout.tsx
import {useSelectCurrentUser} from "@/store/openApiSdk";
import {Redirect} from "expo-router";

function RootLayout() {
const user = useSelectCurrentUser();
const pathname = usePathname();

if (!user?.admin && pathname.startsWith("/admin")) {
return <Redirect href="/" />;
}

return <Stack />;
}

Custom Field Renderers

Extend AdminFieldRenderer for custom field types:

const CustomFieldRenderer = ({value, field, ...props}) => {
if (field.type === "myCustomType") {
return <MyCustomComponent value={value} />;
}
return <AdminFieldRenderer value={value} field={field} {...props} />;
};

Integration

Expects backend to provide:

  1. GET {baseUrl}/config — Model metadata
  2. CRUD routes at {basePath}{routePath} for each model
  3. admin:access (or IsAdmin when RBAC is off) to open the page; per-model RBAC after that
  4. Paginated responses: {data, page, limit, total, more}

When RBAC is enabled, /admin/config is filtered for the current user. AdminShell uses its platformTools flags to hide denied Scripts, Roles, Version, and Configuration links, and only renders model or custom-screen links returned by the server.