@tideorg/ui
v0.0.1
Published
Tide UI Framework - Reusable components for data management interfaces
Downloads
10
Readme
@tide/ui
Ready-to-use admin pages for Tide. Manage users, roles, approvals, logs, and templates with minimal setup.
Install
npm install @tide/ui @tidecloak/react @tidecloak/jsQuick Start
import { QueryClient, QueryClientProvider, UsersPage } from '@tide/ui';
import { TideCloakContextProvider, useTideCloak, Authenticated, Unauthenticated } from '@tidecloak/react';
import tidecloakConfig from './tidecloak.json';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<TideCloakContextProvider config={tidecloakConfig}>
<Authenticated>
<AdminDashboard />
</Authenticated>
<Unauthenticated>
<LoginPage />
</Unauthenticated>
</TideCloakContextProvider>
</QueryClientProvider>
);
}
function AdminDashboard() {
const { AdminAPI } = useTideCloak();
return <UsersPage adminAPI={AdminAPI} title="Users" />;
}
function LoginPage() {
const { login } = useTideCloak();
return <button onClick={login}>Login</button>;
}That's it. You have a working user management page.
Available Pages
UsersPage
Manage users and assign roles.
<UsersPage adminAPI={AdminAPI} />RolesPage
Create roles with policy support and approval workflows.
import { createLocalStoragePolicyAPI, createLocalStorageTemplateAPI } from '@tide/ui';
<RolesPage
adminAPI={AdminAPI}
policyAPI={createLocalStoragePolicyAPI()}
templateAPI={createLocalStorageTemplateAPI()}
tideContext={tideContext}
currentUsername={username}
/>ApprovalsPage
Review and approve pending changes.
<ApprovalsPage
adminAPI={AdminAPI}
tideContext={tideContext}
currentUsername={username}
/>LogsPage
View access and policy activity.
import { createLocalStoragePolicyLogsAPI } from '@tide/ui';
<LogsPage
adminAPI={AdminAPI}
policyLogsAPI={createLocalStoragePolicyLogsAPI()}
/>TemplatesPage
Manage policy templates.
import { createLocalStorageTemplateAPI } from '@tide/ui';
<TemplatesPage api={createLocalStorageTemplateAPI()} />Full Example
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import {
QueryClient, QueryClientProvider,
UsersPage, RolesPage, ApprovalsPage, LogsPage, TemplatesPage,
createLocalStorageTemplateAPI,
createLocalStoragePolicyAPI,
createLocalStorageAccessMetadataAPI,
createLocalStoragePolicyLogsAPI,
Tabs, TabsList, TabsTrigger, TabsContent,
} from '@tide/ui';
import { TideCloakContextProvider, useTideCloak, Authenticated, Unauthenticated } from '@tidecloak/react';
import tidecloakConfig from './tidecloak.json';
const queryClient = new QueryClient();
const templateAPI = createLocalStorageTemplateAPI();
const policyAPI = createLocalStoragePolicyAPI();
const accessMetadataAPI = createLocalStorageAccessMetadataAPI();
const policyLogsAPI = createLocalStoragePolicyLogsAPI();
function AdminDashboard() {
const {
AdminAPI,
logout,
isInitializing,
getValueFromIdToken,
initializeTideRequest,
getVendorId,
getResource,
approveTideRequests,
} = useTideCloak();
const tideContext = { initializeTideRequest, getVendorId, getResource, approveTideRequests };
const username = getValueFromIdToken('preferred_username') ?? undefined;
if (isInitializing) {
return <p>Loading...</p>;
}
return (
<div>
<header>
<h1>Admin Dashboard</h1>
<p>Signed in as {username}</p>
<button onClick={logout}>Logout</button>
</header>
<Tabs defaultValue="users">
<TabsList>
<TabsTrigger value="users">Users</TabsTrigger>
<TabsTrigger value="roles">Roles</TabsTrigger>
<TabsTrigger value="approvals">Approvals</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
<TabsTrigger value="templates">Templates</TabsTrigger>
</TabsList>
<TabsContent value="users">
<UsersPage adminAPI={AdminAPI} accessMetadataAPI={accessMetadataAPI} />
</TabsContent>
<TabsContent value="roles">
<RolesPage
adminAPI={AdminAPI}
templateAPI={templateAPI}
policyAPI={policyAPI}
policyLogsAPI={policyLogsAPI}
tideContext={tideContext}
currentUsername={username}
/>
</TabsContent>
<TabsContent value="approvals">
<ApprovalsPage
adminAPI={AdminAPI}
tideContext={tideContext}
accessMetadataAPI={accessMetadataAPI}
policyLogsAPI={policyLogsAPI}
currentUsername={username}
/>
</TabsContent>
<TabsContent value="logs">
<LogsPage adminAPI={AdminAPI} policyLogsAPI={policyLogsAPI} />
</TabsContent>
<TabsContent value="templates">
<TemplatesPage api={templateAPI} />
</TabsContent>
</Tabs>
</div>
);
}
function LoginPage() {
const { login } = useTideCloak();
return (
<div>
<h1>Welcome</h1>
<button onClick={login}>Login</button>
</div>
);
}
createRoot(document.getElementById('root')!).render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<TideCloakContextProvider config={tidecloakConfig}>
<Authenticated>
<AdminDashboard />
</Authenticated>
<Unauthenticated>
<LoginPage />
</Unauthenticated>
</TideCloakContextProvider>
</QueryClientProvider>
</StrictMode>
);Storage Adapters
For development, use the localStorage adapters. They work instantly but show a warning that data won't persist across devices.
createLocalStorageTemplateAPI() // Policy templates
createLocalStoragePolicyAPI() // Role policies
createLocalStorageAccessMetadataAPI() // Change set metadata
createLocalStoragePolicyLogsAPI() // Policy activity logs
createLocalStoragePolicyApprovalsAPI() // Policy approvalsFor production, implement your own:
const myPolicyAPI: PolicyAPI = {
getPolicy: (roleName) => fetch(`/api/policies/${roleName}`).then(r => r.json()),
upsertPolicy: (policy) => fetch('/api/policies', { method: 'POST', body: JSON.stringify(policy) }),
deletePolicy: (roleName) => fetch(`/api/policies/${roleName}`, { method: 'DELETE' }),
};Tide Enclave Integration
Pass tideContext to enable the Tide approval enclave popup for cryptographic signing:
const {
initializeTideRequest,
getVendorId,
getResource,
approveTideRequests,
} = useTideCloak();
const tideContext = { initializeTideRequest, getVendorId, getResource, approveTideRequests };
<ApprovalsPage tideContext={tideContext} />
<RolesPage tideContext={tideContext} />Custom Data Fetching
Need full control? Use the base components:
import { UsersPageBase } from '@tide/ui';
<UsersPageBase
fetchUsers={() => myApi.getUsers()}
fetchRoles={() => myApi.getRoles()}
onCreate={(data) => myApi.createUser(data)}
onUpdateProfile={(data) => myApi.updateUser(data)}
onUpdateRoles={(data) => myApi.updateRoles(data)}
onDelete={(id) => myApi.deleteUser(id)}
/>Available base components: UsersPageBase, RolesPageBase, ApprovalsPageBase, LogsPageBase, TemplatesPageBase
Built-in UI Components
Works out of the box with inline styles. No Tailwind or CSS required.
import {
Card, CardContent, Button, Badge, Input, Label,
Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
Dialog, DialogContent, DialogHeader, DialogTitle,
Tabs, TabsList, TabsTrigger, TabsContent,
} from '@tide/ui';Or pass your own shadcn/ui components:
import { Button } from '@/components/ui/button';
<RolesPage components={{ Button }} />Theming
Inject theme CSS variables for dark mode support and consistent styling:
import { injectThemeCSS } from '@tide/ui';
// Call once at app init
injectThemeCSS();Or use the theme constants directly:
import { colors, spacing, radius, focusRing } from '@tide/ui';
const myStyle = {
color: colors.foreground.primary,
padding: spacing.md,
borderRadius: radius.lg,
};Supports prefers-color-scheme: dark and prefers-reduced-motion: reduce automatically.
Hooks
useAutoRefresh
Auto-refresh data at configurable intervals with error handling:
import { useAutoRefresh } from '@tide/ui';
const { secondsRemaining, refreshNow, lastError, failureCount, isStopped } = useAutoRefresh({
intervalSeconds: 15,
refresh: fetchData,
isBlocked: isLoading,
onError: (err) => console.error('Refresh failed:', err),
maxRetries: 3, // stops after 3 consecutive failures
});
// Show countdown or error state
{lastError && <span>Refresh failed: {lastError.message}</span>}
{secondsRemaining && <span>Refreshing in {secondsRemaining}s</span>}Accessibility
All components include proper ARIA attributes:
role="status"andaria-busyfor loading statesrole="alertdialog"witharia-modalfor confirmation dialogsaria-labelon interactive elementsprefers-reduced-motionsupport for animations
API Reference
| Adapter | Purpose |
|---------|---------|
| TemplateAPI | Store policy templates |
| PolicyAPI | Store role policies |
| PolicyLogsAPI | Log policy activity |
| PolicyApprovalsAPI | Track pending policy approvals |
| AccessMetadataAPI | Track change set metadata |
License
MIT
