React Hooks & Context
The ez-console package re-exports UI building blocks from web/src/index.ts. This page documents the React hooks and context values you use most often inside pages and components rendered under EZApp (or any tree that includes the same providers).
For the full export catalog (components, api, client, types), see Package exports (index.ts).
For HTTP helpers (apiGet, apiPost, …) and the aggregated api object, see API integration. For declarative permission UI, see PermissionGuard / AdminGuard. For backend AI pipelines, see AI model integration.
useAuth
Reads authentication state from AuthProvider (mounted by EZApp).
Returns (shape from AuthContextType):
| Field | Type | Notes |
|---|---|---|
user | API.User | null | undefined | undefined while the initial session check is in flight; null when logged out |
loading | boolean | Session bootstrap loading |
login | (data: Partial<API.LoginRequest>) => Promise<API.User | null> | Sets token and user on success; may throw for MFA / password-expired flows |
oauthLogin | (data: API.OAuthCallbackRequest) => Promise<API.User | null> | OAuth callback completion |
logout | () => void | Clears token and user |
updateUser | (user: API.User) => void | Replace the cached user object |
error | Error | undefined | Last error from loading the current user |
import { useAuth } from 'ez-console';
export const ProfileSummary: React.FC = () => {
const { user, loading, logout } = useAuth();
if (loading || user === undefined) {
return null;
}
if (!user) {
return <span>Not signed in</span>;
}
return (
<span>
{user.username}
<button type="button" onClick={logout}>
Sign out
</button>
</span>
);
};
usePermission
RBAC checks for the current organization (useSite().currentOrgId). Roles are filtered to those that are global (organization_id unset) or belong to the active org. Users with the global admin role bypass permission checks.
Returns:
| Field | Type | Description |
|---|---|---|
hasPermission | (code: string) => boolean | Single permission code (e.g. backend-defined authorization:user:create) |
hasAllPermissions | (codes: string[]) => boolean | Every code must pass |
hasAnyPermission | (codes: string[]) => boolean | At least one code |
hasGlobalPermission | (code: string) => boolean | Like hasPermission, but only roles without organization_id are considered |
isAdmin | boolean | Global admin role present |
loading | boolean | true while user is still undefined |
import { Button } from 'antd';
import { usePermission } from 'ez-console';
export const UserToolbar: React.FC = () => {
const { hasPermission, loading } = usePermission();
if (loading) {
return null;
}
return (
<>
{hasPermission('authorization:user:create') && (
<Button type="primary">New user</Button>
)}
</>
);
};
Use PermissionGuard when you prefer JSX over imperative checks. AdminGuard only renders children for global admins.
useSite
Site-wide configuration, current organization, and lightweight task notifications used by the shell.
Returns (highlights from SiteContextType):
| Field | Type | Description |
|---|---|---|
siteConfig | API.SiteConfig | null | From api.system.getSiteConfig() after login |
loading | boolean | Site config request in flight |
fetchSiteConfig | () => Promise<API.SiteConfig | null> | Manual refresh |
enableMultiOrg | boolean | Derived from siteConfig.enable_multi_org |
enableSkillToolBinding | boolean | Derived from siteConfig.enable_skill_tool_binding |
currentOrgId | string | null | Persisted under orgID in localStorage |
setCurrentOrgId / clearCurrentOrgId | functions | Switch or clear org context |
tasks / setTasks / addTask | In-app task list for long-running work | |
tasksDropdownOpen / setTasksDropdownOpen | Shell task dropdown visibility |
import { useSite } from 'ez-console';
export const OrgBanner: React.FC = () => {
const { siteConfig, loading, currentOrgId, enableMultiOrg } = useSite();
if (loading || !enableMultiOrg) {
return null;
}
return <div>Active organization: {currentOrgId}</div>;
};
useAI
Global AI assistant UI state: layout, visibility, conversations list, and page-level tools / prompts for the embedded chat.
Typical uses:
- Open the assistant with a prefilled user message:
callAI(message, priorMessages?). - Register ephemeral system prompts, client tools, and optional page data for the current route (cleared automatically when the route changes inside
AppLayout).
Exported types (for TypeScript): PageAIOptions, RegisteredClientTool, ClientToolHandler, PageDataGetter.
Context fields
| Field | Type | Description |
|---|---|---|
layout | 'classic' | 'sidebar' | 'float-sidebar' | Chat panel layout |
setLayout | (layout) => void | |
visible | boolean | Chat open/closed |
setVisible | (visible: boolean) => void | |
callAI | (message: string, messages?: API.SimpleChatMessage[]) => void | Opens chat and forwards to the registered handler |
onCallAI | (cb) => void | Used internally by AIChat to receive callAI invocations |
loaded / setLoaded | boolean / setter | Chat surface mounted |
fetchConversations | () => Promise<API.AIChatSession[]> | Loaded when chat becomes visible |
fetchConversationsLoading | boolean | |
conversations | API.AIChatSession[] | undefined | |
activeConversationKey / setActiveConversationKey | Persisted as activeConversationKey in localStorage | |
ephemeralSystemPrompts | string[] | Merged from the last registerPageAI call |
clientTools | RegisteredClientTool[] | Includes auto-registered ui_get_page_data when pageData is set |
registerPageAI | (opts: PageAIOptions) => () => void | Register page context; returns an unregister function |
resetPageAIContext | () => void | Clears prompts and tools |
registerPageAI options (PageAIOptions)
| Option | Type | Description |
|---|---|---|
ephemeralSystemPrompts | string[] | Extra system instructions for this page only |
tools | RegisteredClientTool[] | Browser-side tools exposed to the model; each name must start with ui_ |
pageData | any | PageDataGetter | Static snapshot, object, or getter; when set, the framework adds tool ui_get_page_data |
pageDataDescription | string | Appended to the built-in tool description for the model |
import { useEffect } from 'react';
import { useAI } from 'ez-console';
export const OrdersPage: React.FC = () => {
const { registerPageAI } = useAI();
const [orders, setOrders] = useState<API.Order[]>([]);
useEffect(() => {
const unregister = registerPageAI({
ephemeralSystemPrompts: [
'The user is on the Orders list. Prefer concise tables when summarizing.',
],
pageData: () => orders,
pageDataDescription: 'Current in-memory order rows for the active filters.',
tools: [
{
name: 'ui_focus_order',
description: 'Scroll the table to the order id given by the user.',
parameters: {
type: 'object',
properties: { orderId: { type: 'string' } },
required: ['orderId'],
},
handler: async (argsJson) => {
const { orderId } = JSON.parse(argsJson) as { orderId: string };
document.getElementById(`order-${orderId}`)?.scrollIntoView();
return JSON.stringify({ ok: true });
},
},
],
});
return unregister;
}, [registerPageAI, orders]);
return (/* ... */);
};
Invoke the assistant from your own UI:
const { callAI } = useAI();
callAI('Summarize the visible orders and highlight anomalies.');
For how models, toolsets, and SSE events work on the server, see AI model integration.
Related exports
From the same package entry you will often import:
- Routing:
withSuspense,IRoute,IRouteGroup,IRouteItem— see Routing & navigation. - i18n:
useTranslation(fromreact-i18next),i18n— see Internationalization. - Components:
EZApp,Table,AIChat, … — see Built-in components.
Need help? Ask in GitHub Discussions.