
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@diagramers/admin
Advanced tools
A comprehensive React-based admin dashboard template with modern UI/UX, extensive customization options, and full integration with the Diagramers ecosystem. Built with React 18, TypeScript, and a modular architecture for rapid development of professional admin interfaces.
# Install CLI globally
npm install -g @diagramers/cli
# Create new admin project
diagramers init admin my-admin-dashboard
# Navigate to project
cd my-admin-dashboard
# Install dependencies
npm install --legacy-peer-deps
# Start development server
npm start
# Install package
npm install @diagramers/admin
# Initialize project
npx diagramers-admin-init my-admin-dashboard
# Navigate to project
cd my-admin-dashboard
# Install dependencies
npm install --legacy-peer-deps
# Start development server
npm start
# Create new admin project
diagramers init admin my-admin-dashboard
# Navigate to project
cd my-admin-dashboard
# Configure environment variables
cp .env.example .env
# Edit .env with your API URL and configuration
# Install dependencies
npm install --legacy-peer-deps
# Start development server
npm start
# Update API configuration in src/config.js
export const SERVICE_URL = 'http://localhost:3000';
export const REACT_HELMET_PROPS = {
defaultTitle: 'My Admin Dashboard',
titleTemplate: '%s | My Admin Dashboard',
};
# Replace logo in public/img/logo/
# Update favicon in public/img/favicon/
# Customize theme in src/sass/themes/
# Modify navigation in src/layout/nav/
# Start development server
npm start
# Build for production
npm run build
# Run tests
npm test
# Lint code
npm run lint
# API Configuration
REACT_APP_API_URL=http://localhost:3000
REACT_APP_PROJECT_NAME=My Admin Dashboard
# Authentication
REACT_APP_JWT_SECRET=your-jwt-secret
REACT_APP_AUTH_PROVIDER=internal
# Features
REACT_APP_ENABLE_ANALYTICS=true
REACT_APP_ENABLE_NOTIFICATIONS=true
REACT_APP_ENABLE_REAL_TIME=true
# External Services
REACT_APP_SOCKET_URL=ws://localhost:3000
REACT_APP_SENTRY_DSN=your-sentry-dsn
// src/config.js
export const SERVICE_URL = process.env.REACT_APP_API_URL || 'http://localhost:3000';
export const REACT_HELMET_PROPS = {
defaultTitle: process.env.REACT_APP_PROJECT_NAME || 'Admin Dashboard',
titleTemplate: `%s | ${process.env.REACT_APP_PROJECT_NAME || 'Admin Dashboard'}`,
};
// src/sass/themes/_custom.scss
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
--success-color: #28a745;
--danger-color: #dc3545;
--warning-color: #ffc107;
--info-color: #17a2b8;
--light-color: #f8f9fa;
--dark-color: #343a40;
}
import { Layout, Sidebar, Header, Footer } from '@diagramers/admin';
// Main layout
<Layout>
<Sidebar />
<div className="main-content">
<Header />
<main>{children}</main>
<Footer />
</div>
</Layout>
import { DataTable, DataGrid, DataChart } from '@diagramers/admin';
// Data table with sorting and filtering
<DataTable
data={products}
columns={productColumns}
sortable
filterable
pagination
/>
// Interactive chart
<DataChart
type="line"
data={chartData}
options={chartOptions}
/>
import { Form, Input, Select, Button } from '@diagramers/admin';
// Dynamic form
<Form onSubmit={handleSubmit}>
<Input name="name" label="Name" required />
<Select name="category" label="Category" options={categories} />
<Button type="submit">Save</Button>
</Form>
import { Navigation, Menu, Breadcrumb } from '@diagramers/admin';
// Sidebar navigation
<Navigation>
<Menu items={menuItems} />
</Navigation>
// Breadcrumb navigation
<Breadcrumb items={breadcrumbItems} />
import { LoginForm } from '@diagramers/admin';
<LoginForm
onLogin={handleLogin}
providers={['internal', 'google', 'github']}
rememberMe
forgotPassword
/>
import { ProtectedRoute, useAuth } from '@diagramers/admin';
// Protected route component
<ProtectedRoute
path="/dashboard"
component={Dashboard}
roles={['admin', 'user']}
permissions={['read:dashboard']}
/>
// Use auth hook
const { user, isAuthenticated, login, logout } = useAuth();
import { usePermissions } from '@diagramers/admin';
const { hasPermission, hasRole } = usePermissions();
// Check permissions
{hasPermission('create:users') && (
<Button onClick={createUser}>Create User</Button>
)}
// Check roles
{hasRole('admin') && (
<AdminPanel />
)}
import { AnalyticsDashboard } from '@diagramers/admin';
<AnalyticsDashboard
metrics={[
{ title: 'Total Users', value: 1250, change: '+12%' },
{ title: 'Revenue', value: '$45,230', change: '+8%' },
{ title: 'Orders', value: 89, change: '+5%' },
]}
charts={[
{ type: 'line', data: revenueData, title: 'Revenue Trend' },
{ type: 'bar', data: userData, title: 'User Growth' },
]}
/>
import { DataManager } from '@diagramers/admin';
<DataManager
endpoint="/api/users"
columns={userColumns}
actions={['create', 'edit', 'delete', 'export']}
filters={['search', 'role', 'status']}
bulkActions={['activate', 'deactivate', 'delete']}
/>
import { useWebSocket } from '@diagramers/admin';
const { data, isConnected } = useWebSocket('/api/notifications');
// Real-time notifications
{data.map(notification => (
<Notification key={notification.id} {...notification} />
))}
// src/sass/themes/_custom.scss
:root {
// Primary colors
--primary-color: #007bff;
--primary-hover: #0056b3;
--primary-light: #e3f2fd;
// Secondary colors
--secondary-color: #6c757d;
--secondary-hover: #545b62;
// Success colors
--success-color: #28a745;
--success-hover: #1e7e34;
// Danger colors
--danger-color: #dc3545;
--danger-hover: #c82333;
// Typography
--font-family: 'Inter', sans-serif;
--font-size-base: 1rem;
--line-height-base: 1.5;
// Spacing
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 3rem;
}
// src/sass/components/_custom.scss
.custom-button {
background: var(--primary-color);
border: none;
border-radius: 8px;
padding: 12px 24px;
font-weight: 600;
transition: all 0.2s ease;
&:hover {
background: var(--primary-hover);
transform: translateY(-1px);
}
}
.custom-card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 24px;
margin-bottom: 24px;
}
// src/layout/Layout.js
import { Layout, Sidebar, Header } from '@diagramers/admin';
const CustomLayout = ({ children }) => (
<Layout className="custom-layout">
<Sidebar
className="custom-sidebar"
logo="/img/logo/custom-logo.svg"
menuItems={customMenuItems}
/>
<div className="main-content">
<Header
className="custom-header"
userMenu={customUserMenu}
notifications={customNotifications}
/>
<main className="content-area">
{children}
</main>
</div>
</Layout>
);
// src/services/api.js
import { ApiService } from '@diagramers/admin';
const api = new ApiService({
baseURL: process.env.REACT_APP_API_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// Add request interceptor for authentication
api.interceptors.request.use((config) => {
const token = localStorage.getItem('auth_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Add response interceptor for error handling
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Handle unauthorized access
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default api;
import { useApi } from '@diagramers/admin';
const { data, loading, error, refetch } = useApi('/api/users');
// With parameters
const { data: users } = useApi('/api/users', {
params: { page: 1, limit: 10, search: 'john' }
});
// With mutations
const { mutate, isLoading } = useApi('/api/users', {
method: 'POST',
onSuccess: () => {
// Handle success
},
onError: (error) => {
// Handle error
},
});
import { useWebSocket } from '@diagramers/admin';
const { data, isConnected, send } = useWebSocket('/api/notifications', {
onMessage: (message) => {
// Handle incoming messages
console.log('Received:', message);
},
onConnect: () => {
console.log('Connected to WebSocket');
},
onDisconnect: () => {
console.log('Disconnected from WebSocket');
},
});
// Send message
send({ type: 'notification', data: { message: 'Hello!' } });
// src/sass/layout/_responsive.scss
.container {
width: 100%;
padding: 0 16px;
margin: 0 auto;
@media (min-width: 576px) {
max-width: 540px;
}
@media (min-width: 768px) {
max-width: 720px;
}
@media (min-width: 992px) {
max-width: 960px;
}
@media (min-width: 1200px) {
max-width: 1140px;
}
}
.sidebar {
@media (max-width: 768px) {
transform: translateX(-100%);
position: fixed;
z-index: 1000;
&.open {
transform: translateX(0);
}
}
}
import { TouchableButton, SwipeableCard } from '@diagramers/admin';
// Touch-friendly button
<TouchableButton
size="large"
onPress={handlePress}
feedback="haptic"
>
Press Me
</TouchableButton>
// Swipeable card
<SwipeableCard
onSwipeLeft={() => handleDelete()}
onSwipeRight={() => handleEdit()}
>
<CardContent />
</SwipeableCard>
import { render, screen, fireEvent } from '@testing-library/react';
import { LoginForm } from '@diagramers/admin';
test('login form submits with correct data', () => {
const mockOnLogin = jest.fn();
render(<LoginForm onLogin={mockOnLogin} />);
fireEvent.change(screen.getByLabelText('Email'), {
target: { value: 'test@example.com' },
});
fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'password123' },
});
fireEvent.click(screen.getByRole('button', { name: /login/i }));
expect(mockOnLogin).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123',
});
});
import { render, screen, waitFor } from '@testing-library/react';
import { DataTable } from '@diagramers/admin';
test('data table loads and displays data', async () => {
const mockData = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' },
];
render(<DataTable data={mockData} />);
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
});
// webpack.config.js
module.exports = {
mode: 'production',
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js',
},
};
# Development build
npm run build:dev
# Staging build
npm run build:staging
# Production build
npm run build:prod
# Analyze bundle
npm run build:analyze
# Dockerfile
FROM node:18-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build:prod
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
import { lazy, Suspense } from 'react';
// Lazy load components
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Users = lazy(() => import('./pages/Users'));
const Settings = lazy(() => import('./pages/Settings'));
// Suspense wrapper
<Suspense fallback={<LoadingSpinner />}>
<Dashboard />
</Suspense>
import { useMemo, useCallback } from 'react';
// Memoize expensive calculations
const expensiveValue = useMemo(() => {
return data.reduce((sum, item) => sum + item.value, 0);
}, [data]);
// Memoize callbacks
const handleClick = useCallback((id) => {
// Handle click
}, []);
import { OptimizedImage } from '@diagramers/admin';
<OptimizedImage
src="/img/avatar.jpg"
alt="User Avatar"
width={100}
height={100}
lazy
placeholder="/img/avatar-placeholder.jpg"
/>
// public/index.html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta http-equiv="X-Frame-Options" content="DENY">
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
import { useForm } from '@diagramers/admin';
const { register, handleSubmit, errors } = useForm();
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
})}
/>
{errors.email && <span>{errors.email.message}</span>}
</form>
import { sanitizeHtml } from '@diagramers/admin';
// Sanitize user input
const sanitizedContent = sanitizeHtml(userInput);
// Safe rendering
<div dangerouslySetInnerHTML={{ __html: sanitizedContent }} />
/**
* @component DataTable
* @description A responsive data table with sorting, filtering, and pagination
* @example
* ```jsx
* <DataTable
* data={users}
* columns={userColumns}
* sortable
* filterable
* pagination
* />
* ```
*/
/**
* @api {get} /api/users Get users
* @apiName GetUsers
* @apiGroup Users
* @apiParam {Number} page Page number
* @apiParam {Number} limit Items per page
* @apiParam {String} search Search query
* @apiSuccess {Object[]} users List of users
* @apiSuccess {String} users.id User ID
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.email User email
*/
# Clone repository
git clone https://github.com/diagramers/diagramers-admin.git
cd diagramers-admin
# Install dependencies
npm install
# Start development server
npm start
# Run tests
npm test
# Build project
npm run build
# Run linting
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Type checking
npm run type-check
# Run unit tests
npm run test:unit
# Run integration tests
npm run test:integration
# Run e2e tests
npm run test:e2e
# Generate coverage report
npm run test:coverage
MIT License - see LICENSE file for details
For support and questions:
FAQs
Diagramers Admin Template - React starter for admin dashboards.
We found that @diagramers/admin demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last weekβs supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.