vendure-admin-ui-reviewing
Vendure Admin UI Reviewing
Purpose
Audit Vendure Admin UI extensions for violations and anti-patterns.
Review Workflow
Step 1: Identify UI Files
# Find UI extension files
find . -path "*/ui/*.ts" -o -path "*/ui/*.tsx"
# Find component files
find . -name "*.tsx" -path "*/components/*"
# Find hook files
find . -name "use*.ts" -path "*/hooks/*"
Step 2: Run Automated Checks
# === CRITICAL VIOLATIONS ===
# Direct fetch calls (should use Vendure hooks)
grep -rn "fetch(" --include="*.tsx" --include="*.ts" | grep -v "node_modules"
# Missing useInjector for services
grep -rn "NotificationService" --include="*.tsx" | grep -v "useInjector"
# Angular patterns in React code
grep -rn "@Component\|@Injectable\|ngOnInit" --include="*.tsx"
# Missing page metadata
grep -rn "export function.*List\|export function.*Detail" --include="*.tsx" -A 20 | grep -v "usePageMetadata"
# === HIGH PRIORITY ===
# Missing loading states
grep -rn "useQuery" --include="*.tsx" -A 10 | grep -v "loading"
# Missing error states
grep -rn "useQuery" --include="*.tsx" -A 10 | grep -v "error"
# Direct state mutation
grep -rn "\.push(\|\.splice(\|\.pop(" --include="*.tsx"
# Missing useCallback/useMemo
grep -rn "onClick.*=.*async" --include="*.tsx" | grep -v "useCallback"
# === MEDIUM PRIORITY ===
# Inline styles (should use CSS variables)
grep -rn 'style={{' --include="*.tsx"
# Missing TypeScript types on GraphQL queries
grep -rn "useQuery(" --include="*.tsx" | grep -v "useQuery<"
# Console.log statements
grep -rn "console.log\|console.error" --include="*.tsx" --include="*.ts"
Step 3: Manual Review Checklist
Extension Structure
- index.ts exports AdminUiExtension
- routes.ts uses registerReactRouteComponent
- providers.ts uses addNavMenuSection
- Translations file exists if needed
- GraphQL codegen configured
Components
- usePageMetadata for title/breadcrumbs
- useInjector(NotificationService) for notifications
- Loading state handled
- Error state handled
- useCallback for event handlers
- useMemo for expensive computations
GraphQL Integration
- Queries in separate files
- TypeScript types from codegen
- Proper refetch after mutations
- Error handling on mutations
Styling
- CSS variables for colors/spacing
- Responsive design considered
- No hardcoded pixel values
- Theme consistency with Vendure
Severity Classification
CRITICAL (Must Fix)
- Direct fetch calls bypassing Vendure hooks
- Angular patterns in React code
- Missing error handling
- No loading states
HIGH (Should Fix)
- Missing usePageMetadata
- Missing useInjector for services
- Direct state mutation
- Inline styles
- Missing TypeScript types
MEDIUM (Should Fix)
- Missing useCallback/useMemo
- Console statements
- Hardcoded strings (no translations)
- Missing accessibility attributes
Common Violations
1. Missing Loading State
Violation:
export function ItemList() {
const { data } = useQuery(GET_ITEMS);
return (
<table>
{data?.items.map(item => (
<tr key={item.id}>{item.name}</tr>
))}
</table>
);
}
Fix:
export function ItemList() {
const { data, loading, error } = useQuery(GET_ITEMS);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<table>
{data?.items.map(item => (
<tr key={item.id}>{item.name}</tr>
))}
</table>
);
}
2. Missing useInjector
Violation:
// Directly importing and using service
import { NotificationService } from "@vendure/admin-ui/core";
export function ItemForm() {
const handleSave = async () => {
NotificationService.success("Saved!"); // WRONG
};
}
Fix:
import { NotificationService } from "@vendure/admin-ui/core";
import { useInjector } from "@vendure/admin-ui/react";
export function ItemForm() {
const notificationService = useInjector(NotificationService);
const handleSave = async () => {
notificationService.success("Saved!"); // CORRECT
};
}
3. Missing Page Metadata
Violation:
export function ItemDetail() {
// No page metadata!
return (
<div>
<h1>Item Details</h1>
{/* content */}
</div>
);
}
Fix:
export function ItemDetail() {
const { setTitle, setBreadcrumb } = usePageMetadata();
React.useEffect(() => {
setTitle('Item Details');
setBreadcrumb([
{ label: 'Items', link: ['/extensions/my-plugin/items'] },
{ label: 'Details', link: [] }
]);
}, [setTitle, setBreadcrumb]);
return (
<PageBlock>
{/* content */}
</PageBlock>
);
}
4. Direct State Mutation
Violation:
const [items, setItems] = React.useState<Item[]>([]);
const addItem = (item: Item) => {
items.push(item); // WRONG - mutating state
setItems(items);
};
Fix:
const [items, setItems] = React.useState<Item[]>([]);
const addItem = React.useCallback((item: Item) => {
setItems((prev) => [...prev, item]); // CORRECT - new array
}, []);
5. Missing TypeScript Types on Query
Violation:
const { data } = useQuery(GET_ITEMS); // No type!
// data is 'any'
Fix:
const { data } = useQuery<GetItemsQuery>(GET_ITEMS);
// data is properly typed
6. Missing useCallback on Event Handlers
Violation:
export function ItemList() {
const handleDelete = async (id: string) => {
// Creates new function on every render
};
return items.map(item => (
<button onClick={() => handleDelete(item.id)}>Delete</button>
));
}
Fix:
export function ItemList() {
const handleDelete = React.useCallback(async (id: string) => {
// Memoized function
}, [/* dependencies */]);
return items.map(item => (
<button onClick={() => handleDelete(item.id)}>Delete</button>
));
}
Quick Detection Commands
# All-in-one UI audit
echo "=== CRITICAL: Direct fetch calls ===" && \
grep -rn "fetch(" --include="*.tsx" | grep -v "node_modules" | head -10 && \
echo "" && \
echo "=== HIGH: Missing loading states ===" && \
grep -rn "useQuery" --include="*.tsx" -l | xargs -I{} sh -c 'grep -L "loading" {} 2>/dev/null' | head -10 && \
echo "" && \
echo "=== MEDIUM: Missing TypeScript types ===" && \
grep -rn "useQuery(" --include="*.tsx" | grep -v "useQuery<" | head -10
Review Output Template
## Admin UI Review: [Component/Feature Name]
### Summary
[Overview of UI quality]
### Critical Issues (Must Fix)
- [ ] [Issue] - `file:line`
### High Priority
- [ ] [Issue] - `file:line`
### Passed Checks
- [x] Extension structure correct
- [x] Routes properly registered
- [x] Navigation items configured
- [x] Loading states handled
### Recommendations
- [Suggestions]
Extension Structure Checklist
## Extension Structure Review
### Required Files
- [ ] ui/index.ts - AdminUiExtension export
- [ ] ui/routes.ts - registerReactRouteComponent
- [ ] ui/providers.ts - addNavMenuSection
### GraphQL Setup
- [ ] ui/graphql/queries.ts - Query definitions
- [ ] ui/graphql/mutations.ts - Mutation definitions
- [ ] ui/gql/graphql.ts - Generated types
- [ ] ui/codegen.yml - Codegen configuration
### Component Organization
- [ ] components/ - React components
- [ ] hooks/ - Custom hooks
- [ ] styles/ - CSS files
- [ ] translations/ - i18n files
Cross-Reference
All rules match patterns in vendure-admin-ui-writing skill.
Related Skills
- vendure-admin-ui-writing - UI patterns
- vendure-plugin-reviewing - Plugin-level review
- vendure-graphql-reviewing - GraphQL review
More from meriley/claude-code-skills
obs-cpp-qt-patterns
C++ and Qt integration patterns for OBS Studio plugins. Covers Qt6 Widgets for settings dialogs, CMAKE_AUTOMOC, OBS frontend API, optional Qt builds with C fallbacks, and modal dialog patterns. Use when adding UI components or C++ features to OBS plugins.
54vendure-developing
Develop Vendure e-commerce plugins, extend GraphQL APIs, create Admin UI components, and define database entities. Use vendure-expert agent for comprehensive guidance across all Vendure development domains.
35vendure-admin-ui-writing
Create Vendure Admin UI extensions with React components, route registration, navigation menus, and GraphQL integration. Handles useQuery, useMutation, useInjector patterns. Use when building Admin UI features for Vendure plugins.
32vendure-entity-writing
Define Vendure database entities extending VendureEntity, with TypeORM decorators, relations, custom fields, and channel-awareness. Use when creating database models in Vendure.
30vendure-graphql-writing
Extend Vendure GraphQL schema with custom types, queries, mutations, and resolvers. Handles RequestContext threading, permissions, and dual Shop/Admin API separation. Use when adding GraphQL endpoints to Vendure.
30vendure-plugin-writing
Create production-ready Vendure plugins with @VendurePlugin decorator, NestJS dependency injection, lifecycle hooks, and configuration patterns. Use when developing new Vendure plugins or extending existing ones.
28