@hed-hog/core 0.0.298 → 0.0.299
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/dist/dashboard/dashboard/dashboard.controller.d.ts +3 -0
- package/dist/dashboard/dashboard/dashboard.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard/dashboard.service.d.ts +3 -0
- package/dist/dashboard/dashboard/dashboard.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +12 -0
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js +22 -0
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +15 -0
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.js +110 -3
- package/dist/dashboard/dashboard-component/dashboard-component.service.js.map +1 -1
- package/dist/dashboard/dashboard-component/dto/create.dto.d.ts +1 -0
- package/dist/dashboard/dashboard-component/dto/create.dto.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dto/create.dto.js +5 -0
- package/dist/dashboard/dashboard-component/dto/create.dto.js.map +1 -1
- package/dist/dashboard/dashboard-component/dto/update.dto.d.ts +1 -0
- package/dist/dashboard/dashboard-component/dto/update.dto.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dto/update.dto.js +5 -0
- package/dist/dashboard/dashboard-component/dto/update.dto.js.map +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +1 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +1 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +7 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +7 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +88 -4
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +1 -0
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +1 -0
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
- package/hedhog/data/dashboard_item.yaml +1 -1
- package/hedhog/data/route.yaml +12 -0
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +141 -24
- package/hedhog/frontend/app/dashboard/[slug]/types.ts.ejs +3 -0
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +136 -23
- package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +266 -85
- package/hedhog/frontend/app/dashboard/components/widgets/core..gitkeep.ejs +11 -0
- package/hedhog/frontend/app/dashboard/components/widgets/core.account-security.tsx.ejs +192 -0
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-sessions.tsx.ejs +236 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.alerts.tsx.ejs +108 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-balance-kpi.tsx.ejs +66 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-flow-chart.tsx.ejs +122 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.default-kpi.tsx.ejs +63 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.payable-30d-kpi.tsx.ejs +73 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.receivable-30d-kpi.tsx.ejs +73 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-payable.tsx.ejs +123 -0
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-receivable.tsx.ejs +118 -0
- package/hedhog/frontend/messages/en.json +3 -0
- package/hedhog/frontend/messages/pt.json +3 -0
- package/hedhog/frontend/public/dashboard-previews/.gitkeep +12 -0
- package/hedhog/frontend/public/dashboard-previews/account-security.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/active-users-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/activity-timeline.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/cash-balance-kpi.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/cash-flow-chart.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/default-kpi.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/email-notifications.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/financial-alerts.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/login-history-chart.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/mail-sent-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/mail-sent-chart.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/menus-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/payable-30d-kpi.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/permissions-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/permissions-chart.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/profile-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/receivable-30d-kpi.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/routes-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/session-activity-chart.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/sessions-today-card.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/stat-access-level.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/stat-actions-today.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/stat-consecutive-days.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/stat-online-time.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/upcoming-payable.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/upcoming-receivable.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/user-growth-chart.png +0 -0
- package/hedhog/frontend/public/dashboard-previews/user-roles.png +0 -0
- package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/account-security.tsx.ejs +33 -29
- package/hedhog/frontend/widgets/active-users-card.tsx.ejs +58 -0
- package/hedhog/frontend/widgets/activity-timeline.tsx.ejs +223 -0
- package/hedhog/frontend/widgets/email-notifications.tsx.ejs +226 -0
- package/hedhog/frontend/widgets/locale-config.tsx.ejs +168 -0
- package/hedhog/frontend/widgets/login-history-chart.tsx.ejs +115 -0
- package/hedhog/frontend/widgets/mail-config.tsx.ejs +199 -0
- package/hedhog/frontend/widgets/mail-sent-card.tsx.ejs +58 -0
- package/hedhog/frontend/widgets/mail-sent-chart.tsx.ejs +149 -0
- package/hedhog/frontend/widgets/menus-card.tsx.ejs +58 -0
- package/hedhog/frontend/widgets/oauth-config.tsx.ejs +175 -0
- package/hedhog/frontend/widgets/permissions-card.tsx.ejs +61 -0
- package/hedhog/frontend/widgets/permissions-chart.tsx.ejs +156 -0
- package/hedhog/frontend/widgets/profile-card.tsx.ejs +186 -0
- package/hedhog/frontend/widgets/routes-card.tsx.ejs +58 -0
- package/hedhog/frontend/widgets/session-activity-chart.tsx.ejs +183 -0
- package/hedhog/frontend/widgets/sessions-today-card.tsx.ejs +62 -0
- package/hedhog/frontend/widgets/stat-access-level.tsx.ejs +57 -0
- package/hedhog/frontend/widgets/stat-actions-today.tsx.ejs +57 -0
- package/hedhog/frontend/widgets/stat-consecutive-days.tsx.ejs +57 -0
- package/hedhog/frontend/widgets/stat-online-time.tsx.ejs +57 -0
- package/hedhog/frontend/widgets/storage-config.tsx.ejs +196 -0
- package/hedhog/frontend/widgets/theme-config.tsx.ejs +213 -0
- package/hedhog/frontend/widgets/user-growth-chart.tsx.ejs +210 -0
- package/hedhog/frontend/widgets/user-roles.tsx.ejs +132 -0
- package/hedhog/frontend/{app/dashboard/components/widgets → widgets}/user-sessions.tsx.ejs +1 -1
- package/hedhog/table/dashboard_component.yaml +7 -0
- package/package.json +4 -4
- package/src/dashboard/dashboard-component/dashboard-component.controller.ts +36 -12
- package/src/dashboard/dashboard-component/dashboard-component.service.ts +150 -3
- package/src/dashboard/dashboard-component/dto/create.dto.ts +4 -0
- package/src/dashboard/dashboard-component/dto/update.dto.ts +4 -0
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +108 -5
- /package/hedhog/frontend/app/dashboard/components/widgets/{active-users-card.tsx.ejs → core.active-users-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{activity-timeline.tsx.ejs → core.activity-timeline.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{email-notifications.tsx.ejs → core.email-notifications.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{locale-config.tsx.ejs → core.locale-config.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{login-history-chart.tsx.ejs → core.login-history-chart.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{mail-config.tsx.ejs → core.mail-config.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{mail-sent-card.tsx.ejs → core.mail-sent-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{mail-sent-chart.tsx.ejs → core.mail-sent-chart.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{menus-card.tsx.ejs → core.menus-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{oauth-config.tsx.ejs → core.oauth-config.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{permissions-card.tsx.ejs → core.permissions-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{permissions-chart.tsx.ejs → core.permissions-chart.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{profile-card.tsx.ejs → core.profile-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{routes-card.tsx.ejs → core.routes-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{session-activity-chart.tsx.ejs → core.session-activity-chart.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{sessions-today-card.tsx.ejs → core.sessions-today-card.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{stat-access-level.tsx.ejs → core.stat-access-level.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{stat-actions-today.tsx.ejs → core.stat-actions-today.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{stat-consecutive-days.tsx.ejs → core.stat-consecutive-days.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{stat-online-time.tsx.ejs → core.stat-online-time.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{storage-config.tsx.ejs → core.storage-config.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{theme-config.tsx.ejs → core.theme-config.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{user-growth-chart.tsx.ejs → core.user-growth-chart.tsx.ejs} +0 -0
- /package/hedhog/frontend/app/dashboard/components/widgets/{user-roles.tsx.ejs → core.user-roles.tsx.ejs} +0 -0
|
@@ -2,11 +2,15 @@ import { getLocaleText } from '@hed-hog/api-locale';
|
|
|
2
2
|
import { PaginationDTO, PaginationService } from '@hed-hog/api-pagination';
|
|
3
3
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
4
4
|
import {
|
|
5
|
+
BadRequestException,
|
|
6
|
+
ForbiddenException,
|
|
5
7
|
forwardRef,
|
|
6
8
|
Inject,
|
|
7
9
|
Injectable,
|
|
8
10
|
NotFoundException
|
|
9
11
|
} from '@nestjs/common';
|
|
12
|
+
import { existsSync, promises as fs } from 'fs';
|
|
13
|
+
import { join, resolve } from 'path';
|
|
10
14
|
import {
|
|
11
15
|
CreateDashboardComponentDTO,
|
|
12
16
|
UpdateDashboardComponentDTO,
|
|
@@ -21,7 +25,7 @@ export class DashboardComponentService {
|
|
|
21
25
|
) {}
|
|
22
26
|
|
|
23
27
|
async getAllComponents(paginationParams: PaginationDTO) {
|
|
24
|
-
const fields = ['slug']
|
|
28
|
+
const fields = ['slug', 'library_slug']
|
|
25
29
|
const OR = this.prismaService.createInsensitiveSearch(
|
|
26
30
|
fields,
|
|
27
31
|
paginationParams,
|
|
@@ -83,6 +87,42 @@ export class DashboardComponentService {
|
|
|
83
87
|
|
|
84
88
|
const userRoleIds = userRoles.map((ur) => ur.role_id);
|
|
85
89
|
|
|
90
|
+
if (userRoleIds.length === 0) {
|
|
91
|
+
return this.paginationService.paginate(
|
|
92
|
+
this.prismaService.dashboard_component,
|
|
93
|
+
paginationParams,
|
|
94
|
+
{
|
|
95
|
+
include: {
|
|
96
|
+
dashboard_component_locale: {
|
|
97
|
+
include: {
|
|
98
|
+
locale: true,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
dashboard_component_role: {
|
|
102
|
+
include: {
|
|
103
|
+
role: {
|
|
104
|
+
include: {
|
|
105
|
+
role_locale: {
|
|
106
|
+
include: {
|
|
107
|
+
locale: true,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
where: {
|
|
116
|
+
id: -1,
|
|
117
|
+
},
|
|
118
|
+
orderBy: {
|
|
119
|
+
created_at: 'desc',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
'dashboardComponent',
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
86
126
|
const fields = ['slug']
|
|
87
127
|
const OR = this.prismaService.createInsensitiveSearch(
|
|
88
128
|
fields,
|
|
@@ -221,9 +261,15 @@ export class DashboardComponentService {
|
|
|
221
261
|
}
|
|
222
262
|
|
|
223
263
|
async createComponent(data: CreateDashboardComponentDTO, locale: string) {
|
|
264
|
+
const normalized = this.normalizeComponentIdentity(
|
|
265
|
+
data.slug,
|
|
266
|
+
data.library_slug,
|
|
267
|
+
);
|
|
268
|
+
|
|
224
269
|
const component = await this.prismaService.dashboard_component.create({
|
|
225
270
|
data: {
|
|
226
|
-
slug:
|
|
271
|
+
slug: normalized.slug,
|
|
272
|
+
library_slug: normalized.library_slug,
|
|
227
273
|
min_width: data.min_width,
|
|
228
274
|
max_width: data.max_width,
|
|
229
275
|
min_height: data.min_height,
|
|
@@ -257,10 +303,18 @@ export class DashboardComponentService {
|
|
|
257
303
|
}
|
|
258
304
|
|
|
259
305
|
async updateComponent(id: number, data: UpdateDashboardComponentDTO, locale: string) {
|
|
306
|
+
const normalized = data.slug
|
|
307
|
+
? this.normalizeComponentIdentity(data.slug, data.library_slug)
|
|
308
|
+
: {
|
|
309
|
+
slug: undefined,
|
|
310
|
+
library_slug: data.library_slug,
|
|
311
|
+
};
|
|
312
|
+
|
|
260
313
|
await this.prismaService.dashboard_component.update({
|
|
261
314
|
where: { id },
|
|
262
315
|
data: {
|
|
263
|
-
slug:
|
|
316
|
+
slug: normalized.slug,
|
|
317
|
+
library_slug: normalized.library_slug,
|
|
264
318
|
min_width: data.min_width,
|
|
265
319
|
max_width: data.max_width,
|
|
266
320
|
min_height: data.min_height,
|
|
@@ -312,4 +366,97 @@ export class DashboardComponentService {
|
|
|
312
366
|
where: { id },
|
|
313
367
|
});
|
|
314
368
|
}
|
|
369
|
+
|
|
370
|
+
private normalizeComponentIdentity(slug: string, librarySlug?: string | null) {
|
|
371
|
+
const slugParts = slug.split('.').filter(Boolean);
|
|
372
|
+
const baseSlug =
|
|
373
|
+
slugParts.length > 0 ? slugParts[slugParts.length - 1]! : slug;
|
|
374
|
+
const resolvedLibrarySlug =
|
|
375
|
+
librarySlug || (slugParts.length > 1 ? slugParts[0]! : 'core');
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
slug: baseSlug,
|
|
379
|
+
library_slug: resolvedLibrarySlug,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
private buildWidgetAssetSlug(slug: string, librarySlug?: string | null) {
|
|
384
|
+
const normalized = this.normalizeComponentIdentity(slug, librarySlug);
|
|
385
|
+
|
|
386
|
+
return normalized.slug;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private resolvePreviewDirectory(): string {
|
|
390
|
+
const cwd = process.cwd();
|
|
391
|
+
const candidates = [
|
|
392
|
+
resolve(cwd, 'libraries/core/hedhog/frontend/public/dashboard-previews'),
|
|
393
|
+
resolve(cwd, '../libraries/core/hedhog/frontend/public/dashboard-previews'),
|
|
394
|
+
resolve(cwd, '../../libraries/core/hedhog/frontend/public/dashboard-previews'),
|
|
395
|
+
];
|
|
396
|
+
|
|
397
|
+
for (const candidate of candidates) {
|
|
398
|
+
const parentDirectory = resolve(candidate, '..');
|
|
399
|
+
if (existsSync(parentDirectory)) {
|
|
400
|
+
return candidate;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return candidates[0];
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async savePreview(id: number, file: MulterFile, locale: string) {
|
|
408
|
+
const isDevelopment = process.env.NODE_ENV !== 'production';
|
|
409
|
+
if (!isDevelopment) {
|
|
410
|
+
throw new ForbiddenException(
|
|
411
|
+
getLocaleText('dashboardPreviewOnlyInDevelopment', locale, 'Preview capture is only available in development environment'),
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!file || !file.buffer) {
|
|
416
|
+
throw new BadRequestException(
|
|
417
|
+
getLocaleText('dashboardPreviewFileRequired', locale, 'Preview image file is required'),
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (!file.mimetype?.startsWith('image/')) {
|
|
422
|
+
throw new BadRequestException(
|
|
423
|
+
getLocaleText('dashboardPreviewInvalidFileType', locale, 'Preview file must be an image'),
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const component = await this.prismaService.dashboard_component.findUnique({
|
|
428
|
+
where: { id },
|
|
429
|
+
select: {
|
|
430
|
+
id: true,
|
|
431
|
+
slug: true,
|
|
432
|
+
library_slug: true,
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
if (!component) {
|
|
437
|
+
throw new NotFoundException(
|
|
438
|
+
getLocaleText('dashboardComponentNotFound', locale, 'Dashboard component not found'),
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const previewDirectory = this.resolvePreviewDirectory();
|
|
443
|
+
await fs.mkdir(previewDirectory, { recursive: true });
|
|
444
|
+
|
|
445
|
+
const assetSlug = this.buildWidgetAssetSlug(
|
|
446
|
+
component.slug,
|
|
447
|
+
component.library_slug,
|
|
448
|
+
);
|
|
449
|
+
const fileName = `${assetSlug}.png`;
|
|
450
|
+
const outputPath = join(previewDirectory, fileName);
|
|
451
|
+
await fs.writeFile(outputPath, file.buffer);
|
|
452
|
+
|
|
453
|
+
return {
|
|
454
|
+
success: true,
|
|
455
|
+
componentId: component.id,
|
|
456
|
+
slug: component.slug,
|
|
457
|
+
library_slug: component.library_slug,
|
|
458
|
+
fileName,
|
|
459
|
+
relativeUrl: `/libraries/${component.library_slug}/dashboard-previews/${fileName}`,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
315
462
|
}
|
|
@@ -5,6 +5,10 @@ export class CreateDTO {
|
|
|
5
5
|
@IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
|
|
6
6
|
slug: string;
|
|
7
7
|
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
|
|
10
|
+
library_slug?: string;
|
|
11
|
+
|
|
8
12
|
@IsOptional()
|
|
9
13
|
@IsNumber({}, { message: (args) => getLocaleText('validation.numberRequired', args.value) })
|
|
10
14
|
min_width?: number;
|
|
@@ -6,6 +6,10 @@ export class UpdateDTO {
|
|
|
6
6
|
@IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
|
|
7
7
|
slug?: string;
|
|
8
8
|
|
|
9
|
+
@IsOptional()
|
|
10
|
+
@IsString({ message: (args) => getLocaleText('validation.stringRequired', args.value) })
|
|
11
|
+
library_slug?: string;
|
|
12
|
+
|
|
9
13
|
@IsOptional()
|
|
10
14
|
@IsNumber({}, { message: (args) => getLocaleText('validation.numberRequired', args.value) })
|
|
11
15
|
min_width?: number;
|
|
@@ -1014,6 +1014,7 @@ export class DashboardCoreService {
|
|
|
1014
1014
|
i: `widget-${item.id}`,
|
|
1015
1015
|
component_id: item.component_id,
|
|
1016
1016
|
slug: component.slug,
|
|
1017
|
+
library_slug: component.library_slug,
|
|
1017
1018
|
name: locale?.name || component.slug,
|
|
1018
1019
|
description: locale?.description || '',
|
|
1019
1020
|
x: item.x_axis,
|
|
@@ -1113,8 +1114,50 @@ export class DashboardCoreService {
|
|
|
1113
1114
|
throw new ForbiddenException('Access denied to this dashboard');
|
|
1114
1115
|
}
|
|
1115
1116
|
|
|
1117
|
+
const userRoles = await this.prismaService.role_user.findMany({
|
|
1118
|
+
where: { user_id: userId },
|
|
1119
|
+
select: { role_id: true },
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
const userRoleIds = userRoles.map((item) => item.role_id);
|
|
1123
|
+
|
|
1124
|
+
if (userRoleIds.length === 0) {
|
|
1125
|
+
throw new ForbiddenException('Access denied to this component');
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
const slugParts = componentSlug.split('.').filter(Boolean);
|
|
1129
|
+
const requestedSlug =
|
|
1130
|
+
slugParts.length > 0 ? slugParts[slugParts.length - 1]! : componentSlug;
|
|
1131
|
+
const requestedLibrarySlug =
|
|
1132
|
+
slugParts.length > 1 ? slugParts[0] : undefined;
|
|
1133
|
+
|
|
1116
1134
|
const component = await this.prismaService.dashboard_component.findFirst({
|
|
1117
|
-
where: {
|
|
1135
|
+
where: {
|
|
1136
|
+
AND: [
|
|
1137
|
+
requestedLibrarySlug
|
|
1138
|
+
? {
|
|
1139
|
+
OR: [
|
|
1140
|
+
{ slug: componentSlug },
|
|
1141
|
+
{
|
|
1142
|
+
slug: requestedSlug,
|
|
1143
|
+
library_slug: requestedLibrarySlug,
|
|
1144
|
+
},
|
|
1145
|
+
],
|
|
1146
|
+
}
|
|
1147
|
+
: {
|
|
1148
|
+
OR: [{ slug: componentSlug }, { slug: requestedSlug }],
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
dashboard_component_role: {
|
|
1152
|
+
some: {
|
|
1153
|
+
role_id: {
|
|
1154
|
+
in: userRoleIds,
|
|
1155
|
+
},
|
|
1156
|
+
},
|
|
1157
|
+
},
|
|
1158
|
+
},
|
|
1159
|
+
],
|
|
1160
|
+
},
|
|
1118
1161
|
include: {
|
|
1119
1162
|
dashboard_component_locale: {
|
|
1120
1163
|
where: {
|
|
@@ -1127,7 +1170,7 @@ export class DashboardCoreService {
|
|
|
1127
1170
|
});
|
|
1128
1171
|
|
|
1129
1172
|
if (!component) {
|
|
1130
|
-
throw new
|
|
1173
|
+
throw new ForbiddenException('Access denied to this component');
|
|
1131
1174
|
}
|
|
1132
1175
|
|
|
1133
1176
|
let dashboardItem = await this.prismaService.dashboard_item.findFirst({
|
|
@@ -1138,6 +1181,21 @@ export class DashboardCoreService {
|
|
|
1138
1181
|
});
|
|
1139
1182
|
|
|
1140
1183
|
if (!dashboardItem) {
|
|
1184
|
+
const dashboardItems = await this.prismaService.dashboard_item.findMany({
|
|
1185
|
+
where: {
|
|
1186
|
+
dashboard_id: dashboard.id,
|
|
1187
|
+
},
|
|
1188
|
+
select: {
|
|
1189
|
+
y_axis: true,
|
|
1190
|
+
height: true,
|
|
1191
|
+
},
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
const nextAvailableY = dashboardItems.reduce(
|
|
1195
|
+
(maxY, item) => Math.max(maxY, item.y_axis + item.height),
|
|
1196
|
+
0,
|
|
1197
|
+
);
|
|
1198
|
+
|
|
1141
1199
|
dashboardItem = await this.prismaService.dashboard_item.create({
|
|
1142
1200
|
data: {
|
|
1143
1201
|
dashboard_id: dashboard.id,
|
|
@@ -1145,7 +1203,7 @@ export class DashboardCoreService {
|
|
|
1145
1203
|
width: component.width,
|
|
1146
1204
|
height: component.height,
|
|
1147
1205
|
x_axis: 0,
|
|
1148
|
-
y_axis:
|
|
1206
|
+
y_axis: nextAvailableY,
|
|
1149
1207
|
},
|
|
1150
1208
|
});
|
|
1151
1209
|
}
|
|
@@ -1156,6 +1214,7 @@ export class DashboardCoreService {
|
|
|
1156
1214
|
i: `widget-${dashboardItem.id}`,
|
|
1157
1215
|
component_id: component.id,
|
|
1158
1216
|
slug: component.slug,
|
|
1217
|
+
library_slug: component.library_slug,
|
|
1159
1218
|
name: locale?.name || component.slug,
|
|
1160
1219
|
description: locale?.description || '',
|
|
1161
1220
|
x: dashboardItem.x_axis,
|
|
@@ -1175,8 +1234,52 @@ export class DashboardCoreService {
|
|
|
1175
1234
|
slug: string,
|
|
1176
1235
|
widgetId: string,
|
|
1177
1236
|
) {
|
|
1178
|
-
|
|
1179
|
-
|
|
1237
|
+
const dashboard = await this.prismaService.dashboard.findFirst({
|
|
1238
|
+
where: { slug },
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
if (!dashboard) {
|
|
1242
|
+
throw new Error(`Dashboard with slug '${slug}' not found`);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
const canAccess = await this.prismaService.dashboard_user.findFirst({
|
|
1246
|
+
where: {
|
|
1247
|
+
dashboard_id: dashboard.id,
|
|
1248
|
+
user_id: userId,
|
|
1249
|
+
},
|
|
1250
|
+
select: { id: true },
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
if (!canAccess) {
|
|
1254
|
+
throw new ForbiddenException('Access denied to this dashboard');
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
const parsedWidgetId = Number(widgetId.replace(/^widget-/, ''));
|
|
1258
|
+
|
|
1259
|
+
if (!Number.isInteger(parsedWidgetId) || parsedWidgetId <= 0) {
|
|
1260
|
+
throw new BadRequestException('Invalid widget id');
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
const dashboardItem = await this.prismaService.dashboard_item.findFirst({
|
|
1264
|
+
where: {
|
|
1265
|
+
id: parsedWidgetId,
|
|
1266
|
+
dashboard_id: dashboard.id,
|
|
1267
|
+
},
|
|
1268
|
+
select: { id: true },
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
if (!dashboardItem) {
|
|
1272
|
+
throw new BadRequestException('Widget not found in this dashboard');
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
await this.prismaService.dashboard_item.delete({
|
|
1276
|
+
where: { id: dashboardItem.id },
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
return {
|
|
1280
|
+
success: true,
|
|
1281
|
+
removedWidgetId: `widget-${dashboardItem.id}`,
|
|
1282
|
+
};
|
|
1180
1283
|
}
|
|
1181
1284
|
|
|
1182
1285
|
async checkDashboardAccess(userId: number, slug: string, locale: string) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|