@hed-hog/core 0.0.299 → 0.0.300
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 +6 -0
- package/dist/dashboard/dashboard/dashboard.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard/dashboard.service.d.ts +6 -0
- package/dist/dashboard/dashboard/dashboard.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +2 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js +6 -3
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +7 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.js +76 -33
- package/dist/dashboard/dashboard-component/dashboard-component.service.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +65 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js +111 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +69 -0
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +526 -19
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +2 -0
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +2 -0
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +2 -0
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +2 -0
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.map +1 -1
- package/hedhog/data/dashboard.yaml +12 -6
- package/hedhog/data/dashboard_component_role.yaml +66 -0
- package/hedhog/data/dashboard_role.yaml +2 -8
- package/hedhog/data/route.yaml +72 -0
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +333 -128
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +277 -53
- package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +179 -231
- package/hedhog/frontend/app/dashboard/components/draggable-grid.tsx.ejs +64 -18
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +1389 -0
- package/hedhog/frontend/app/dashboard/dashboard.css.ejs +37 -0
- package/hedhog/frontend/app/dashboard/management/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +6 -6
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +8 -8
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +3 -3
- package/hedhog/frontend/app/dashboard/page.tsx.ejs +3 -25
- package/hedhog/frontend/messages/en.json +112 -2
- package/hedhog/frontend/messages/pt.json +111 -1
- package/hedhog/frontend/widgets/account-security.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/active-users-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/activity-timeline.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/email-notifications.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/locale-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/login-history-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/mail-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/mail-sent-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/mail-sent-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/menus-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/oauth-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/permissions-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/permissions-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/profile-card.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/routes-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/session-activity-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/sessions-today-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/stat-access-level.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-actions-today.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-consecutive-days.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-online-time.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/storage-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/theme-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-growth-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-roles.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-sessions.tsx.ejs +1 -1
- package/hedhog/table/dashboard.yaml +6 -0
- package/package.json +5 -5
- package/src/dashboard/dashboard-component/dashboard-component.controller.ts +15 -2
- package/src/dashboard/dashboard-component/dashboard-component.service.ts +107 -43
- package/src/dashboard/dashboard-core/dashboard-core.controller.ts +112 -1
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +674 -19
- package/hedhog/frontend/app/dashboard/components/widgets/core..gitkeep.ejs +0 -11
- package/hedhog/frontend/app/dashboard/components/widgets/core.account-security.tsx.ejs +0 -192
- package/hedhog/frontend/app/dashboard/components/widgets/core.active-users-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.activity-timeline.tsx.ejs +0 -223
- package/hedhog/frontend/app/dashboard/components/widgets/core.email-notifications.tsx.ejs +0 -226
- package/hedhog/frontend/app/dashboard/components/widgets/core.locale-config.tsx.ejs +0 -168
- package/hedhog/frontend/app/dashboard/components/widgets/core.login-history-chart.tsx.ejs +0 -115
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-config.tsx.ejs +0 -199
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-sent-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-sent-chart.tsx.ejs +0 -149
- package/hedhog/frontend/app/dashboard/components/widgets/core.menus-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.oauth-config.tsx.ejs +0 -175
- package/hedhog/frontend/app/dashboard/components/widgets/core.permissions-card.tsx.ejs +0 -61
- package/hedhog/frontend/app/dashboard/components/widgets/core.permissions-chart.tsx.ejs +0 -156
- package/hedhog/frontend/app/dashboard/components/widgets/core.profile-card.tsx.ejs +0 -186
- package/hedhog/frontend/app/dashboard/components/widgets/core.routes-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.session-activity-chart.tsx.ejs +0 -183
- package/hedhog/frontend/app/dashboard/components/widgets/core.sessions-today-card.tsx.ejs +0 -62
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-access-level.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-actions-today.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-consecutive-days.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-online-time.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.storage-config.tsx.ejs +0 -196
- package/hedhog/frontend/app/dashboard/components/widgets/core.theme-config.tsx.ejs +0 -213
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-growth-chart.tsx.ejs +0 -210
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-roles.tsx.ejs +0 -132
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-sessions.tsx.ejs +0 -236
- package/hedhog/frontend/app/dashboard/components/widgets/finance.alerts.tsx.ejs +0 -108
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-balance-kpi.tsx.ejs +0 -66
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-flow-chart.tsx.ejs +0 -122
- package/hedhog/frontend/app/dashboard/components/widgets/finance.default-kpi.tsx.ejs +0 -63
- package/hedhog/frontend/app/dashboard/components/widgets/finance.payable-30d-kpi.tsx.ejs +0 -73
- package/hedhog/frontend/app/dashboard/components/widgets/finance.receivable-30d-kpi.tsx.ejs +0 -73
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-payable.tsx.ejs +0 -123
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-receivable.tsx.ejs +0 -118
|
@@ -430,6 +430,115 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
430
430
|
}
|
|
431
431
|
return value.map((provider) => String(provider).toLowerCase());
|
|
432
432
|
}
|
|
433
|
+
slugifyDashboardName(value) {
|
|
434
|
+
const normalized = value
|
|
435
|
+
.normalize('NFD')
|
|
436
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
437
|
+
.toLowerCase()
|
|
438
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
439
|
+
.replace(/^-+|-+$/g, '');
|
|
440
|
+
return normalized || `dashboard-${Date.now()}`;
|
|
441
|
+
}
|
|
442
|
+
getDashboardDisplayName(dashboard) {
|
|
443
|
+
var _a, _b;
|
|
444
|
+
return ((_b = (_a = dashboard.dashboard_locale) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.name) || dashboard.slug;
|
|
445
|
+
}
|
|
446
|
+
async buildUniqueDashboardSlug(baseSlug) {
|
|
447
|
+
let slug = baseSlug;
|
|
448
|
+
let suffix = 2;
|
|
449
|
+
while (await this.prismaService.dashboard.findFirst({
|
|
450
|
+
where: { slug },
|
|
451
|
+
select: { id: true },
|
|
452
|
+
})) {
|
|
453
|
+
slug = `${baseSlug}-${suffix}`;
|
|
454
|
+
suffix += 1;
|
|
455
|
+
}
|
|
456
|
+
return slug;
|
|
457
|
+
}
|
|
458
|
+
async getDashboardUserOrThrow(userId, slug, locale) {
|
|
459
|
+
const dashboardUser = await this.prismaService.dashboard_user.findFirst({
|
|
460
|
+
where: {
|
|
461
|
+
user_id: userId,
|
|
462
|
+
dashboard: { slug },
|
|
463
|
+
},
|
|
464
|
+
include: {
|
|
465
|
+
dashboard: {
|
|
466
|
+
include: {
|
|
467
|
+
dashboard_locale: {
|
|
468
|
+
where: {
|
|
469
|
+
locale: {
|
|
470
|
+
code: locale,
|
|
471
|
+
},
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
});
|
|
478
|
+
if (!dashboardUser) {
|
|
479
|
+
throw new common_1.ForbiddenException((0, api_locale_1.getLocaleText)('dashboardNotFound', locale, 'Dashboard not found.'));
|
|
480
|
+
}
|
|
481
|
+
return dashboardUser;
|
|
482
|
+
}
|
|
483
|
+
async getUserRoleIds(userId) {
|
|
484
|
+
const roleUsers = await this.prismaService.role_user.findMany({
|
|
485
|
+
where: { user_id: userId },
|
|
486
|
+
select: { role_id: true },
|
|
487
|
+
});
|
|
488
|
+
return roleUsers.map((roleUser) => roleUser.role_id);
|
|
489
|
+
}
|
|
490
|
+
async getAccessibleTemplateOrThrow(userId, templateSlug, locale) {
|
|
491
|
+
const userRoleIds = await this.getUserRoleIds(userId);
|
|
492
|
+
const templateAccessFilter = userRoleIds.length > 0
|
|
493
|
+
? {
|
|
494
|
+
OR: [
|
|
495
|
+
{
|
|
496
|
+
dashboard_role: {
|
|
497
|
+
some: {
|
|
498
|
+
role_id: {
|
|
499
|
+
in: userRoleIds,
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
dashboard_role: {
|
|
506
|
+
none: {},
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
],
|
|
510
|
+
}
|
|
511
|
+
: {
|
|
512
|
+
dashboard_role: {
|
|
513
|
+
none: {},
|
|
514
|
+
},
|
|
515
|
+
};
|
|
516
|
+
const template = await this.prismaService.dashboard.findFirst({
|
|
517
|
+
where: Object.assign({ slug: templateSlug, is_template: true }, templateAccessFilter),
|
|
518
|
+
include: {
|
|
519
|
+
dashboard_locale: {
|
|
520
|
+
where: {
|
|
521
|
+
locale: {
|
|
522
|
+
code: locale,
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
dashboard_item: {
|
|
527
|
+
select: {
|
|
528
|
+
component_id: true,
|
|
529
|
+
width: true,
|
|
530
|
+
height: true,
|
|
531
|
+
x_axis: true,
|
|
532
|
+
y_axis: true,
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
if (!template) {
|
|
538
|
+
throw new common_1.ForbiddenException((0, api_locale_1.getLocaleText)('dashboardNotFound', locale, 'Dashboard template not found.'));
|
|
539
|
+
}
|
|
540
|
+
return template;
|
|
541
|
+
}
|
|
433
542
|
async getHome(userId, locale) {
|
|
434
543
|
const user = await this.prismaService.user.findUnique({
|
|
435
544
|
where: { id: userId },
|
|
@@ -771,26 +880,29 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
771
880
|
if (!canAccess) {
|
|
772
881
|
throw new common_1.ForbiddenException('Access denied to this dashboard');
|
|
773
882
|
}
|
|
774
|
-
|
|
775
|
-
const itemId = parseInt(item.i.replace('widget-', ''));
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
dashboard_id: dashboard.id,
|
|
780
|
-
},
|
|
781
|
-
});
|
|
782
|
-
if (!dashboardItem) {
|
|
783
|
-
continue;
|
|
883
|
+
const layoutUpdates = layout.flatMap((item) => {
|
|
884
|
+
const itemId = Number.parseInt(item.i.replace('widget-', ''), 10);
|
|
885
|
+
if (Number.isNaN(itemId)) {
|
|
886
|
+
this.logger.warn(`Skipping dashboard layout item with invalid id: ${item.i}`);
|
|
887
|
+
return [];
|
|
784
888
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
889
|
+
return [
|
|
890
|
+
this.prismaService.dashboard_item.updateMany({
|
|
891
|
+
where: {
|
|
892
|
+
id: itemId,
|
|
893
|
+
dashboard_id: dashboard.id,
|
|
894
|
+
},
|
|
895
|
+
data: {
|
|
896
|
+
x_axis: item.x,
|
|
897
|
+
y_axis: item.y,
|
|
898
|
+
width: item.w,
|
|
899
|
+
height: item.h,
|
|
900
|
+
},
|
|
901
|
+
}),
|
|
902
|
+
];
|
|
903
|
+
});
|
|
904
|
+
if (layoutUpdates.length > 0) {
|
|
905
|
+
await this.prismaService.$transaction(layoutUpdates);
|
|
794
906
|
}
|
|
795
907
|
return { success: true };
|
|
796
908
|
}
|
|
@@ -988,6 +1100,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
988
1100
|
};
|
|
989
1101
|
}
|
|
990
1102
|
async getUserDashboards(userId, locale) {
|
|
1103
|
+
await this.getHome(userId, locale);
|
|
991
1104
|
const dashboardUsers = await this.prismaService.dashboard_user.findMany({
|
|
992
1105
|
where: { user_id: userId },
|
|
993
1106
|
include: {
|
|
@@ -1003,6 +1116,7 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1003
1116
|
},
|
|
1004
1117
|
},
|
|
1005
1118
|
},
|
|
1119
|
+
orderBy: [{ is_home: 'desc' }, { id: 'asc' }],
|
|
1006
1120
|
});
|
|
1007
1121
|
const uniqueByDashboardId = new Map();
|
|
1008
1122
|
for (const dashboardUser of dashboardUsers) {
|
|
@@ -1013,9 +1127,402 @@ let DashboardCoreService = DashboardCoreService_1 = class DashboardCoreService {
|
|
|
1013
1127
|
return Array.from(uniqueByDashboardId.values()).map((dashboardUser) => ({
|
|
1014
1128
|
id: dashboardUser.dashboard.id,
|
|
1015
1129
|
slug: dashboardUser.dashboard.slug,
|
|
1130
|
+
name: this.getDashboardDisplayName(dashboardUser.dashboard),
|
|
1131
|
+
icon: dashboardUser.dashboard.icon,
|
|
1132
|
+
is_home: dashboardUser.is_home,
|
|
1016
1133
|
dashboard_locale: dashboardUser.dashboard.dashboard_locale,
|
|
1017
1134
|
}));
|
|
1018
1135
|
}
|
|
1136
|
+
async getAvailableTemplates(userId, locale) {
|
|
1137
|
+
const userRoleIds = await this.getUserRoleIds(userId);
|
|
1138
|
+
const templateAccessFilter = userRoleIds.length > 0
|
|
1139
|
+
? {
|
|
1140
|
+
OR: [
|
|
1141
|
+
{
|
|
1142
|
+
dashboard_role: {
|
|
1143
|
+
some: {
|
|
1144
|
+
role_id: {
|
|
1145
|
+
in: userRoleIds,
|
|
1146
|
+
},
|
|
1147
|
+
},
|
|
1148
|
+
},
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
dashboard_role: {
|
|
1152
|
+
none: {},
|
|
1153
|
+
},
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
1156
|
+
}
|
|
1157
|
+
: {
|
|
1158
|
+
dashboard_role: {
|
|
1159
|
+
none: {},
|
|
1160
|
+
},
|
|
1161
|
+
};
|
|
1162
|
+
const templates = await this.prismaService.dashboard.findMany({
|
|
1163
|
+
where: Object.assign({ is_template: true }, templateAccessFilter),
|
|
1164
|
+
include: {
|
|
1165
|
+
dashboard_locale: {
|
|
1166
|
+
where: {
|
|
1167
|
+
locale: {
|
|
1168
|
+
code: locale,
|
|
1169
|
+
},
|
|
1170
|
+
},
|
|
1171
|
+
},
|
|
1172
|
+
dashboard_item: {
|
|
1173
|
+
select: { id: true },
|
|
1174
|
+
},
|
|
1175
|
+
},
|
|
1176
|
+
orderBy: [{ id: 'asc' }],
|
|
1177
|
+
});
|
|
1178
|
+
return templates.map((template) => ({
|
|
1179
|
+
id: template.id,
|
|
1180
|
+
slug: template.slug,
|
|
1181
|
+
name: this.getDashboardDisplayName(template),
|
|
1182
|
+
icon: template.icon,
|
|
1183
|
+
itemCount: template.dashboard_item.length,
|
|
1184
|
+
}));
|
|
1185
|
+
}
|
|
1186
|
+
async createUserDashboard(userId, data, locale) {
|
|
1187
|
+
var _a, _b, _c, _d;
|
|
1188
|
+
const templateSlug = this.toNullableString(data === null || data === void 0 ? void 0 : data.templateSlug);
|
|
1189
|
+
const template = templateSlug
|
|
1190
|
+
? await this.getAccessibleTemplateOrThrow(userId, templateSlug, locale)
|
|
1191
|
+
: null;
|
|
1192
|
+
const templateName = template ? this.getDashboardDisplayName(template) : null;
|
|
1193
|
+
const name = this.toNullableString(data === null || data === void 0 ? void 0 : data.name) || templateName;
|
|
1194
|
+
if (!name) {
|
|
1195
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'Dashboard name is required.'));
|
|
1196
|
+
}
|
|
1197
|
+
const requestedSlug = this.toNullableString(data === null || data === void 0 ? void 0 : data.slug);
|
|
1198
|
+
const baseSlug = this.slugifyDashboardName(requestedSlug || name);
|
|
1199
|
+
const slug = await this.buildUniqueDashboardSlug(baseSlug);
|
|
1200
|
+
const icon = (data === null || data === void 0 ? void 0 : data.icon) === undefined
|
|
1201
|
+
? (_a = template === null || template === void 0 ? void 0 : template.icon) !== null && _a !== void 0 ? _a : null
|
|
1202
|
+
: (_c = (_b = this.toNullableString(data === null || data === void 0 ? void 0 : data.icon)) !== null && _b !== void 0 ? _b : template === null || template === void 0 ? void 0 : template.icon) !== null && _c !== void 0 ? _c : null;
|
|
1203
|
+
const [localeRecord, existingCount] = await Promise.all([
|
|
1204
|
+
this.prismaService.locale.findFirst({
|
|
1205
|
+
where: { code: locale },
|
|
1206
|
+
select: { id: true },
|
|
1207
|
+
}),
|
|
1208
|
+
this.prismaService.dashboard_user.count({
|
|
1209
|
+
where: { user_id: userId },
|
|
1210
|
+
}),
|
|
1211
|
+
]);
|
|
1212
|
+
const dashboard = await this.prismaService.dashboard.create({
|
|
1213
|
+
data: {
|
|
1214
|
+
slug,
|
|
1215
|
+
icon,
|
|
1216
|
+
},
|
|
1217
|
+
});
|
|
1218
|
+
if (localeRecord) {
|
|
1219
|
+
await this.prismaService.dashboard_locale.create({
|
|
1220
|
+
data: {
|
|
1221
|
+
dashboard_id: dashboard.id,
|
|
1222
|
+
locale_id: localeRecord.id,
|
|
1223
|
+
name,
|
|
1224
|
+
},
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
await this.prismaService.dashboard_user.create({
|
|
1228
|
+
data: {
|
|
1229
|
+
dashboard_id: dashboard.id,
|
|
1230
|
+
user_id: userId,
|
|
1231
|
+
is_home: existingCount === 0,
|
|
1232
|
+
},
|
|
1233
|
+
});
|
|
1234
|
+
if ((_d = template === null || template === void 0 ? void 0 : template.dashboard_item) === null || _d === void 0 ? void 0 : _d.length) {
|
|
1235
|
+
await this.prismaService.dashboard_item.createMany({
|
|
1236
|
+
data: template.dashboard_item.map((item) => ({
|
|
1237
|
+
dashboard_id: dashboard.id,
|
|
1238
|
+
component_id: item.component_id,
|
|
1239
|
+
width: item.width,
|
|
1240
|
+
height: item.height,
|
|
1241
|
+
x_axis: item.x_axis,
|
|
1242
|
+
y_axis: item.y_axis,
|
|
1243
|
+
})),
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
return {
|
|
1247
|
+
id: dashboard.id,
|
|
1248
|
+
slug,
|
|
1249
|
+
name,
|
|
1250
|
+
icon,
|
|
1251
|
+
is_home: existingCount === 0,
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
async renameUserDashboard(userId, slug, data, locale) {
|
|
1255
|
+
var _a, _b;
|
|
1256
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1257
|
+
const name = this.toNullableString(data === null || data === void 0 ? void 0 : data.name);
|
|
1258
|
+
const normalizedIcon = (data === null || data === void 0 ? void 0 : data.icon) === undefined ? undefined : this.toNullableString(data === null || data === void 0 ? void 0 : data.icon);
|
|
1259
|
+
if (!name && (data === null || data === void 0 ? void 0 : data.icon) === undefined) {
|
|
1260
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'Dashboard name or icon is required.'));
|
|
1261
|
+
}
|
|
1262
|
+
if ((data === null || data === void 0 ? void 0 : data.icon) !== undefined) {
|
|
1263
|
+
await this.prismaService.dashboard.update({
|
|
1264
|
+
where: { id: dashboardUser.dashboard_id },
|
|
1265
|
+
data: {
|
|
1266
|
+
icon: normalizedIcon !== null && normalizedIcon !== void 0 ? normalizedIcon : null,
|
|
1267
|
+
},
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
if (name) {
|
|
1271
|
+
const localeRecord = await this.prismaService.locale.findFirst({
|
|
1272
|
+
where: { code: locale },
|
|
1273
|
+
select: { id: true },
|
|
1274
|
+
});
|
|
1275
|
+
if (!localeRecord) {
|
|
1276
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('localeNotFound', locale, 'Locale not found.'));
|
|
1277
|
+
}
|
|
1278
|
+
const existingLocale = await this.prismaService.dashboard_locale.findFirst({
|
|
1279
|
+
where: {
|
|
1280
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1281
|
+
locale_id: localeRecord.id,
|
|
1282
|
+
},
|
|
1283
|
+
select: { id: true },
|
|
1284
|
+
});
|
|
1285
|
+
if (existingLocale) {
|
|
1286
|
+
await this.prismaService.dashboard_locale.update({
|
|
1287
|
+
where: { id: existingLocale.id },
|
|
1288
|
+
data: { name },
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
else {
|
|
1292
|
+
await this.prismaService.dashboard_locale.create({
|
|
1293
|
+
data: {
|
|
1294
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1295
|
+
locale_id: localeRecord.id,
|
|
1296
|
+
name,
|
|
1297
|
+
},
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
const updatedDashboard = await this.prismaService.dashboard.findUnique({
|
|
1302
|
+
where: { id: dashboardUser.dashboard_id },
|
|
1303
|
+
include: {
|
|
1304
|
+
dashboard_locale: {
|
|
1305
|
+
where: {
|
|
1306
|
+
locale: {
|
|
1307
|
+
code: locale,
|
|
1308
|
+
},
|
|
1309
|
+
},
|
|
1310
|
+
},
|
|
1311
|
+
},
|
|
1312
|
+
});
|
|
1313
|
+
return {
|
|
1314
|
+
success: true,
|
|
1315
|
+
slug,
|
|
1316
|
+
name: name ||
|
|
1317
|
+
(updatedDashboard
|
|
1318
|
+
? this.getDashboardDisplayName(updatedDashboard)
|
|
1319
|
+
: slug),
|
|
1320
|
+
icon: (_b = (_a = updatedDashboard === null || updatedDashboard === void 0 ? void 0 : updatedDashboard.icon) !== null && _a !== void 0 ? _a : normalizedIcon) !== null && _b !== void 0 ? _b : null,
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
async setHomeDashboard(userId, slug, locale) {
|
|
1324
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1325
|
+
await this.prismaService.dashboard_user.updateMany({
|
|
1326
|
+
where: { user_id: userId },
|
|
1327
|
+
data: { is_home: false },
|
|
1328
|
+
});
|
|
1329
|
+
await this.prismaService.dashboard_user.update({
|
|
1330
|
+
where: { id: dashboardUser.id },
|
|
1331
|
+
data: { is_home: true },
|
|
1332
|
+
});
|
|
1333
|
+
return {
|
|
1334
|
+
success: true,
|
|
1335
|
+
slug,
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
async getDashboardShares(userId, slug, locale) {
|
|
1339
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1340
|
+
const sharedUsers = await this.prismaService.dashboard_user.findMany({
|
|
1341
|
+
where: {
|
|
1342
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1343
|
+
},
|
|
1344
|
+
include: {
|
|
1345
|
+
user: {
|
|
1346
|
+
select: {
|
|
1347
|
+
id: true,
|
|
1348
|
+
name: true,
|
|
1349
|
+
user_identifier: {
|
|
1350
|
+
where: {
|
|
1351
|
+
type: 'email',
|
|
1352
|
+
},
|
|
1353
|
+
select: {
|
|
1354
|
+
value: true,
|
|
1355
|
+
},
|
|
1356
|
+
take: 1,
|
|
1357
|
+
},
|
|
1358
|
+
},
|
|
1359
|
+
},
|
|
1360
|
+
},
|
|
1361
|
+
orderBy: {
|
|
1362
|
+
id: 'asc',
|
|
1363
|
+
},
|
|
1364
|
+
});
|
|
1365
|
+
return sharedUsers.map((sharedDashboardUser) => {
|
|
1366
|
+
var _a, _b;
|
|
1367
|
+
return ({
|
|
1368
|
+
id: sharedDashboardUser.user.id,
|
|
1369
|
+
name: sharedDashboardUser.user.name,
|
|
1370
|
+
email: (_b = (_a = sharedDashboardUser.user.user_identifier[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null,
|
|
1371
|
+
isCurrentUser: sharedDashboardUser.user.id === userId,
|
|
1372
|
+
isHome: sharedDashboardUser.is_home,
|
|
1373
|
+
});
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
async getShareableUsers(userId, slug, search, locale) {
|
|
1377
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1378
|
+
const normalizedSearch = this.toNullableString(search);
|
|
1379
|
+
const existingUsers = await this.prismaService.dashboard_user.findMany({
|
|
1380
|
+
where: {
|
|
1381
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1382
|
+
},
|
|
1383
|
+
select: {
|
|
1384
|
+
user_id: true,
|
|
1385
|
+
},
|
|
1386
|
+
});
|
|
1387
|
+
const users = await this.prismaService.user.findMany({
|
|
1388
|
+
where: Object.assign({ id: {
|
|
1389
|
+
notIn: existingUsers.map((item) => item.user_id),
|
|
1390
|
+
} }, (normalizedSearch
|
|
1391
|
+
? {
|
|
1392
|
+
OR: [
|
|
1393
|
+
{
|
|
1394
|
+
name: {
|
|
1395
|
+
contains: normalizedSearch,
|
|
1396
|
+
mode: 'insensitive',
|
|
1397
|
+
},
|
|
1398
|
+
},
|
|
1399
|
+
{
|
|
1400
|
+
user_identifier: {
|
|
1401
|
+
some: {
|
|
1402
|
+
type: 'email',
|
|
1403
|
+
value: {
|
|
1404
|
+
contains: normalizedSearch,
|
|
1405
|
+
mode: 'insensitive',
|
|
1406
|
+
},
|
|
1407
|
+
},
|
|
1408
|
+
},
|
|
1409
|
+
},
|
|
1410
|
+
],
|
|
1411
|
+
}
|
|
1412
|
+
: {})),
|
|
1413
|
+
select: {
|
|
1414
|
+
id: true,
|
|
1415
|
+
name: true,
|
|
1416
|
+
user_identifier: {
|
|
1417
|
+
where: {
|
|
1418
|
+
type: 'email',
|
|
1419
|
+
},
|
|
1420
|
+
select: {
|
|
1421
|
+
value: true,
|
|
1422
|
+
},
|
|
1423
|
+
take: 1,
|
|
1424
|
+
},
|
|
1425
|
+
},
|
|
1426
|
+
take: 20,
|
|
1427
|
+
orderBy: {
|
|
1428
|
+
id: 'desc',
|
|
1429
|
+
},
|
|
1430
|
+
});
|
|
1431
|
+
return users.map((candidateUser) => {
|
|
1432
|
+
var _a, _b;
|
|
1433
|
+
return ({
|
|
1434
|
+
id: candidateUser.id,
|
|
1435
|
+
name: candidateUser.name,
|
|
1436
|
+
email: (_b = (_a = candidateUser.user_identifier[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null,
|
|
1437
|
+
});
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
async shareDashboard(userId, slug, sharedUserId, locale) {
|
|
1441
|
+
if (!sharedUserId || Number.isNaN(Number(sharedUserId))) {
|
|
1442
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.fieldRequired', locale, 'User is required.'));
|
|
1443
|
+
}
|
|
1444
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1445
|
+
if (sharedUserId === userId) {
|
|
1446
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.invalidValue', locale, 'You already have access to this dashboard.'));
|
|
1447
|
+
}
|
|
1448
|
+
const targetUser = await this.prismaService.user.findUnique({
|
|
1449
|
+
where: { id: sharedUserId },
|
|
1450
|
+
select: { id: true },
|
|
1451
|
+
});
|
|
1452
|
+
if (!targetUser) {
|
|
1453
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('userNotFound', locale, 'User not found.'));
|
|
1454
|
+
}
|
|
1455
|
+
const existingShare = await this.prismaService.dashboard_user.findFirst({
|
|
1456
|
+
where: {
|
|
1457
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1458
|
+
user_id: sharedUserId,
|
|
1459
|
+
},
|
|
1460
|
+
select: { id: true },
|
|
1461
|
+
});
|
|
1462
|
+
if (existingShare) {
|
|
1463
|
+
return {
|
|
1464
|
+
success: true,
|
|
1465
|
+
alreadyShared: true,
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
await this.prismaService.dashboard_user.create({
|
|
1469
|
+
data: {
|
|
1470
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1471
|
+
user_id: sharedUserId,
|
|
1472
|
+
is_home: false,
|
|
1473
|
+
},
|
|
1474
|
+
});
|
|
1475
|
+
return {
|
|
1476
|
+
success: true,
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
async revokeDashboardShare(userId, slug, sharedUserId, locale) {
|
|
1480
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1481
|
+
if (sharedUserId === userId) {
|
|
1482
|
+
throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('validation.invalidValue', locale, 'Use the remove dashboard action to leave this tab.'));
|
|
1483
|
+
}
|
|
1484
|
+
await this.prismaService.dashboard_user.deleteMany({
|
|
1485
|
+
where: {
|
|
1486
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1487
|
+
user_id: sharedUserId,
|
|
1488
|
+
},
|
|
1489
|
+
});
|
|
1490
|
+
return {
|
|
1491
|
+
success: true,
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
async removeUserDashboard(userId, slug, locale) {
|
|
1495
|
+
const dashboardUser = await this.getDashboardUserOrThrow(userId, slug, locale);
|
|
1496
|
+
await this.prismaService.dashboard_user.delete({
|
|
1497
|
+
where: { id: dashboardUser.id },
|
|
1498
|
+
});
|
|
1499
|
+
if (dashboardUser.is_home) {
|
|
1500
|
+
const nextDashboard = await this.prismaService.dashboard_user.findFirst({
|
|
1501
|
+
where: { user_id: userId },
|
|
1502
|
+
orderBy: { id: 'asc' },
|
|
1503
|
+
});
|
|
1504
|
+
if (nextDashboard) {
|
|
1505
|
+
await this.prismaService.dashboard_user.update({
|
|
1506
|
+
where: { id: nextDashboard.id },
|
|
1507
|
+
data: { is_home: true },
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const remainingShares = await this.prismaService.dashboard_user.count({
|
|
1512
|
+
where: {
|
|
1513
|
+
dashboard_id: dashboardUser.dashboard_id,
|
|
1514
|
+
},
|
|
1515
|
+
});
|
|
1516
|
+
if (remainingShares === 0) {
|
|
1517
|
+
await this.prismaService.dashboard.delete({
|
|
1518
|
+
where: { id: dashboardUser.dashboard_id },
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
return {
|
|
1522
|
+
success: true,
|
|
1523
|
+
removedSlug: slug,
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1019
1526
|
async getAccountSecurity(userId) {
|
|
1020
1527
|
const now = new Date();
|
|
1021
1528
|
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|