@hed-hog/core 0.0.303 → 0.0.305

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 (118) hide show
  1. package/README.md +84 -36
  2. package/dist/auth/auth.controller.d.ts +0 -3
  3. package/dist/auth/auth.controller.d.ts.map +1 -1
  4. package/dist/auth/auth.controller.js +4 -7
  5. package/dist/auth/auth.controller.js.map +1 -1
  6. package/dist/auth/auth.service.d.ts.map +1 -1
  7. package/dist/auth/auth.service.js +6 -3
  8. package/dist/auth/auth.service.js.map +1 -1
  9. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +9 -0
  10. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
  11. package/dist/dashboard/dashboard-core/dashboard-core.controller.js +12 -0
  12. package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
  13. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +7 -0
  14. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
  15. package/dist/dashboard/dashboard-core/dashboard-core.service.js +45 -1
  16. package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts +9 -0
  22. package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts.map +1 -0
  23. package/dist/mail-sent/dto/query-mail-sent-list.dto.js +49 -0
  24. package/dist/mail-sent/dto/query-mail-sent-list.dto.js.map +1 -0
  25. package/dist/mail-sent/mail-sent.controller.d.ts +24 -2
  26. package/dist/mail-sent/mail-sent.controller.d.ts.map +1 -1
  27. package/dist/mail-sent/mail-sent.controller.js +5 -3
  28. package/dist/mail-sent/mail-sent.controller.js.map +1 -1
  29. package/dist/mail-sent/mail-sent.service.d.ts +28 -3
  30. package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
  31. package/dist/mail-sent/mail-sent.service.js +108 -3
  32. package/dist/mail-sent/mail-sent.service.js.map +1 -1
  33. package/dist/oauth/oauth-callback-coordinator.service.d.ts +18 -0
  34. package/dist/oauth/oauth-callback-coordinator.service.d.ts.map +1 -0
  35. package/dist/oauth/oauth-callback-coordinator.service.js +137 -0
  36. package/dist/oauth/oauth-callback-coordinator.service.js.map +1 -0
  37. package/dist/oauth/oauth.controller.d.ts +4 -2
  38. package/dist/oauth/oauth.controller.d.ts.map +1 -1
  39. package/dist/oauth/oauth.controller.js +39 -11
  40. package/dist/oauth/oauth.controller.js.map +1 -1
  41. package/dist/oauth/oauth.errors.d.ts +16 -0
  42. package/dist/oauth/oauth.errors.d.ts.map +1 -0
  43. package/dist/oauth/oauth.errors.js +30 -0
  44. package/dist/oauth/oauth.errors.js.map +1 -0
  45. package/dist/oauth/oauth.module.d.ts.map +1 -1
  46. package/dist/oauth/oauth.module.js +10 -1
  47. package/dist/oauth/oauth.module.js.map +1 -1
  48. package/dist/oauth/oauth.service.d.ts +9 -1
  49. package/dist/oauth/oauth.service.d.ts.map +1 -1
  50. package/dist/oauth/oauth.service.js +97 -24
  51. package/dist/oauth/oauth.service.js.map +1 -1
  52. package/dist/oauth/providers/abstract.provider.d.ts +6 -0
  53. package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
  54. package/dist/oauth/providers/abstract.provider.js +34 -0
  55. package/dist/oauth/providers/abstract.provider.js.map +1 -1
  56. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +3 -0
  57. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
  58. package/dist/oauth/providers/microsoft-entra-id.provider.js +40 -22
  59. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  60. package/dist/security/security.service.d.ts +1 -0
  61. package/dist/security/security.service.d.ts.map +1 -1
  62. package/dist/security/security.service.js +9 -10
  63. package/dist/security/security.service.js.map +1 -1
  64. package/dist/session/session.service.d.ts +5 -1
  65. package/dist/session/session.service.d.ts.map +1 -1
  66. package/dist/session/session.service.js +76 -10
  67. package/dist/session/session.service.js.map +1 -1
  68. package/dist/setting/setting.service.js +4 -4
  69. package/dist/setting/setting.service.js.map +1 -1
  70. package/dist/token/token.service.d.ts +1 -0
  71. package/dist/token/token.service.d.ts.map +1 -1
  72. package/dist/token/token.service.js +23 -12
  73. package/dist/token/token.service.js.map +1 -1
  74. package/dist/user/user.service.d.ts +1 -1
  75. package/dist/user/user.service.d.ts.map +1 -1
  76. package/dist/user/user.service.js +3 -0
  77. package/dist/user/user.service.js.map +1 -1
  78. package/hedhog/data/dashboard.yaml +2 -2
  79. package/hedhog/data/mail.yaml +147 -0
  80. package/hedhog/data/route.yaml +8 -0
  81. package/hedhog/frontend/app/account/components/change-email-form.tsx.ejs +87 -8
  82. package/hedhog/frontend/app/account/components/profile-form.tsx.ejs +90 -10
  83. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +145 -31
  84. package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
  85. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +67 -2
  86. package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +13 -9
  87. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +250 -45
  88. package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +111 -15
  89. package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +110 -15
  90. package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +113 -15
  91. package/hedhog/frontend/app/mail/log/page.tsx.ejs +481 -70
  92. package/hedhog/frontend/app/menu/page.tsx.ejs +202 -30
  93. package/hedhog/frontend/app/roles/menus.tsx.ejs +1 -1
  94. package/hedhog/frontend/app/roles/page.tsx.ejs +288 -104
  95. package/hedhog/frontend/app/users/page.tsx.ejs +168 -23
  96. package/hedhog/frontend/messages/en.json +45 -6
  97. package/hedhog/frontend/messages/pt.json +45 -6
  98. package/package.json +4 -4
  99. package/src/auth/auth.controller.ts +15 -19
  100. package/src/auth/auth.service.ts +13 -8
  101. package/src/dashboard/dashboard-core/dashboard-core.controller.ts +22 -9
  102. package/src/dashboard/dashboard-core/dashboard-core.service.ts +75 -1
  103. package/src/index.ts +10 -7
  104. package/src/mail-sent/dto/query-mail-sent-list.dto.ts +30 -0
  105. package/src/mail-sent/mail-sent.controller.ts +14 -2
  106. package/src/mail-sent/mail-sent.service.ts +159 -4
  107. package/src/oauth/oauth-callback-coordinator.service.ts +158 -0
  108. package/src/oauth/oauth.controller.ts +58 -1
  109. package/src/oauth/oauth.errors.ts +32 -0
  110. package/src/oauth/oauth.module.ts +10 -1
  111. package/src/oauth/oauth.service.ts +178 -28
  112. package/src/oauth/providers/abstract.provider.ts +64 -0
  113. package/src/oauth/providers/microsoft-entra-id.provider.ts +92 -56
  114. package/src/security/security.service.ts +12 -10
  115. package/src/session/session.service.ts +84 -9
  116. package/src/setting/setting.service.ts +10 -10
  117. package/src/token/token.service.ts +29 -11
  118. package/src/user/user.service.ts +10 -6
@@ -79,9 +79,13 @@ import {
79
79
  TooltipContent,
80
80
  TooltipTrigger,
81
81
  } from '@/components/ui/tooltip';
82
+ import { useFormDraft } from '@/hooks/use-form-draft';
83
+ import { formatDateTime } from '@/lib/format-date';
82
84
  import { cn } from '@/lib/utils';
83
85
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
84
86
  import { zodResolver } from '@hookform/resolvers/zod';
87
+ import { formatDistanceToNow } from 'date-fns';
88
+ import { enUS, ptBR } from 'date-fns/locale';
85
89
  import {
86
90
  BadgeHelp,
87
91
  BookOpen,
@@ -112,7 +116,7 @@ import {
112
116
  } from 'lucide-react';
113
117
  import { useTranslations } from 'next-intl';
114
118
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
115
- import { useForm } from 'react-hook-form';
119
+ import { useForm, useWatch } from 'react-hook-form';
116
120
  import { toast } from 'sonner';
117
121
  import { z } from 'zod';
118
122
 
@@ -1218,6 +1222,20 @@ type RequestError = {
1218
1222
  message?: string;
1219
1223
  };
1220
1224
 
1225
+ type MenuDraftPayload = {
1226
+ mode: 'create' | 'edit';
1227
+ menuId: number | null;
1228
+ localeCode: string;
1229
+ values: {
1230
+ slug: string;
1231
+ url: string;
1232
+ name: string;
1233
+ icon: string;
1234
+ order?: number;
1235
+ menu_id: string;
1236
+ };
1237
+ };
1238
+
1221
1239
  function getRequestErrorMessage(error: unknown, fallback: string) {
1222
1240
  if (error && typeof error === 'object') {
1223
1241
  const requestError = error as RequestError;
@@ -1261,10 +1279,12 @@ function TooltipBadge({
1261
1279
  }
1262
1280
 
1263
1281
  const NO_PARENT = '__none__';
1282
+ const MENU_CREATE_DRAFT_STORAGE_KEY = 'core-menu-create-draft';
1283
+ const MENU_EDIT_DRAFT_STORAGE_KEY = 'core-menu-edit-draft';
1264
1284
 
1265
1285
  export default function MenuPage() {
1266
1286
  const t = useTranslations('core.MenuPage');
1267
- const { request, currentLocaleCode, locales } = useApp();
1287
+ const { request, currentLocaleCode, locales, getSettingValue } = useApp();
1268
1288
 
1269
1289
  const [searchQuery, setSearchQuery] = useState('');
1270
1290
  const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -1367,12 +1387,131 @@ export default function MenuPage() {
1367
1387
  },
1368
1388
  });
1369
1389
 
1390
+ const watchedCreateValues = useWatch({
1391
+ control: form.control,
1392
+ });
1393
+ const watchedEditValues = useWatch({
1394
+ control: editForm.control,
1395
+ });
1396
+
1397
+ const {
1398
+ clearDraft: clearCreateDraft,
1399
+ loadDraft: loadCreateDraft,
1400
+ hasDraft: hasCreateDraft,
1401
+ savedAt: createDraftSavedAt,
1402
+ } = useFormDraft<MenuDraftPayload>({
1403
+ storageKey: MENU_CREATE_DRAFT_STORAGE_KEY,
1404
+ value: {
1405
+ mode: 'create',
1406
+ menuId: null,
1407
+ localeCode: currentLocaleCode,
1408
+ values: {
1409
+ slug: watchedCreateValues.slug ?? '',
1410
+ url: watchedCreateValues.url ?? '',
1411
+ name: watchedCreateValues.name ?? '',
1412
+ icon: watchedCreateValues.icon ?? '',
1413
+ order: watchedCreateValues.order,
1414
+ menu_id: watchedCreateValues.menu_id ?? NO_PARENT,
1415
+ },
1416
+ },
1417
+ hasData: Boolean(
1418
+ (watchedCreateValues.slug ?? '').trim() ||
1419
+ (watchedCreateValues.url ?? '').trim() ||
1420
+ (watchedCreateValues.name ?? '').trim() ||
1421
+ (watchedCreateValues.icon ?? '').trim() ||
1422
+ watchedCreateValues.order != null ||
1423
+ (watchedCreateValues.menu_id ?? NO_PARENT) !== NO_PARENT
1424
+ ),
1425
+ enabled: isDialogOpen,
1426
+ });
1427
+
1428
+ const {
1429
+ clearDraft: clearEditDraft,
1430
+ loadDraft: loadEditDraft,
1431
+ hasDraft: hasEditDraft,
1432
+ savedAt: editDraftSavedAt,
1433
+ } = useFormDraft<MenuDraftPayload>({
1434
+ storageKey: MENU_EDIT_DRAFT_STORAGE_KEY,
1435
+ value: {
1436
+ mode: 'edit',
1437
+ menuId: editingMenu?.id ?? null,
1438
+ localeCode: selectedLocale,
1439
+ values: {
1440
+ slug: watchedEditValues.slug ?? '',
1441
+ url: watchedEditValues.url ?? '',
1442
+ name: watchedEditValues.name ?? '',
1443
+ icon: watchedEditValues.icon ?? '',
1444
+ order: watchedEditValues.order,
1445
+ menu_id: watchedEditValues.menu_id ?? NO_PARENT,
1446
+ },
1447
+ },
1448
+ hasData: Boolean(
1449
+ (watchedEditValues.slug ?? '').trim() ||
1450
+ (watchedEditValues.url ?? '').trim() ||
1451
+ (watchedEditValues.name ?? '').trim() ||
1452
+ (watchedEditValues.icon ?? '').trim() ||
1453
+ watchedEditValues.order != null ||
1454
+ (watchedEditValues.menu_id ?? NO_PARENT) !== NO_PARENT
1455
+ ),
1456
+ enabled: Boolean(editingMenu),
1457
+ });
1458
+
1459
+ const createDraftStatusContent = useMemo(() => {
1460
+ if (!hasCreateDraft || !createDraftSavedAt) {
1461
+ return null;
1462
+ }
1463
+
1464
+ const savedDate = new Date(createDraftSavedAt);
1465
+ if (Number.isNaN(savedDate.getTime())) {
1466
+ return null;
1467
+ }
1468
+
1469
+ const locale = currentLocaleCode.startsWith('pt') ? ptBR : enUS;
1470
+ const relativeLabel = formatDistanceToNow(savedDate, {
1471
+ addSuffix: true,
1472
+ locale,
1473
+ });
1474
+ const absoluteLabel = formatDateTime(
1475
+ savedDate,
1476
+ getSettingValue,
1477
+ currentLocaleCode
1478
+ );
1479
+
1480
+ return currentLocaleCode.startsWith('pt')
1481
+ ? `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`
1482
+ : `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`;
1483
+ }, [createDraftSavedAt, currentLocaleCode, getSettingValue, hasCreateDraft]);
1484
+
1485
+ const editDraftStatusContent = useMemo(() => {
1486
+ if (!hasEditDraft || !editDraftSavedAt) {
1487
+ return null;
1488
+ }
1489
+
1490
+ const savedDate = new Date(editDraftSavedAt);
1491
+ if (Number.isNaN(savedDate.getTime())) {
1492
+ return null;
1493
+ }
1494
+
1495
+ const locale = currentLocaleCode.startsWith('pt') ? ptBR : enUS;
1496
+ const relativeLabel = formatDistanceToNow(savedDate, {
1497
+ addSuffix: true,
1498
+ locale,
1499
+ });
1500
+ const absoluteLabel = formatDateTime(
1501
+ savedDate,
1502
+ getSettingValue,
1503
+ currentLocaleCode
1504
+ );
1505
+
1506
+ return currentLocaleCode.startsWith('pt')
1507
+ ? `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`
1508
+ : `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`;
1509
+ }, [editDraftSavedAt, currentLocaleCode, getSettingValue, hasEditDraft]);
1510
+
1370
1511
  const getMenuDisplayName = useCallback((menu: MenuItem | TreeNode) => {
1371
1512
  return menu.name || menu.menu_locale?.[0]?.name || menu.slug;
1372
1513
  }, []);
1373
1514
 
1374
- const editingMenuId = editingMenu?.id ?? null;
1375
-
1376
1515
  const handleEdit = useCallback(
1377
1516
  async (menu: Pick<MenuItem, 'id'>) => {
1378
1517
  setEditFormError(null);
@@ -1402,6 +1541,14 @@ export default function MenuPage() {
1402
1541
  }
1403
1542
  });
1404
1543
 
1544
+ const storedDraft = loadEditDraft();
1545
+ const nextLocale =
1546
+ storedDraft?.payload.mode === 'edit' &&
1547
+ storedDraft.payload.menuId === fullMenu.id
1548
+ ? storedDraft.payload.localeCode
1549
+ : currentLocaleCode;
1550
+
1551
+ setSelectedLocale(nextLocale);
1405
1552
  setEditingMenu({ ...fullMenu, locale: localeData });
1406
1553
  } catch (error) {
1407
1554
  console.error('Error fetching menu:', error);
@@ -1410,32 +1557,36 @@ export default function MenuPage() {
1410
1557
  setIsRefreshingMenu(false);
1411
1558
  }
1412
1559
  },
1413
- [locales, request, t]
1560
+ [currentLocaleCode, loadEditDraft, locales, request, t]
1414
1561
  );
1415
1562
 
1416
- useEffect(() => {
1417
- if (editingMenuId == null) {
1418
- return;
1419
- }
1420
-
1421
- setSelectedLocale(currentLocaleCode);
1422
- }, [currentLocaleCode, editingMenuId]);
1423
-
1424
1563
  useEffect(() => {
1425
1564
  if (!editingMenu) {
1426
1565
  return;
1427
1566
  }
1428
1567
 
1568
+ const storedDraft = loadEditDraft();
1569
+ const shouldRestoreDraft =
1570
+ storedDraft?.payload.mode === 'edit' &&
1571
+ storedDraft.payload.menuId === editingMenu.id &&
1572
+ storedDraft.payload.localeCode === selectedLocale;
1429
1573
  const localeData = editingMenu.locale?.[selectedLocale];
1430
- editForm.reset({
1431
- slug: editingMenu.slug || '',
1432
- url: editingMenu.url || '',
1433
- icon: editingMenu.icon || '',
1434
- order: editingMenu.order ?? undefined,
1435
- menu_id: editingMenu.menu_id ? String(editingMenu.menu_id) : NO_PARENT,
1436
- name: localeData?.name || editingMenu.name || '',
1437
- });
1438
- }, [editForm, editingMenu, selectedLocale]);
1574
+
1575
+ editForm.reset(
1576
+ shouldRestoreDraft
1577
+ ? storedDraft.payload.values
1578
+ : {
1579
+ slug: editingMenu.slug || '',
1580
+ url: editingMenu.url || '',
1581
+ icon: editingMenu.icon || '',
1582
+ order: editingMenu.order ?? undefined,
1583
+ menu_id: editingMenu.menu_id
1584
+ ? String(editingMenu.menu_id)
1585
+ : NO_PARENT,
1586
+ name: localeData?.name || editingMenu.name || '',
1587
+ }
1588
+ );
1589
+ }, [editForm, editingMenu, loadEditDraft, selectedLocale]);
1439
1590
 
1440
1591
  useEffect(() => {
1441
1592
  if (!allMenus || allMenus.length === 0) {
@@ -1457,14 +1608,20 @@ export default function MenuPage() {
1457
1608
 
1458
1609
  const openCreateMenu = (parentId?: number | null) => {
1459
1610
  setFormError(null);
1460
- form.reset({
1461
- slug: '',
1462
- url: '',
1463
- name: '',
1464
- icon: '',
1465
- order: undefined,
1466
- menu_id: parentId ? String(parentId) : NO_PARENT,
1467
- });
1611
+ const storedDraft = loadCreateDraft();
1612
+
1613
+ form.reset(
1614
+ storedDraft?.payload.mode === 'create'
1615
+ ? storedDraft.payload.values
1616
+ : {
1617
+ slug: '',
1618
+ url: '',
1619
+ name: '',
1620
+ icon: '',
1621
+ order: undefined,
1622
+ menu_id: parentId ? String(parentId) : NO_PARENT,
1623
+ }
1624
+ );
1468
1625
  setIsDialogOpen(true);
1469
1626
  };
1470
1627
 
@@ -1504,6 +1661,7 @@ export default function MenuPage() {
1504
1661
  },
1505
1662
  });
1506
1663
 
1664
+ clearCreateDraft();
1507
1665
  form.reset({
1508
1666
  slug: '',
1509
1667
  url: '',
@@ -1555,6 +1713,7 @@ export default function MenuPage() {
1555
1713
  },
1556
1714
  });
1557
1715
 
1716
+ clearEditDraft();
1558
1717
  toast.success(t('menuUpdatedSuccess'));
1559
1718
  setEditFormError(null);
1560
1719
  await refreshWorkspace(editingMenu.id);
@@ -1640,6 +1799,7 @@ export default function MenuPage() {
1640
1799
  data: { ids: [Number(editingMenu.id)] },
1641
1800
  });
1642
1801
 
1802
+ clearEditDraft();
1643
1803
  setOpenDeleteModal(false);
1644
1804
  setEditingMenu(null);
1645
1805
  setEditFormError(null);
@@ -2078,6 +2238,12 @@ export default function MenuPage() {
2078
2238
  </Alert>
2079
2239
  ) : null}
2080
2240
 
2241
+ {editDraftStatusContent ? (
2242
+ <p className="text-xs text-muted-foreground">
2243
+ {editDraftStatusContent}
2244
+ </p>
2245
+ ) : null}
2246
+
2081
2247
  <div className="flex flex-col gap-2 sm:flex-row">
2082
2248
  <Button
2083
2249
  type="submit"
@@ -2557,6 +2723,12 @@ export default function MenuPage() {
2557
2723
  </Alert>
2558
2724
  ) : null}
2559
2725
 
2726
+ {createDraftStatusContent ? (
2727
+ <p className="text-xs text-muted-foreground">
2728
+ {createDraftStatusContent}
2729
+ </p>
2730
+ ) : null}
2731
+
2560
2732
  <Button type="submit" className="w-full cursor-pointer">
2561
2733
  <Plus className="mr-1 h-4 w-4" />
2562
2734
  {t('buttonAddMenu')}
@@ -222,7 +222,7 @@ export function RoleMenusSection({
222
222
  match.replace('-', '').toUpperCase()
223
223
  );
224
224
 
225
- const tablerIcons = TablerIcons as Record<
225
+ const tablerIcons = TablerIcons as unknown as Record<
226
226
  string,
227
227
  ComponentType<{ className?: string }>
228
228
  >;