proje-react-panel 1.4.1 → 1.6.0-test-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules.md +11 -1
- package/.vscode/launch.json +9 -0
- package/AUTH_LAYOUT_EXAMPLE.md +343 -0
- package/AUTH_LAYOUT_GUIDE.md +819 -0
- package/IMPLEMENTATION_GUIDE.md +899 -0
- package/dist/api/ApiConfig.d.ts +11 -0
- package/dist/api/AuthApi.d.ts +2 -5
- package/dist/api/CrudApi.d.ts +11 -12
- package/dist/components/list/CellField.d.ts +2 -2
- package/dist/components/list/cells/BooleanCell.d.ts +5 -2
- package/dist/components/list/cells/DateCell.d.ts +5 -2
- package/dist/components/list/cells/DefaultCell.d.ts +3 -2
- package/dist/components/list/cells/DownloadCell.d.ts +3 -2
- package/dist/components/list/cells/ImageCell.d.ts +3 -2
- package/dist/components/list/cells/LinkCell.d.ts +8 -0
- package/dist/components/list/cells/UUIDCell.d.ts +5 -2
- package/dist/decorators/auth/DefaultLoginForm.d.ts +4 -0
- package/dist/decorators/details/Details.d.ts +1 -1
- package/dist/decorators/list/Cell.d.ts +5 -1
- package/dist/decorators/list/List.d.ts +8 -4
- package/dist/decorators/list/cells/LinkCell.d.ts +13 -0
- package/dist/index.cjs.js +15 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.esm.js +15 -1
- package/dist/types/Login.d.ts +8 -0
- package/package.json +3 -1
- package/src/api/ApiConfig.ts +63 -0
- package/src/api/AuthApi.ts +8 -0
- package/src/api/CrudApi.ts +96 -60
- package/src/assets/icons/svg/down-arrow-backup-2.svg +3 -0
- package/src/components/DetailsPage.tsx +5 -1
- package/src/components/list/CellField.tsx +25 -10
- package/src/components/list/Datagrid.tsx +83 -53
- package/src/components/list/ListPage.tsx +3 -0
- package/src/components/list/cells/BooleanCell.tsx +7 -2
- package/src/components/list/cells/DateCell.tsx +6 -2
- package/src/components/list/cells/DefaultCell.tsx +4 -4
- package/src/components/list/cells/DownloadCell.tsx +4 -2
- package/src/components/list/cells/ImageCell.tsx +5 -2
- package/src/components/list/cells/LinkCell.tsx +31 -0
- package/src/components/list/cells/UUIDCell.tsx +6 -2
- package/src/decorators/auth/DefaultLoginForm.ts +32 -0
- package/src/decorators/details/Details.ts +1 -1
- package/src/decorators/list/Cell.ts +5 -1
- package/src/decorators/list/List.ts +4 -4
- package/src/decorators/list/cells/LinkCell.ts +22 -0
- package/src/index.ts +27 -1
- package/src/services/DataService.ts +14 -10
- package/src/store/store.ts +1 -1
- package/src/styles/components/button.scss +14 -0
- package/src/styles/index.scss +1 -1
- package/src/styles/list.scss +64 -1
- package/src/types/Login.ts +9 -0
- package/src/utils/logout.ts +2 -0
package/.cursor/rules.md
CHANGED
|
@@ -40,7 +40,17 @@ export function Button({ label, onClick }: ButtonProps) {
|
|
|
40
40
|
|
|
41
41
|
Use SCSS exclusively for styling.
|
|
42
42
|
|
|
43
|
-
## 5.
|
|
43
|
+
## 5. Package Management
|
|
44
|
+
|
|
45
|
+
**ALWAYS use yarn, NEVER use npm.**
|
|
46
|
+
|
|
47
|
+
- Use `yarn add` instead of `npm install`
|
|
48
|
+
- Use `yarn remove` instead of `npm uninstall`
|
|
49
|
+
- Use `yarn` instead of `npm install` for installing dependencies
|
|
50
|
+
- Use `yarn build` instead of `npm run build`
|
|
51
|
+
- Use `yarn test` instead of `npm test`
|
|
52
|
+
|
|
53
|
+
## 6. General Rules
|
|
44
54
|
|
|
45
55
|
- Keep components focused and single-responsibility
|
|
46
56
|
- Use meaningful names
|
package/.vscode/launch.json
CHANGED
|
@@ -22,6 +22,15 @@
|
|
|
22
22
|
"cwd": "${workspaceFolder}/examples",
|
|
23
23
|
"console": "integratedTerminal",
|
|
24
24
|
"internalConsoleOptions": "neverOpen"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "node",
|
|
28
|
+
"request": "launch",
|
|
29
|
+
"name": "Start Server",
|
|
30
|
+
"runtimeExecutable": "yarn",
|
|
31
|
+
"runtimeArgs": ["start"],
|
|
32
|
+
"cwd": "/Users/hasbisefademir/WebstormProjects/proje/nestjs-react-panel-server",
|
|
33
|
+
"console": "integratedTerminal"
|
|
25
34
|
}
|
|
26
35
|
]
|
|
27
36
|
}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# AuthLayout Implementation Example
|
|
2
|
+
|
|
3
|
+
This file shows a complete working example of how to implement AuthLayout with sidebar in your React application.
|
|
4
|
+
|
|
5
|
+
> **Note**: `AuthLayout` is a **helper component** created for demonstration purposes. It is **not part of the core `proje-react-panel` library**. This example shows how to create your own AuthLayout using the library's `Layout` component.
|
|
6
|
+
|
|
7
|
+
> **Important**: The helper component uses React Router components (`Outlet`, `BrowserRouter`, `Route`, `Routes`, `Link`) and other external dependencies that are **not part of the `proje-react-panel` library**.
|
|
8
|
+
|
|
9
|
+
## File Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
src/
|
|
13
|
+
├── App.tsx # Main application component
|
|
14
|
+
├── AuthLayout.tsx # Authentication layout component
|
|
15
|
+
├── api/
|
|
16
|
+
│ └── apiConfig.ts # API configuration
|
|
17
|
+
├── pages/
|
|
18
|
+
│ └── Dashboard.tsx # Example dashboard page
|
|
19
|
+
└── types/
|
|
20
|
+
└── Login.tsx # Login form model
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Complete Implementation
|
|
24
|
+
|
|
25
|
+
### 1. App.tsx
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import React from 'react';
|
|
29
|
+
import { Login, Panel, ListPage, FormPage, DetailsPage } from 'proje-react-panel';
|
|
30
|
+
import { BrowserRouter as Router, Route, Routes } from 'react-router';
|
|
31
|
+
import { Dashboard } from './pages/Dashboard';
|
|
32
|
+
import { AuthLayout } from './AuthLayout';
|
|
33
|
+
import { initApi, initAuthToken, setAuthToken } from './api/apiConfig';
|
|
34
|
+
import { LoginForm } from './types/Login';
|
|
35
|
+
|
|
36
|
+
// Initialize API
|
|
37
|
+
initApi({
|
|
38
|
+
baseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080',
|
|
39
|
+
});
|
|
40
|
+
initAuthToken();
|
|
41
|
+
|
|
42
|
+
export function App() {
|
|
43
|
+
return (
|
|
44
|
+
<Panel
|
|
45
|
+
onInit={appData => {
|
|
46
|
+
if (appData.token) {
|
|
47
|
+
setAuthToken(appData.token);
|
|
48
|
+
}
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
<Router>
|
|
52
|
+
<Routes>
|
|
53
|
+
{/* Authenticated routes */}
|
|
54
|
+
<Route path="/" element={<AuthLayout />}>
|
|
55
|
+
<Route path={'/'} index element={<Dashboard key="dashboard" />} />
|
|
56
|
+
<Route path={'users'}>
|
|
57
|
+
<Route path={''} element={<ListPage key="user-list" model={UserList} />} />
|
|
58
|
+
<Route
|
|
59
|
+
path={'create'}
|
|
60
|
+
element={<FormPage key="user-create" model={CreateUserForm} />}
|
|
61
|
+
/>
|
|
62
|
+
<Route
|
|
63
|
+
path={'edit/:id'}
|
|
64
|
+
element={<FormPage key="user-edit" model={EditUserForm} />}
|
|
65
|
+
/>
|
|
66
|
+
<Route
|
|
67
|
+
path={':id'}
|
|
68
|
+
element={<DetailsPage key="user-details" model={UserDetails} />}
|
|
69
|
+
/>
|
|
70
|
+
</Route>
|
|
71
|
+
{/* Add more routes as needed */}
|
|
72
|
+
</Route>
|
|
73
|
+
|
|
74
|
+
{/* Public routes */}
|
|
75
|
+
<Route path="/login" element={<Login model={LoginForm} />} />
|
|
76
|
+
</Routes>
|
|
77
|
+
</Router>
|
|
78
|
+
</Panel>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. AuthLayout.tsx
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { Outlet } from 'react-router';
|
|
87
|
+
import React from 'react';
|
|
88
|
+
import { Layout, logout } from 'proje-react-panel';
|
|
89
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
90
|
+
import {
|
|
91
|
+
faDashboard,
|
|
92
|
+
faEnvelope,
|
|
93
|
+
faGlobe,
|
|
94
|
+
faImage,
|
|
95
|
+
faLanguage,
|
|
96
|
+
faMessage,
|
|
97
|
+
faUserAlt,
|
|
98
|
+
faUserCircle,
|
|
99
|
+
} from '@fortawesome/free-solid-svg-icons';
|
|
100
|
+
import { setAuthLogout } from './api/apiConfig';
|
|
101
|
+
|
|
102
|
+
export type IconType =
|
|
103
|
+
| 'dashboard'
|
|
104
|
+
| 'admin'
|
|
105
|
+
| 'user'
|
|
106
|
+
| 'message'
|
|
107
|
+
| 'thread'
|
|
108
|
+
| 'assets'
|
|
109
|
+
| 'localization'
|
|
110
|
+
| 'language';
|
|
111
|
+
|
|
112
|
+
function getIcons(iconType: IconType) {
|
|
113
|
+
switch (iconType) {
|
|
114
|
+
case 'dashboard':
|
|
115
|
+
return <FontAwesomeIcon icon={faDashboard} />;
|
|
116
|
+
case 'admin':
|
|
117
|
+
return <FontAwesomeIcon icon={faUserAlt} />;
|
|
118
|
+
case 'user':
|
|
119
|
+
return <FontAwesomeIcon icon={faUserCircle} />;
|
|
120
|
+
case 'message':
|
|
121
|
+
return <FontAwesomeIcon icon={faEnvelope} />;
|
|
122
|
+
case 'thread':
|
|
123
|
+
return <FontAwesomeIcon icon={faMessage} />;
|
|
124
|
+
case 'assets':
|
|
125
|
+
return <FontAwesomeIcon icon={faImage} />;
|
|
126
|
+
case 'localization':
|
|
127
|
+
return <FontAwesomeIcon icon={faLanguage} />;
|
|
128
|
+
case 'language':
|
|
129
|
+
return <FontAwesomeIcon icon={faGlobe} />;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getMenu(): {
|
|
134
|
+
name: string;
|
|
135
|
+
path: string;
|
|
136
|
+
iconType: IconType;
|
|
137
|
+
}[] {
|
|
138
|
+
return [
|
|
139
|
+
{ name: 'Dashboard', path: '/', iconType: 'dashboard' },
|
|
140
|
+
{ name: 'Admins', path: '/admins', iconType: 'admin' },
|
|
141
|
+
{ name: 'Users', path: 'users', iconType: 'user' },
|
|
142
|
+
{ name: 'Threads', path: 'threads', iconType: 'thread' },
|
|
143
|
+
{ name: 'Messages', path: 'messages', iconType: 'message' },
|
|
144
|
+
{ name: 'Assets', path: 'assets', iconType: 'assets' },
|
|
145
|
+
{ name: 'Localization', path: 'localization?language=tr', iconType: 'localization' },
|
|
146
|
+
{ name: 'Languages', path: 'languages', iconType: 'language' },
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function AuthLayout() {
|
|
151
|
+
return (
|
|
152
|
+
<Layout
|
|
153
|
+
logout={() => {
|
|
154
|
+
setAuthLogout();
|
|
155
|
+
logout(() => {
|
|
156
|
+
window.location.href = '/login';
|
|
157
|
+
});
|
|
158
|
+
}}
|
|
159
|
+
getIcons={getIcons}
|
|
160
|
+
menu={getMenu}
|
|
161
|
+
>
|
|
162
|
+
<Outlet />
|
|
163
|
+
</Layout>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 3. api/apiConfig.ts
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import axios, { AxiosInstance } from 'axios';
|
|
172
|
+
|
|
173
|
+
let axiosInstance: AxiosInstance;
|
|
174
|
+
|
|
175
|
+
export function initApi(config: { baseUrl: string }) {
|
|
176
|
+
axiosInstance = axios.create({
|
|
177
|
+
baseURL: config.baseUrl,
|
|
178
|
+
headers: {
|
|
179
|
+
'Content-Type': 'application/json',
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Handle 401 responses automatically
|
|
184
|
+
axiosInstance.interceptors.response.use(
|
|
185
|
+
response => response,
|
|
186
|
+
error => {
|
|
187
|
+
if (error.response && error.response.status === 401) {
|
|
188
|
+
setAuthLogout();
|
|
189
|
+
window.location.href = '/login';
|
|
190
|
+
}
|
|
191
|
+
return Promise.reject(error);
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function initAuthToken(): void {
|
|
197
|
+
if (!axiosInstance) {
|
|
198
|
+
throw new Error('API not initialized. Call initApi first.');
|
|
199
|
+
}
|
|
200
|
+
const token = localStorage.getItem('token');
|
|
201
|
+
if (token) {
|
|
202
|
+
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function setAuthToken(token: string): void {
|
|
207
|
+
if (!axiosInstance) {
|
|
208
|
+
throw new Error('API not initialized. Call initApi first.');
|
|
209
|
+
}
|
|
210
|
+
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
|
211
|
+
localStorage.setItem('token', token);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function setAuthLogout(): void {
|
|
215
|
+
if (!axiosInstance) {
|
|
216
|
+
throw new Error('API not initialized. Call initApi first.');
|
|
217
|
+
}
|
|
218
|
+
axiosInstance.defaults.headers.common['Authorization'] = null;
|
|
219
|
+
localStorage.removeItem('token');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function getAxiosInstance(): AxiosInstance {
|
|
223
|
+
if (!axiosInstance) {
|
|
224
|
+
throw new Error('API not initialized. Call initApi first.');
|
|
225
|
+
}
|
|
226
|
+
return axiosInstance;
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 4. pages/Dashboard.tsx
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
import React from 'react';
|
|
234
|
+
|
|
235
|
+
export function Dashboard() {
|
|
236
|
+
return (
|
|
237
|
+
<div>
|
|
238
|
+
<h1>Dashboard</h1>
|
|
239
|
+
<p>Welcome to your dashboard!</p>
|
|
240
|
+
</div>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 5. types/Login.tsx
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
import { Form } from 'proje-react-panel';
|
|
249
|
+
|
|
250
|
+
export const LoginForm = Form({
|
|
251
|
+
title: 'Login',
|
|
252
|
+
fields: [
|
|
253
|
+
{
|
|
254
|
+
name: 'email',
|
|
255
|
+
type: 'email',
|
|
256
|
+
label: 'Email',
|
|
257
|
+
required: true,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: 'password',
|
|
261
|
+
type: 'password',
|
|
262
|
+
label: 'Password',
|
|
263
|
+
required: true,
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
submitText: 'Login',
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Package.json Dependencies
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"dependencies": {
|
|
275
|
+
"proje-react-panel": "^latest",
|
|
276
|
+
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
|
277
|
+
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
|
278
|
+
"@fortawesome/react-fontawesome": "^0.2.0",
|
|
279
|
+
"react-router": "^6.8.0",
|
|
280
|
+
"axios": "^1.3.0",
|
|
281
|
+
"react": "^18.0.0",
|
|
282
|
+
"react-dom": "^18.0.0"
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
> **Important**: Use `react-router` (not `react-router-dom`) for all routing components.
|
|
288
|
+
|
|
289
|
+
## Environment Variables
|
|
290
|
+
|
|
291
|
+
Create a `.env` file in your project root:
|
|
292
|
+
|
|
293
|
+
```env
|
|
294
|
+
VITE_API_BASE_URL=http://localhost:8080
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Usage
|
|
298
|
+
|
|
299
|
+
1. Install dependencies: `npm install`
|
|
300
|
+
2. Start your development server: `npm run dev`
|
|
301
|
+
3. Navigate to `http://localhost:3000`
|
|
302
|
+
4. The app will redirect to `/login` if not authenticated
|
|
303
|
+
5. After login, you'll see the sidebar with navigation
|
|
304
|
+
|
|
305
|
+
## Features Demonstrated
|
|
306
|
+
|
|
307
|
+
- ✅ Authentication flow with automatic redirects
|
|
308
|
+
- ✅ Automatic redirect to login for unauthenticated users
|
|
309
|
+
- ✅ Collapsible sidebar with toggle button
|
|
310
|
+
- ✅ Active route highlighting
|
|
311
|
+
- ✅ Icon support with FontAwesome
|
|
312
|
+
- ✅ Logout functionality
|
|
313
|
+
- ✅ Responsive design
|
|
314
|
+
- ✅ API integration with token management
|
|
315
|
+
- ✅ Proper React key props for route components
|
|
316
|
+
|
|
317
|
+
## Important Notes
|
|
318
|
+
|
|
319
|
+
- **AuthLayout is a helper component**: This component is created specifically for this example and is not part of the `proje-react-panel` library
|
|
320
|
+
- **Core library component**: The `Layout` component from `proje-react-panel` is the actual library component that provides the sidebar functionality
|
|
321
|
+
- **External dependencies**: The helper component uses React Router (`Outlet`, `BrowserRouter`, `Route`, `Routes`, `Link`), FontAwesome, and Axios - these are not part of the core library
|
|
322
|
+
- **Use react-router**: Always use `react-router` (not `react-router-dom`) for all routing components
|
|
323
|
+
- **Automatic authentication**: The `Layout` component automatically redirects unauthenticated users to `/login`
|
|
324
|
+
- **Custom implementation**: You'll need to create your own AuthLayout component following this pattern
|
|
325
|
+
- **Flexible design**: You can customize the AuthLayout component to match your application's specific needs
|
|
326
|
+
|
|
327
|
+
### What's from the Library vs External Dependencies
|
|
328
|
+
|
|
329
|
+
**From `proje-react-panel` library:**
|
|
330
|
+
|
|
331
|
+
- `Layout` - Main layout with sidebar
|
|
332
|
+
- `Panel` - Application wrapper
|
|
333
|
+
- `Login`, `ListPage`, `FormPage`, `DetailsPage` - UI components
|
|
334
|
+
- `logout` - Utility function
|
|
335
|
+
|
|
336
|
+
**External dependencies (not from library):**
|
|
337
|
+
|
|
338
|
+
- `react-router` - Routing components
|
|
339
|
+
- `@fortawesome/*` - Icons
|
|
340
|
+
- `axios` - HTTP client
|
|
341
|
+
- `react` - React framework
|
|
342
|
+
|
|
343
|
+
This example provides a complete working implementation that you can use as a starting point for your own application.
|