@hed-hog/core 0.0.278 → 0.0.285

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.
Files changed (51) hide show
  1. package/README.md +60 -0
  2. package/dist/auth/auth.controller.d.ts +3 -3
  3. package/dist/auth/auth.service.d.ts +8 -8
  4. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +12 -0
  5. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
  6. package/dist/dashboard/dashboard-core/dashboard-core.controller.js +9 -0
  7. package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
  8. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +12 -0
  9. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
  10. package/dist/dashboard/dashboard-core/dashboard-core.service.js +25 -0
  11. package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
  12. package/dist/file/file.controller.d.ts +2 -2
  13. package/dist/file/file.service.d.ts +4 -4
  14. package/dist/role/guards/role.guard.d.ts.map +1 -1
  15. package/dist/role/guards/role.guard.js +1 -1
  16. package/dist/role/guards/role.guard.js.map +1 -1
  17. package/dist/session/session.controller.d.ts +1 -1
  18. package/dist/session/session.service.d.ts +3 -3
  19. package/dist/user/user.controller.d.ts +2 -2
  20. package/dist/user/user.service.d.ts +6 -6
  21. package/hedhog/data/dashboard_component.yaml +95 -77
  22. package/hedhog/data/dashboard_component_role.yaml +91 -79
  23. package/hedhog/data/dashboard_item.yaml +121 -101
  24. package/hedhog/data/route.yaml +8 -0
  25. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +69 -62
  26. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +23 -12
  27. package/hedhog/frontend/app/dashboard/components/draggable-grid.tsx.ejs +80 -5
  28. package/hedhog/frontend/app/dashboard/components/widgets/account-security.tsx.ejs +33 -29
  29. package/hedhog/frontend/app/dashboard/components/widgets/activity-timeline.tsx.ejs +18 -14
  30. package/hedhog/frontend/app/dashboard/components/widgets/email-notifications.tsx.ejs +39 -32
  31. package/hedhog/frontend/app/dashboard/components/widgets/login-history-chart.tsx.ejs +22 -19
  32. package/hedhog/frontend/app/dashboard/components/widgets/menus-card.tsx.ejs +58 -0
  33. package/hedhog/frontend/app/dashboard/components/widgets/routes-card.tsx.ejs +58 -0
  34. package/hedhog/frontend/app/dashboard/components/widgets/stat-access-level.tsx.ejs +18 -18
  35. package/hedhog/frontend/app/dashboard/components/widgets/stat-actions-today.tsx.ejs +18 -18
  36. package/hedhog/frontend/app/dashboard/components/widgets/stat-consecutive-days.tsx.ejs +18 -18
  37. package/hedhog/frontend/app/dashboard/components/widgets/stat-online-time.tsx.ejs +18 -18
  38. package/hedhog/frontend/app/dashboard/components/widgets/user-roles.tsx.ejs +15 -11
  39. package/hedhog/frontend/app/dashboard/components/widgets/user-sessions.tsx.ejs +39 -37
  40. package/hedhog/frontend/app/dashboard/dashboard.css.ejs +20 -4
  41. package/hedhog/frontend/app/mail/log/page.tsx.ejs +36 -47
  42. package/hedhog/frontend/app/mail/template/page.tsx.ejs +176 -126
  43. package/hedhog/frontend/app/menu/page.tsx.ejs +45 -39
  44. package/hedhog/frontend/app/roles/page.tsx.ejs +45 -46
  45. package/hedhog/frontend/app/users/page.tsx.ejs +70 -73
  46. package/hedhog/frontend/messages/en.json +15 -2
  47. package/hedhog/frontend/messages/pt.json +15 -2
  48. package/package.json +4 -4
  49. package/src/dashboard/dashboard-core/dashboard-core.controller.ts +5 -0
  50. package/src/dashboard/dashboard-core/dashboard-core.service.ts +34 -0
  51. package/src/role/guards/role.guard.ts +9 -8
@@ -68,6 +68,26 @@
68
68
  height: 2
69
69
  x_axis: 2
70
70
  y_axis: 0
71
+ - component_id:
72
+ where:
73
+ slug: menus-card
74
+ dashboard_id:
75
+ where:
76
+ slug: default
77
+ width: 2
78
+ height: 2
79
+ x_axis: 8
80
+ y_axis: 0
81
+ - component_id:
82
+ where:
83
+ slug: routes-card
84
+ dashboard_id:
85
+ where:
86
+ slug: default
87
+ width: 2
88
+ height: 2
89
+ x_axis: 10
90
+ y_axis: 0
71
91
  - component_id:
72
92
  where:
73
93
  slug: user-growth-chart
@@ -86,109 +106,109 @@
86
106
  where:
87
107
  slug: user
88
108
  width: 12
89
- height: 2
109
+ height: 3
90
110
  x_axis: 0
91
111
  y_axis: 0
92
- - component_id:
93
- where:
94
- slug: stat-online-time
95
- dashboard_id:
96
- where:
97
- slug: user
98
- width: 3
99
- height: 1
100
- x_axis: 0
101
- y_axis: 2
102
- - component_id:
103
- where:
104
- slug: stat-actions-today
105
- dashboard_id:
106
- where:
107
- slug: user
108
- width: 3
109
- height: 1
110
- x_axis: 3
111
- y_axis: 2
112
- - component_id:
113
- where:
114
- slug: stat-consecutive-days
115
- dashboard_id:
116
- where:
117
- slug: user
118
- width: 3
119
- height: 1
120
- x_axis: 6
121
- y_axis: 2
122
- - component_id:
123
- where:
124
- slug: stat-access-level
125
- dashboard_id:
126
- where:
127
- slug: user
128
- width: 3
129
- height: 1
130
- x_axis: 9
131
- y_axis: 2
132
- - component_id:
133
- where:
134
- slug: account-security
135
- dashboard_id:
136
- where:
137
- slug: user
138
- width: 5
139
- height: 5
140
- x_axis: 0
141
- y_axis: 7
142
- - component_id:
143
- where:
144
- slug: login-history-chart
145
- dashboard_id:
146
- where:
147
- slug: user
148
- width: 7
149
- height: 4
150
- x_axis: 0
151
- y_axis: 3
152
- - component_id:
153
- where:
154
- slug: email-notifications
155
- dashboard_id:
156
- where:
157
- slug: user
158
- width: 7
159
- height: 5
160
- x_axis: 5
161
- y_axis: 7
162
- - component_id:
163
- where:
164
- slug: activity-timeline
165
- dashboard_id:
166
- where:
167
- slug: user
168
- width: 5
169
- height: 3
170
- x_axis: 7
171
- y_axis: 12
172
- - component_id:
173
- where:
174
- slug: user-sessions
175
- dashboard_id:
176
- where:
177
- slug: user
178
- width: 5
179
- height: 4
180
- x_axis: 7
181
- y_axis: 3
182
- - component_id:
183
- where:
184
- slug: user-roles
185
- dashboard_id:
186
- where:
187
- slug: user
188
- width: 7
189
- height: 3
190
- x_axis: 0
191
- y_axis: 12
112
+ - component_id:
113
+ where:
114
+ slug: stat-online-time
115
+ dashboard_id:
116
+ where:
117
+ slug: user
118
+ width: 3
119
+ height: 1
120
+ x_axis: 0
121
+ y_axis: 3
122
+ - component_id:
123
+ where:
124
+ slug: stat-actions-today
125
+ dashboard_id:
126
+ where:
127
+ slug: user
128
+ width: 3
129
+ height: 1
130
+ x_axis: 3
131
+ y_axis: 3
132
+ - component_id:
133
+ where:
134
+ slug: stat-consecutive-days
135
+ dashboard_id:
136
+ where:
137
+ slug: user
138
+ width: 3
139
+ height: 1
140
+ x_axis: 6
141
+ y_axis: 3
142
+ - component_id:
143
+ where:
144
+ slug: stat-access-level
145
+ dashboard_id:
146
+ where:
147
+ slug: user
148
+ width: 3
149
+ height: 1
150
+ x_axis: 9
151
+ y_axis: 3
152
+ - component_id:
153
+ where:
154
+ slug: account-security
155
+ dashboard_id:
156
+ where:
157
+ slug: user
158
+ width: 5
159
+ height: 5
160
+ x_axis: 0
161
+ y_axis: 7
162
+ - component_id:
163
+ where:
164
+ slug: login-history-chart
165
+ dashboard_id:
166
+ where:
167
+ slug: user
168
+ width: 7
169
+ height: 4
170
+ x_axis: 0
171
+ y_axis: 3
172
+ - component_id:
173
+ where:
174
+ slug: email-notifications
175
+ dashboard_id:
176
+ where:
177
+ slug: user
178
+ width: 7
179
+ height: 5
180
+ x_axis: 5
181
+ y_axis: 7
182
+ - component_id:
183
+ where:
184
+ slug: activity-timeline
185
+ dashboard_id:
186
+ where:
187
+ slug: user
188
+ width: 5
189
+ height: 3
190
+ x_axis: 7
191
+ y_axis: 13
192
+ - component_id:
193
+ where:
194
+ slug: user-sessions
195
+ dashboard_id:
196
+ where:
197
+ slug: user
198
+ width: 5
199
+ height: 4
200
+ x_axis: 7
201
+ y_axis: 4
202
+ - component_id:
203
+ where:
204
+ slug: user-roles
205
+ dashboard_id:
206
+ where:
207
+ slug: user
208
+ width: 7
209
+ height: 3
210
+ x_axis: 0
211
+ y_axis: 13
192
212
 
193
213
  - component_id:
194
214
  where:
@@ -716,6 +716,14 @@
716
716
  role:
717
717
  - where:
718
718
  slug: admin-mail
719
+ - url: /dashboard-core/stats/overview/system
720
+ method: GET
721
+ relations:
722
+ role:
723
+ - where:
724
+ slug: admin
725
+ - where:
726
+ slug: admin-access
719
727
  - url: /dashboard-core/layout/:slug
720
728
  method: GET
721
729
  relations:
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import {
4
+ EmptyState,
4
5
  Page,
5
6
  PageHeader,
6
7
  PaginationFooter,
@@ -130,14 +131,14 @@ export default function AiAgentPage() {
130
131
 
131
132
  return response.data;
132
133
  },
133
- initialData: {
134
- data: [],
135
- total: 0,
136
- page: 1,
137
- pageSize: 10,
138
- totalPages: 1,
139
- },
140
134
  });
135
+ const agentList = data ?? {
136
+ data: [],
137
+ total: 0,
138
+ page: 1,
139
+ pageSize: 10,
140
+ totalPages: 1,
141
+ };
141
142
 
142
143
  useEffect(() => {
143
144
  if (editingAgent) {
@@ -261,68 +262,74 @@ export default function AiAgentPage() {
261
262
  placeholder={t('searchPlaceholder')}
262
263
  />
263
264
 
264
- <Card>
265
- <CardContent className="p-0">
266
- <Table>
267
- <TableHeader>
268
- <TableRow>
269
- <TableHead>Slug</TableHead>
270
- <TableHead>{t('columnProvider')}</TableHead>
271
- <TableHead>{t('columnModel')}</TableHead>
272
- <TableHead>{t('columnExternalId')}</TableHead>
273
- <TableHead className="text-right">
274
- {t('columnActions')}
275
- </TableHead>
276
- </TableRow>
277
- </TableHeader>
278
- <TableBody>
279
- {isLoading ? (
265
+ {isLoading || agentList.data.length > 0 ? (
266
+ <Card>
267
+ <CardContent className="p-0">
268
+ <Table>
269
+ <TableHeader>
280
270
  <TableRow>
281
- <TableCell colSpan={5}>{t('loading')}</TableCell>
271
+ <TableHead>Slug</TableHead>
272
+ <TableHead>{t('columnProvider')}</TableHead>
273
+ <TableHead>{t('columnModel')}</TableHead>
274
+ <TableHead>{t('columnExternalId')}</TableHead>
275
+ <TableHead className="text-right">
276
+ {t('columnActions')}
277
+ </TableHead>
282
278
  </TableRow>
283
- ) : data.data.length === 0 ? (
284
- <TableRow>
285
- <TableCell colSpan={5}>{t('empty')}</TableCell>
286
- </TableRow>
287
- ) : (
288
- data.data.map((agent) => (
289
- <TableRow key={agent.id}>
290
- <TableCell>{agent.slug}</TableCell>
291
- <TableCell className="uppercase">
292
- {agent.provider}
293
- </TableCell>
294
- <TableCell>{agent.model || '-'}</TableCell>
295
- <TableCell>{agent.external_agent_id || '-'}</TableCell>
296
- <TableCell className="text-right">
297
- <div className="flex items-center justify-end gap-2">
298
- <Button
299
- variant="outline"
300
- size="icon"
301
- onClick={() => handleOpenEdit(agent)}
302
- >
303
- <Pencil className="h-4 w-4" />
304
- </Button>
305
- <Button
306
- variant="destructive"
307
- size="icon"
308
- onClick={() => setAgentToDelete(agent)}
309
- >
310
- <Trash2 className="h-4 w-4" />
311
- </Button>
312
- </div>
313
- </TableCell>
279
+ </TableHeader>
280
+ <TableBody>
281
+ {isLoading ? (
282
+ <TableRow>
283
+ <TableCell colSpan={5}>{t('loading')}</TableCell>
314
284
  </TableRow>
315
- ))
316
- )}
317
- </TableBody>
318
- </Table>
319
- </CardContent>
320
- </Card>
285
+ ) : (
286
+ agentList.data.map((agent) => (
287
+ <TableRow key={agent.id}>
288
+ <TableCell>{agent.slug}</TableCell>
289
+ <TableCell className="uppercase">
290
+ {agent.provider}
291
+ </TableCell>
292
+ <TableCell>{agent.model || '-'}</TableCell>
293
+ <TableCell>{agent.external_agent_id || '-'}</TableCell>
294
+ <TableCell className="text-right">
295
+ <div className="flex items-center justify-end gap-2">
296
+ <Button
297
+ variant="outline"
298
+ size="icon"
299
+ onClick={() => handleOpenEdit(agent)}
300
+ >
301
+ <Pencil className="h-4 w-4" />
302
+ </Button>
303
+ <Button
304
+ variant="destructive"
305
+ size="icon"
306
+ onClick={() => setAgentToDelete(agent)}
307
+ >
308
+ <Trash2 className="h-4 w-4" />
309
+ </Button>
310
+ </div>
311
+ </TableCell>
312
+ </TableRow>
313
+ ))
314
+ )}
315
+ </TableBody>
316
+ </Table>
317
+ </CardContent>
318
+ </Card>
319
+ ) : (
320
+ <EmptyState
321
+ icon={<Bot className="h-12 w-12" />}
322
+ title={t('empty')}
323
+ description={t('description')}
324
+ actionLabel={t('newAgent')}
325
+ onAction={handleOpenCreate}
326
+ />
327
+ )}
321
328
 
322
329
  <PaginationFooter
323
330
  currentPage={page}
324
331
  pageSize={pageSize}
325
- totalItems={data.total}
332
+ totalItems={agentList.total}
326
333
  onPageChange={setPage}
327
334
  onPageSizeChange={(value) => {
328
335
  setPageSize(value);
@@ -12,6 +12,7 @@ import { Button } from '@/components/ui/button';
12
12
  import { Separator } from '@/components/ui/separator';
13
13
  import { SidebarTrigger } from '@/components/ui/sidebar';
14
14
  import { Skeleton } from '@/components/ui/skeleton';
15
+ import { useIsMobile } from '@/components/ui/use-mobile';
15
16
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
16
17
  import { IconDeviceFloppy } from '@tabler/icons-react';
17
18
  import { useTranslations } from 'next-intl';
@@ -38,6 +39,7 @@ export const DashboardContent = ({ dashboardSlug }: DashboardContentProps) => {
38
39
  const t = useTranslations('core.DashboardPage');
39
40
  const { request } = useApp();
40
41
  const router = useRouter();
42
+ const isMobile = useIsMobile();
41
43
 
42
44
  const [layout, setLayout] = useState<LayoutItem[]>([]);
43
45
  const [widgets, setWidgets] = useState<WidgetLayout[]>([]);
@@ -106,7 +108,10 @@ export const DashboardContent = ({ dashboardSlug }: DashboardContentProps) => {
106
108
  x: item.x,
107
109
  y: item.y,
108
110
  w: item.w,
109
- h: item.h,
111
+ h:
112
+ dashboardSlug === 'user' && item.slug === 'profile-card'
113
+ ? Math.max(item.h, 3)
114
+ : item.h,
110
115
  minW: item.minW || 1,
111
116
  maxW: item.maxW || 12,
112
117
  minH: item.minH || 1,
@@ -277,37 +282,42 @@ export const DashboardContent = ({ dashboardSlug }: DashboardContentProps) => {
277
282
 
278
283
  return (
279
284
  <>
280
- <header className="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
281
- <div className="flex w-full items-center justify-between gap-2 px-4">
282
- <div className="flex items-center gap-2">
285
+ <header className="flex min-h-16 shrink-0 items-center gap-2 py-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12 sm:h-16 sm:py-0">
286
+ <div className="flex w-full flex-col gap-2 px-4 sm:flex-row sm:items-center sm:justify-between">
287
+ <div className="flex min-w-0 items-center gap-2">
283
288
  <SidebarTrigger className="-ml-1" />
284
289
  <Separator
285
290
  orientation="vertical"
286
291
  className="mr-2 data-[orientation=vertical]:h-4"
287
292
  />
288
- <Breadcrumb>
293
+ <Breadcrumb className="min-w-0">
289
294
  <BreadcrumbList>
290
295
  <BreadcrumbItem className="hidden md:block">
291
296
  <BreadcrumbLink href="#">{t('dashboard')}</BreadcrumbLink>
292
297
  </BreadcrumbItem>
293
298
  <BreadcrumbSeparator className="hidden md:block" />
294
299
  <BreadcrumbItem>
295
- <BreadcrumbPage>{dashboardName}</BreadcrumbPage>
300
+ <BreadcrumbPage className="truncate">
301
+ {dashboardName}
302
+ </BreadcrumbPage>
296
303
  </BreadcrumbItem>
297
304
  </BreadcrumbList>
298
305
  </Breadcrumb>
299
306
  </div>
300
- <div className="flex items-center gap-2">
307
+ <div className="flex w-full items-center justify-end gap-2 sm:w-auto">
301
308
  {hasChanges && (
302
309
  <Button
303
310
  size="sm"
304
311
  variant="default"
305
- className="gap-2"
312
+ className="gap-1 px-2 sm:gap-2 sm:px-3"
306
313
  onClick={handleSaveLayout}
307
314
  disabled={isSaving}
315
+ aria-label={isSaving ? t('saving') : t('saveLayout')}
308
316
  >
309
317
  <IconDeviceFloppy className="size-4" />
310
- {isSaving ? t('saving') : t('saveLayout')}
318
+ <span className="hidden sm:inline">
319
+ {isSaving ? t('saving') : t('saveLayout')}
320
+ </span>
311
321
  </Button>
312
322
  )}
313
323
  <AddWidgetSelectorDialog
@@ -321,15 +331,16 @@ export const DashboardContent = ({ dashboardSlug }: DashboardContentProps) => {
321
331
  </header>
322
332
  <div className="flex flex-1 flex-col gap-4 overflow-auto p-4 pt-0">
323
333
  {widgets.length > 0 ? (
324
- <div className="min-h-[600px]">
334
+ <div className="min-h-[420px] sm:min-h-[520px] lg:min-h-[600px]">
325
335
  <DraggableGrid
326
336
  className="dashboard-grid"
327
337
  layout={layout}
328
338
  onLayoutChange={handleLayoutChange}
329
339
  cols={12}
330
340
  rowHeight={80}
331
- isDraggable={true}
332
- isResizable={true}
341
+ preventCollision
342
+ isDraggable={!isMobile}
343
+ isResizable={!isMobile}
333
344
  resizeHandles={['se']}
334
345
  >
335
346
  {widgets.map((widget) => (
@@ -36,6 +36,54 @@ interface DraggableGridProps {
36
36
  resizeHandles?: Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'>;
37
37
  }
38
38
 
39
+ const MOBILE_WIDTH = 640;
40
+ const TABLET_WIDTH = 1024;
41
+
42
+ const clamp = (value: number, min: number, max: number) =>
43
+ Math.max(min, Math.min(max, value));
44
+
45
+ const deriveResponsiveLayout = (
46
+ layout: Layout,
47
+ effectiveCols: number,
48
+ cols: number
49
+ ): Layout => {
50
+ const sorted = [...layout].sort((a, b) => a.y - b.y || a.x - b.x);
51
+ const ratio = effectiveCols / cols;
52
+
53
+ let cursorX = 0;
54
+ let cursorY = 0;
55
+ let rowHeight = 0;
56
+
57
+ return sorted.map((item) => {
58
+ const nextW =
59
+ effectiveCols === 1
60
+ ? 1
61
+ : clamp(Math.round(item.w * ratio), 1, effectiveCols);
62
+ const nextH = Math.max(1, item.h || 1);
63
+
64
+ if (cursorX + nextW > effectiveCols) {
65
+ cursorY += Math.max(1, rowHeight);
66
+ cursorX = 0;
67
+ rowHeight = 0;
68
+ }
69
+
70
+ const mappedItem: LayoutItem = {
71
+ ...item,
72
+ x: cursorX,
73
+ y: cursorY,
74
+ w: nextW,
75
+ h: nextH,
76
+ minW: clamp(Math.min(item.minW || 1, nextW), 1, nextW),
77
+ maxW: clamp(item.maxW || effectiveCols, nextW, effectiveCols),
78
+ };
79
+
80
+ cursorX += nextW;
81
+ rowHeight = Math.max(rowHeight, nextH);
82
+
83
+ return mappedItem;
84
+ });
85
+ };
86
+
39
87
  // Simple compaction function for grid layout
40
88
  const compactLayout = (
41
89
  layout: RGLLayout,
@@ -64,7 +112,7 @@ export function DraggableGrid({
64
112
  isDraggable = true,
65
113
  isResizable = true,
66
114
  compactType = 'vertical',
67
- preventCollision = false,
115
+ preventCollision = true,
68
116
  margin = [16, 16],
69
117
  containerPadding = [0, 0],
70
118
  resizeHandles = ['se'],
@@ -72,6 +120,29 @@ export function DraggableGrid({
72
120
  const containerRef = useRef<HTMLDivElement>(null);
73
121
  const [containerWidth, setContainerWidth] = useState(1200);
74
122
 
123
+ const effectiveCols =
124
+ containerWidth < MOBILE_WIDTH
125
+ ? 1
126
+ : containerWidth < TABLET_WIDTH
127
+ ? Math.min(6, cols)
128
+ : cols;
129
+
130
+ const effectiveRowHeight =
131
+ containerWidth < MOBILE_WIDTH ? Math.max(76, rowHeight - 4) : rowHeight;
132
+
133
+ const effectiveMargin: [number, number] =
134
+ containerWidth < MOBILE_WIDTH
135
+ ? [Math.min(10, margin[0]), Math.min(10, margin[1])]
136
+ : margin;
137
+
138
+ const responsiveLayout = (() => {
139
+ if (effectiveCols === cols) {
140
+ return layout;
141
+ }
142
+
143
+ return deriveResponsiveLayout(layout, effectiveCols, cols);
144
+ })();
145
+
75
146
  useEffect(() => {
76
147
  const updateWidth = () => {
77
148
  if (containerRef.current) {
@@ -91,6 +162,10 @@ export function DraggableGrid({
91
162
  }, []);
92
163
 
93
164
  const handleLayoutChange = (newLayout: RGLLayout) => {
165
+ if (effectiveCols !== cols) {
166
+ return;
167
+ }
168
+
94
169
  const layouts = Array.isArray(newLayout) ? newLayout : [newLayout];
95
170
  const convertedLayout = layouts.map((item: any) => ({
96
171
  i: item.i,
@@ -111,12 +186,12 @@ export function DraggableGrid({
111
186
  <div ref={containerRef} className="w-full">
112
187
  <GridLayout
113
188
  className={`layout ${className}`}
114
- layout={layout}
189
+ layout={responsiveLayout}
115
190
  gridConfig={{
116
- cols,
117
- rowHeight,
191
+ cols: effectiveCols,
192
+ rowHeight: effectiveRowHeight,
118
193
  containerPadding,
119
- margin,
194
+ margin: effectiveMargin,
120
195
  }}
121
196
  dragConfig={{
122
197
  enabled: isDraggable,