@hed-hog/core 0.0.385 → 0.0.387

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 (146) hide show
  1. package/dist/app-command/app-command.registry.d.ts +2 -0
  2. package/dist/app-command/app-command.registry.d.ts.map +1 -1
  3. package/dist/app-command/app-command.registry.js.map +1 -1
  4. package/dist/auth/auth.controller.d.ts +24 -1
  5. package/dist/auth/auth.controller.d.ts.map +1 -1
  6. package/dist/auth/auth.controller.js +27 -0
  7. package/dist/auth/auth.controller.js.map +1 -1
  8. package/dist/auth/auth.service.d.ts +52 -1
  9. package/dist/auth/auth.service.d.ts.map +1 -1
  10. package/dist/auth/auth.service.js +108 -0
  11. package/dist/auth/auth.service.js.map +1 -1
  12. package/dist/auth/dto/complete-account.dto.d.ts +9 -0
  13. package/dist/auth/dto/complete-account.dto.d.ts.map +1 -0
  14. package/dist/auth/dto/complete-account.dto.js +43 -0
  15. package/dist/auth/dto/complete-account.dto.js.map +1 -0
  16. package/dist/authorize/authorize.controller.d.ts +45 -0
  17. package/dist/authorize/authorize.controller.d.ts.map +1 -0
  18. package/dist/authorize/authorize.controller.js +120 -0
  19. package/dist/authorize/authorize.controller.js.map +1 -0
  20. package/dist/authorize/authorize.module.d.ts +8 -0
  21. package/dist/authorize/authorize.module.d.ts.map +1 -0
  22. package/dist/authorize/authorize.module.js +36 -0
  23. package/dist/authorize/authorize.module.js.map +1 -0
  24. package/dist/authorize/authorize.service.d.ts +79 -0
  25. package/dist/authorize/authorize.service.d.ts.map +1 -0
  26. package/dist/authorize/authorize.service.js +196 -0
  27. package/dist/authorize/authorize.service.js.map +1 -0
  28. package/dist/authorize/dto/authorize-info.dto.d.ts +8 -0
  29. package/dist/authorize/dto/authorize-info.dto.d.ts.map +1 -0
  30. package/dist/authorize/dto/authorize-info.dto.js +42 -0
  31. package/dist/authorize/dto/authorize-info.dto.js.map +1 -0
  32. package/dist/authorize/dto/consent.dto.d.ts +8 -0
  33. package/dist/authorize/dto/consent.dto.d.ts.map +1 -0
  34. package/dist/authorize/dto/consent.dto.js +42 -0
  35. package/dist/authorize/dto/consent.dto.js.map +1 -0
  36. package/dist/authorize/dto/token.dto.d.ts +8 -0
  37. package/dist/authorize/dto/token.dto.d.ts.map +1 -0
  38. package/dist/authorize/dto/token.dto.js +42 -0
  39. package/dist/authorize/dto/token.dto.js.map +1 -0
  40. package/dist/challenge/challenge.service.d.ts +7 -0
  41. package/dist/challenge/challenge.service.d.ts.map +1 -1
  42. package/dist/challenge/challenge.service.js +22 -0
  43. package/dist/challenge/challenge.service.js.map +1 -1
  44. package/dist/core.module.d.ts.map +1 -1
  45. package/dist/core.module.js +2 -0
  46. package/dist/core.module.js.map +1 -1
  47. package/dist/file/file.service.d.ts +7 -0
  48. package/dist/file/file.service.d.ts.map +1 -1
  49. package/dist/file/file.service.js +16 -0
  50. package/dist/file/file.service.js.map +1 -1
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +1 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/integration-profile/integration-profile.secrets.d.ts +6 -2
  56. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  57. package/dist/integration-profile/integration-profile.secrets.js +14 -3
  58. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  59. package/dist/integration-profile/integration-profile.service.d.ts +7 -0
  60. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  61. package/dist/integration-profile/integration-profile.service.js +91 -4
  62. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  63. package/dist/integration-profile/integration-profile.utils.d.ts +28 -0
  64. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  65. package/dist/integration-profile/integration-profile.utils.js +40 -1
  66. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  67. package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
  68. package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
  69. package/dist/oauth/oauth.controller.d.ts +26 -0
  70. package/dist/oauth/oauth.controller.d.ts.map +1 -1
  71. package/dist/oauth/oauth.controller.js +94 -0
  72. package/dist/oauth/oauth.controller.js.map +1 -1
  73. package/dist/oauth/oauth.service.d.ts +39 -1
  74. package/dist/oauth/oauth.service.d.ts.map +1 -1
  75. package/dist/oauth/oauth.service.js +115 -7
  76. package/dist/oauth/oauth.service.js.map +1 -1
  77. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -1
  78. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
  79. package/dist/oauth/providers/microsoft-entra-id.provider.js +37 -6
  80. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  81. package/dist/profile/profile.controller.d.ts +4 -3
  82. package/dist/profile/profile.controller.d.ts.map +1 -1
  83. package/dist/profile/profile.controller.js.map +1 -1
  84. package/dist/profile/profile.service.d.ts +5 -4
  85. package/dist/profile/profile.service.d.ts.map +1 -1
  86. package/dist/profile/profile.service.js.map +1 -1
  87. package/dist/webhook-integration/webhook-integration.controller.d.ts +5 -8
  88. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  89. package/dist/webhook-integration/webhook-integration.controller.js +31 -8
  90. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  91. package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
  92. package/dist/webhook-integration/webhook-integration.module.js +5 -0
  93. package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
  94. package/dist/webhook-integration/webhook-integration.service.d.ts +33 -1
  95. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  96. package/dist/webhook-integration/webhook-integration.service.js +116 -5
  97. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  98. package/dist/webhook-integration/webhook-protocol.registry.d.ts +63 -0
  99. package/dist/webhook-integration/webhook-protocol.registry.d.ts.map +1 -0
  100. package/dist/webhook-integration/webhook-protocol.registry.js +51 -0
  101. package/dist/webhook-integration/webhook-protocol.registry.js.map +1 -0
  102. package/hedhog/data/integration_provider.yaml +8 -0
  103. package/hedhog/data/integration_type.yaml +6 -0
  104. package/hedhog/data/mail.yaml +39 -0
  105. package/hedhog/data/route.yaml +12 -0
  106. package/hedhog/data/setting_group.yaml +15 -1
  107. package/hedhog/frontend/app/account/components/regenerate-codes-dialog.tsx.ejs +11 -7
  108. package/hedhog/frontend/app/account/components/verify-before-add-dialog.tsx.ejs +9 -7
  109. package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +6 -2
  110. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +130 -34
  111. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +16 -8
  112. package/hedhog/frontend/messages/en.json +55 -1
  113. package/hedhog/frontend/messages/pt.json +55 -1
  114. package/hedhog/table/webhook_integration.yaml +64 -43
  115. package/package.json +10 -5
  116. package/src/app-command/app-command.registry.ts +2 -0
  117. package/src/auth/auth.controller.ts +23 -1
  118. package/src/auth/auth.service.ts +135 -1
  119. package/src/auth/dto/complete-account.dto.ts +24 -0
  120. package/src/authorize/authorize.controller.ts +99 -0
  121. package/src/authorize/authorize.module.ts +23 -0
  122. package/src/authorize/authorize.service.spec.ts +307 -0
  123. package/src/authorize/authorize.service.ts +245 -0
  124. package/src/authorize/dto/authorize-info.dto.ts +23 -0
  125. package/src/authorize/dto/consent.dto.ts +23 -0
  126. package/src/authorize/dto/token.dto.ts +23 -0
  127. package/src/challenge/challenge.service.ts +28 -0
  128. package/src/core.module.ts +2 -0
  129. package/src/file/file.service.ts +19 -0
  130. package/src/index.ts +1 -0
  131. package/src/integration-profile/integration-profile.secrets.spec.ts +114 -0
  132. package/src/integration-profile/integration-profile.secrets.ts +14 -3
  133. package/src/integration-profile/integration-profile.service.ts +129 -3
  134. package/src/integration-profile/integration-profile.utils.spec.ts +75 -0
  135. package/src/integration-profile/integration-profile.utils.ts +79 -0
  136. package/src/oauth/interfaces/OAuthProvider.ts +5 -1
  137. package/src/oauth/oauth.controller.ts +89 -0
  138. package/src/oauth/oauth.service.ts +190 -8
  139. package/src/oauth/providers/microsoft-entra-id.provider.ts +45 -5
  140. package/src/profile/profile.controller.ts +6 -2
  141. package/src/profile/profile.service.ts +5 -3
  142. package/src/webhook-integration/webhook-integration.controller.ts +40 -2
  143. package/src/webhook-integration/webhook-integration.module.ts +5 -0
  144. package/src/webhook-integration/webhook-integration.service.ts +151 -2
  145. package/src/webhook-integration/webhook-protocol.registry.spec.ts +70 -0
  146. package/src/webhook-integration/webhook-protocol.registry.ts +93 -0
@@ -57,6 +57,8 @@
57
57
  slug: admin
58
58
  - where:
59
59
  slug: admin-access
60
+ - where:
61
+ slug: user
60
62
  - url: /sessions/:sessionId/revoke
61
63
  method: DELETE
62
64
  type: HTTP
@@ -66,6 +68,8 @@
66
68
  slug: admin
67
69
  - where:
68
70
  slug: admin-access
71
+ - where:
72
+ slug: user
69
73
  - url: /sessions/user
70
74
  method: GET
71
75
  type: HTTP
@@ -3228,6 +3232,10 @@
3228
3232
  method: GET
3229
3233
  type: HTTP
3230
3234
  relations: *core_user_roles
3235
+ - url: /auth/authorize/consent
3236
+ method: POST
3237
+ type: HTTP
3238
+ relations: *core_user_roles
3231
3239
  - url: /auth/roles
3232
3240
  method: GET
3233
3241
  type: HTTP
@@ -3244,6 +3252,10 @@
3244
3252
  method: GET
3245
3253
  type: HTTP
3246
3254
  relations: *core_user_roles
3255
+ - url: /oauth/microsoft-entra-id/redeem/connect
3256
+ method: GET
3257
+ type: HTTP
3258
+ relations: *core_user_roles
3247
3259
  - url: /oauth/:provider
3248
3260
  method: DELETE
3249
3261
  type: HTTP
@@ -71,7 +71,7 @@
71
71
  description:
72
72
  en: 'Base URLs for specific apps, formatted as "app=https://example.com" (one per tag). Used in transactional email links (e.g. password reset) when the request comes from that app, falling back to System URL otherwise.'
73
73
  pt: 'URLs base de apps específicos, no formato "app=https://exemplo.com" (uma por tag). Usadas em links de e-mails transacionais (ex.: redefinição de senha) quando a solicitação vem desse app, usando a URL do Sistema como alternativa.'
74
- value: '["training=http://localhost:3001"]'
74
+ value: '["training=http://localhost:3001","class=https://localhost:3002","partners=http://localhost:3003"]'
75
75
  user_override: false
76
76
  subgroup_id:
77
77
  where:
@@ -517,6 +517,20 @@
517
517
  subgroup_id:
518
518
  where:
519
519
  slug: mfa-general
520
+ - slug: account-invite-expiration-minutes
521
+ type: number
522
+ component: input-number
523
+ name:
524
+ en: Account Invite Link Expiration
525
+ pt: Expiração do Link de Convite de Conta
526
+ description:
527
+ en: Minutes before an account creation invite link expires and becomes invalid
528
+ pt: Minutos antes de um link de convite de criação de conta expirar e se tornar inválido
529
+ value: 10080
530
+ user_override: false
531
+ subgroup_id:
532
+ where:
533
+ slug: mfa-general
520
534
  - slug: access-token-expiration-minutes
521
535
  type: number
522
536
  component: input-number
@@ -1,3 +1,4 @@
1
+ import type { PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/browser';
1
2
  import { Button } from '@/components/ui/button';
2
3
  import {
3
4
  Dialog,
@@ -214,14 +215,17 @@ export function RegenerateCodesDialog({
214
215
  const { startAuthentication } =
215
216
  await import('@simplewebauthn/browser');
216
217
 
217
- const { data: optionsData } = await request({
218
- url: '/profile/webauthn/authenticate/generate',
219
- method: 'POST',
220
- });
218
+ const { data: optionsData } =
219
+ await request<PublicKeyCredentialRequestOptionsJSON>(
220
+ {
221
+ url: '/profile/webauthn/authenticate/generate',
222
+ method: 'POST',
223
+ }
224
+ );
221
225
 
222
- const assertion = await startAuthentication(
223
- optionsData as any
224
- );
226
+ const assertion = await startAuthentication({
227
+ optionsJSON: optionsData,
228
+ });
225
229
  await onConfirm(
226
230
  '',
227
231
  undefined,
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import type { PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/browser';
3
4
  import { Button } from '@/components/ui/button';
4
5
  import {
5
6
  Dialog,
@@ -187,14 +188,15 @@ export function VerifyBeforeAddDialog({
187
188
  const { startAuthentication } =
188
189
  await import('@simplewebauthn/browser');
189
190
 
190
- const { data: optionsData } = await request({
191
- url: '/profile/webauthn/authenticate/generate',
192
- method: 'POST',
193
- });
191
+ const { data: optionsData } =
192
+ await request<PublicKeyCredentialRequestOptionsJSON>({
193
+ url: '/profile/webauthn/authenticate/generate',
194
+ method: 'POST',
195
+ });
194
196
 
195
- const assertion = await startAuthentication(
196
- optionsData as any
197
- );
197
+ const assertion = await startAuthentication({
198
+ optionsJSON: optionsData,
199
+ });
198
200
  await onVerify('', undefined, 'webauthn', assertion);
199
201
  setCode('');
200
202
  setLoading(false);
@@ -212,7 +212,9 @@ export function useMfaSetup() {
212
212
  }
213
213
 
214
214
  showToastHandler('success', t('authenticateToRemove'));
215
- const assertion = await startAuthentication(optionsResponse.data);
215
+ const assertion = await startAuthentication({
216
+ optionsJSON: optionsResponse.data,
217
+ });
216
218
  await request({
217
219
  url: '/profile/webauthn/authenticate/verify',
218
220
  method: 'POST',
@@ -417,7 +419,9 @@ export function useMfaSetup() {
417
419
  data: { name },
418
420
  });
419
421
 
420
- const attestationResponse = await startRegistration(options);
422
+ const attestationResponse = await startRegistration({
423
+ optionsJSON: options,
424
+ });
421
425
 
422
426
  const { data }: any = await request({
423
427
  url: '/profile/webauthn/verify',
@@ -28,6 +28,13 @@ import {
28
28
  ContextMenuSeparator,
29
29
  ContextMenuTrigger,
30
30
  } from '@/components/ui/context-menu';
31
+ import {
32
+ DropdownMenu,
33
+ DropdownMenuContent,
34
+ DropdownMenuItem,
35
+ DropdownMenuSeparator,
36
+ DropdownMenuTrigger,
37
+ } from '@/components/ui/dropdown-menu';
31
38
  import { Input } from '@/components/ui/input';
32
39
  import { ScrollArea } from '@/components/ui/scroll-area';
33
40
  import {
@@ -51,6 +58,7 @@ import {
51
58
  Home,
52
59
  LayoutDashboard,
53
60
  Loader2,
61
+ MoreHorizontal,
54
62
  Palette,
55
63
  Pencil,
56
64
  Plus,
@@ -1032,42 +1040,130 @@ export function DashboardHomeTabs() {
1032
1040
  {tabContent}
1033
1041
  </div>
1034
1042
  ) : (
1035
- <TabsTrigger
1036
- value={dashboard.slug}
1037
- draggable={!isBusy}
1038
- onDragStart={(event) =>
1039
- handleTabDragStart(event, dashboard.slug)
1040
- }
1041
- onDragOver={handleTabDragOver}
1042
- onDrop={(event) =>
1043
- void handleTabDrop(event, dashboard.slug)
1044
- }
1045
- onDragEnd={handleTabDragEnd}
1046
- className={cn(
1047
- 'dashboard-tab-trigger -mb-px mt-1 inline-flex h-9 shrink-0 cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-b-none rounded-t-lg border-none px-3 py-2 shadow-none data-[state=active]:shadow-none',
1048
- draggingDashboardSlug === dashboard.slug &&
1049
- 'opacity-70'
1050
- )}
1051
- style={
1052
- isActiveTab
1053
- ? {
1054
- backgroundColor: 'var(--background)',
1055
- color: 'var(--primary)',
1043
+ <div className="group relative mt-1 shrink-0">
1044
+ <TabsTrigger
1045
+ value={dashboard.slug}
1046
+ draggable={!isBusy}
1047
+ onDragStart={(event) =>
1048
+ handleTabDragStart(event, dashboard.slug)
1049
+ }
1050
+ onDragOver={handleTabDragOver}
1051
+ onDrop={(event) =>
1052
+ void handleTabDrop(event, dashboard.slug)
1053
+ }
1054
+ onDragEnd={handleTabDragEnd}
1055
+ className={cn(
1056
+ 'dashboard-tab-trigger -mb-px inline-flex h-9 shrink-0 cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-b-none rounded-t-lg border-none pr-9 pl-3 py-2 shadow-none data-[state=active]:shadow-none',
1057
+ draggingDashboardSlug === dashboard.slug &&
1058
+ 'opacity-70'
1059
+ )}
1060
+ style={
1061
+ isActiveTab
1062
+ ? {
1063
+ backgroundColor: 'var(--background)',
1064
+ color: 'var(--primary)',
1065
+ }
1066
+ : {
1067
+ backgroundColor: 'transparent',
1068
+ color: 'var(--muted-foreground)',
1069
+ }
1070
+ }
1071
+ onDoubleClick={() =>
1072
+ startRenameDashboard(dashboard)
1073
+ }
1074
+ onContextMenu={() =>
1075
+ setActiveSlug(dashboard.slug)
1076
+ }
1077
+ >
1078
+ {tabContent}
1079
+ </TabsTrigger>
1080
+ <DropdownMenu>
1081
+ <DropdownMenuTrigger asChild>
1082
+ <Button
1083
+ type="button"
1084
+ variant="ghost"
1085
+ size="icon"
1086
+ className={cn(
1087
+ 'absolute top-1/2 right-1 z-10 size-7 -translate-y-1/2 rounded-md text-muted-foreground hover:text-foreground',
1088
+ isActiveTab
1089
+ ? 'bg-background/80'
1090
+ : 'bg-transparent hover:bg-background/60'
1091
+ )}
1092
+ onClick={(event) => {
1093
+ event.stopPropagation();
1094
+ setActiveSlug(dashboard.slug);
1095
+ }}
1096
+ onPointerDown={(event) =>
1097
+ event.stopPropagation()
1056
1098
  }
1057
- : {
1058
- backgroundColor: 'transparent',
1059
- color: 'var(--muted-foreground)',
1099
+ aria-label={t('tabActions')}
1100
+ title={t('tabActions')}
1101
+ >
1102
+ <MoreHorizontal className="size-4" />
1103
+ </Button>
1104
+ </DropdownMenuTrigger>
1105
+ <DropdownMenuContent
1106
+ align="end"
1107
+ className="w-56"
1108
+ onCloseAutoFocus={(event) =>
1109
+ event.preventDefault()
1110
+ }
1111
+ >
1112
+ <DropdownMenuItem
1113
+ onSelect={() =>
1114
+ openAddWidgetsForDashboard(dashboard)
1060
1115
  }
1061
- }
1062
- onDoubleClick={() =>
1063
- startRenameDashboard(dashboard)
1064
- }
1065
- onContextMenu={() =>
1066
- setActiveSlug(dashboard.slug)
1067
- }
1068
- >
1069
- {tabContent}
1070
- </TabsTrigger>
1116
+ >
1117
+ <Plus className="size-4" />
1118
+ {t('addWidgets')}
1119
+ </DropdownMenuItem>
1120
+ {!dashboard.is_home ? (
1121
+ <DropdownMenuItem
1122
+ onSelect={() =>
1123
+ void handleSetHomeDashboard(dashboard)
1124
+ }
1125
+ >
1126
+ <Home className="size-4" />
1127
+ {t('setAsHome')}
1128
+ </DropdownMenuItem>
1129
+ ) : null}
1130
+ <DropdownMenuItem
1131
+ onSelect={() =>
1132
+ startRenameDashboard(dashboard)
1133
+ }
1134
+ >
1135
+ <Pencil className="size-4" />
1136
+ {t('rename')}
1137
+ </DropdownMenuItem>
1138
+ <DropdownMenuItem
1139
+ onSelect={() =>
1140
+ openIconForDashboard(dashboard)
1141
+ }
1142
+ >
1143
+ <Palette className="size-4" />
1144
+ {t('changeIcon')}
1145
+ </DropdownMenuItem>
1146
+ <DropdownMenuItem
1147
+ onSelect={() =>
1148
+ openShareForDashboard(dashboard)
1149
+ }
1150
+ >
1151
+ <Share2 className="size-4" />
1152
+ {t('share')}
1153
+ </DropdownMenuItem>
1154
+ <DropdownMenuSeparator />
1155
+ <DropdownMenuItem
1156
+ variant="destructive"
1157
+ onSelect={() =>
1158
+ openDeleteForDashboard(dashboard)
1159
+ }
1160
+ >
1161
+ <Trash2 className="size-4" />
1162
+ {t('delete')}
1163
+ </DropdownMenuItem>
1164
+ </DropdownMenuContent>
1165
+ </DropdownMenu>
1166
+ </div>
1071
1167
  )}
1072
1168
  </ContextMenuTrigger>
1073
1169
  <ContextMenuContent className="w-56">
@@ -48,7 +48,8 @@ import {
48
48
  TableRow,
49
49
  } from '@/components/ui/table';
50
50
  import { TableBodySkeleton } from '@/components/ui/skeletons';
51
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
51
+ import { Tabs, TabsContent } from '@/components/ui/tabs';
52
+ import { TabsOverflowList } from '@/components/ui/tabs-overflow-list';
52
53
  import { usePagination } from '@/hooks/use-pagination';
53
54
  import { formatDate } from '@/lib/format-date';
54
55
  import { useApp } from '@hed-hog/next-app-provider';
@@ -696,13 +697,20 @@ export default function IntegrationProfilesPage() {
696
697
  />
697
698
 
698
699
  <Tabs value={activeTab} onValueChange={setActiveTab}>
699
- <TabsList>
700
- {types.map((ty) => (
701
- <TabsTrigger key={ty.slug} value={ty.slug}>
702
- {getLocaleName(ty.integration_type_locale, currentLocaleCode)}
703
- </TabsTrigger>
704
- ))}
705
- </TabsList>
700
+ {/* Colapsa as abas que não cabem num dropdown "Mais": há muitos tipos de
701
+ integração e em telas estreitas os TabsTrigger crus encolhiam e se
702
+ sobrepunham. triggerClassName replica o padding do TabsTrigger nos
703
+ spans de medição invisíveis do TabsOverflowList. */}
704
+ <TabsOverflowList
705
+ items={types.map((ty) => ({
706
+ value: ty.slug,
707
+ label: getLocaleName(ty.integration_type_locale, currentLocaleCode),
708
+ }))}
709
+ activeValue={activeTab}
710
+ onValueChange={setActiveTab}
711
+ moreLabel={t('tabsMore')}
712
+ triggerClassName="min-h-8 px-3 text-sm font-medium"
713
+ />
706
714
 
707
715
  {types.map((ty) => (
708
716
  <TabsContent key={ty.slug} value={ty.slug} className="mt-4">
@@ -1399,6 +1399,7 @@
1399
1399
  "shareDashboardError": "Could not share the dashboard.",
1400
1400
  "shareRemoved": "Sharing removed.",
1401
1401
  "revokeShareError": "Could not remove the sharing.",
1402
+ "tabActions": "Tab actions",
1402
1403
  "addWidgets": "Add widgets",
1403
1404
  "setAsHome": "Set as home",
1404
1405
  "rename": "Rename",
@@ -2338,6 +2339,7 @@
2338
2339
  "title": "Integration Profiles",
2339
2340
  "description": "Manage credentials and connection settings for email, messaging, storage, AI, OAuth, and payment providers.",
2340
2341
  "searchPlaceholder": "Search profiles by name or slug...",
2342
+ "tabsMore": "More",
2341
2343
  "selectProfile": "Select profile",
2342
2344
  "selectAllVisible": "Select all visible profiles",
2343
2345
  "newProfile": "New Profile",
@@ -2425,11 +2427,33 @@
2425
2427
  "fieldAccessKeyId": "Access Key ID",
2426
2428
  "fieldSecretAccessKey": "Secret Access Key",
2427
2429
  "fieldRegion": "Region",
2430
+ "fieldDomain": "Domain",
2428
2431
  "fieldToken": "Token",
2429
2432
  "fieldInstanceName": "Instance Name",
2430
2433
  "fieldPhoneNumberId": "Phone Number ID",
2431
2434
  "fieldAccessToken": "Access Token",
2432
2435
  "fieldBusinessId": "Business ID",
2436
+ "fieldAppId": "Meta App ID",
2437
+ "fieldAppSecret": "Meta App Secret",
2438
+ "fieldWabaId": "WhatsApp Business Account ID (WABA)",
2439
+ "fieldVerifyToken": "Webhook Verify Token",
2440
+ "fieldGraphApiVersion": "Graph API Version",
2441
+ "fieldEnvironmentTest": "Test",
2442
+ "fieldEnvironmentProduction": "Production",
2443
+ "copiedToClipboard": "Copied to clipboard",
2444
+ "whatsappWebhookSectionTitle": "Meta Webhook",
2445
+ "whatsappWebhookDescription": "Register this webhook in your Meta app to receive WhatsApp messages.",
2446
+ "whatsappWebhookCallbackUrlLabel": "Callback URL",
2447
+ "whatsappWebhookVerifyTokenLabel": "Verify Token",
2448
+ "whatsappWebhookVerifyTokenHint": "Use the same value you set in the Verify Token field above.",
2449
+ "whatsappWebhookLoading": "Generating URL…",
2450
+ "whatsappWebhookUnavailable": "URL unavailable — check the API base URL setting.",
2451
+ "whatsappWebhookSaveFirst": "Save the profile to generate the webhook URL.",
2452
+ "whatsappWebhookStepsTitle": "In the Meta dashboard (WhatsApp → Configuration):",
2453
+ "whatsappWebhookStep1": "Paste the Callback URL and the Verify Token above.",
2454
+ "whatsappWebhookStep2": "Click \"Verify and save\".",
2455
+ "whatsappWebhookStep3": "Subscribe to the \"messages\" field.",
2456
+ "whatsappWebhookStep4": "Send a test message and confirm it arrives.",
2433
2457
  "fieldBasePath": "Base Path",
2434
2458
  "fieldBucket": "Bucket",
2435
2459
  "fieldProjectId": "Project ID",
@@ -2481,6 +2505,36 @@
2481
2505
  "nodePoolPlaceholder": "Select a node pool",
2482
2506
  "nodePoolNoneFound": "No node pools found for this cluster.",
2483
2507
  "nodePoolLoadError": "Failed to load node pools. Check the API token and cluster ID.",
2484
- "nodePoolNeedCreds": "Fill in the API token and cluster ID first, then load the pools."
2508
+ "nodePoolNeedCreds": "Fill in the API token and cluster ID first, then load the pools.",
2509
+ "fieldEnvironment": "Environment",
2510
+ "optionHomologation": "Homologation (testing)",
2511
+ "optionProduction": "Production (real invoices)",
2512
+ "fieldTaxId": "Issuer tax ID (CNPJ)",
2513
+ "fieldLegalName": "Legal name",
2514
+ "fieldTradeName": "Trade name",
2515
+ "fieldMunicipalRegistration": "Municipal registration",
2516
+ "fieldIbgeCityCode": "IBGE city code",
2517
+ "fieldAddressStreet": "Street",
2518
+ "fieldAddressNumber": "Number",
2519
+ "fieldAddressComplement": "Complement",
2520
+ "fieldAddressDistrict": "District",
2521
+ "fieldAddressZip": "ZIP code",
2522
+ "fieldAddressState": "State",
2523
+ "fieldEmail": "Email",
2524
+ "fieldPhone": "Phone",
2525
+ "fieldTaxRegime": "Tax regime",
2526
+ "optionSimplesNacional": "Simples Nacional",
2527
+ "optionSimplesNacionalExcesso": "Simples Nacional (over the cap)",
2528
+ "optionRegimeNormal": "Regular regime",
2529
+ "optionMei": "MEI",
2530
+ "fieldSpecialTaxRegime": "Special tax regime",
2531
+ "fieldCulturalIncentive": "Cultural incentive",
2532
+ "fieldCertificatePfx": "A1 certificate (.pfx/.p12)",
2533
+ "fieldCertificatePassword": "Certificate password",
2534
+ "fieldBaseUrl": "API base URL",
2535
+ "fieldTimeoutMs": "Timeout (ms)",
2536
+ "fieldMaxRetries": "Max retries",
2537
+ "fileStored": "A file is stored and encrypted. Click to replace it.",
2538
+ "fileSelected": "New file selected. It will be encrypted on save."
2485
2539
  }
2486
2540
  }
@@ -1402,6 +1402,7 @@
1402
1402
  "shareDashboardError": "Não foi possível compartilhar o dashboard.",
1403
1403
  "shareRemoved": "Compartilhamento removido.",
1404
1404
  "revokeShareError": "Não foi possível remover o compartilhamento.",
1405
+ "tabActions": "Ações da aba",
1405
1406
  "addWidgets": "Adicionar widgets",
1406
1407
  "setAsHome": "Definir como home",
1407
1408
  "rename": "Renomear",
@@ -2393,6 +2394,7 @@
2393
2394
  "title": "Perfis de Integração",
2394
2395
  "description": "Gerencie credenciais para provedores de e-mail, mensagens, armazenamento, IA, OAuth e pagamentos.",
2395
2396
  "searchPlaceholder": "Buscar perfis por nome ou slug...",
2397
+ "tabsMore": "Mais",
2396
2398
  "selectProfile": "Selecionar perfil",
2397
2399
  "selectAllVisible": "Selecionar todos os perfis visíveis",
2398
2400
  "newProfile": "Novo Perfil",
@@ -2480,11 +2482,33 @@
2480
2482
  "fieldAccessKeyId": "Access Key ID",
2481
2483
  "fieldSecretAccessKey": "Secret Access Key",
2482
2484
  "fieldRegion": "Região",
2485
+ "fieldDomain": "Domínio",
2483
2486
  "fieldToken": "Token",
2484
2487
  "fieldInstanceName": "Nome da Instância",
2485
2488
  "fieldPhoneNumberId": "ID do Número de Telefone",
2486
2489
  "fieldAccessToken": "Access Token",
2487
2490
  "fieldBusinessId": "Business ID",
2491
+ "fieldAppId": "Meta App ID",
2492
+ "fieldAppSecret": "Meta App Secret",
2493
+ "fieldWabaId": "ID da Conta do WhatsApp Business (WABA)",
2494
+ "fieldVerifyToken": "Verify Token do Webhook",
2495
+ "fieldGraphApiVersion": "Versão da Graph API",
2496
+ "fieldEnvironmentTest": "Teste",
2497
+ "fieldEnvironmentProduction": "Produção",
2498
+ "copiedToClipboard": "Copiado para a área de transferência",
2499
+ "whatsappWebhookSectionTitle": "Webhook da Meta",
2500
+ "whatsappWebhookDescription": "Registre este webhook no seu app da Meta para receber mensagens do WhatsApp.",
2501
+ "whatsappWebhookCallbackUrlLabel": "URL de Callback",
2502
+ "whatsappWebhookVerifyTokenLabel": "Verify Token",
2503
+ "whatsappWebhookVerifyTokenHint": "Use o mesmo valor que você definiu no campo Verify Token acima.",
2504
+ "whatsappWebhookLoading": "Gerando URL…",
2505
+ "whatsappWebhookUnavailable": "URL indisponível — verifique a configuração de URL base da API.",
2506
+ "whatsappWebhookSaveFirst": "Salve o perfil para gerar a URL do webhook.",
2507
+ "whatsappWebhookStepsTitle": "No painel da Meta (WhatsApp → Configuração):",
2508
+ "whatsappWebhookStep1": "Cole a URL de Callback e o Verify Token acima.",
2509
+ "whatsappWebhookStep2": "Clique em \"Verificar e salvar\".",
2510
+ "whatsappWebhookStep3": "Assine o campo \"messages\".",
2511
+ "whatsappWebhookStep4": "Envie uma mensagem de teste e confirme que ela chega.",
2488
2512
  "fieldBasePath": "Caminho Base",
2489
2513
  "fieldBucket": "Bucket",
2490
2514
  "fieldProjectId": "Project ID",
@@ -2536,6 +2560,36 @@
2536
2560
  "nodePoolPlaceholder": "Selecione um node pool",
2537
2561
  "nodePoolNoneFound": "Nenhum node pool encontrado para este cluster.",
2538
2562
  "nodePoolLoadError": "Falha ao carregar os node pools. Verifique o token da API e o ID do cluster.",
2539
- "nodePoolNeedCreds": "Preencha o token da API e o ID do cluster primeiro, depois carregue os pools."
2563
+ "nodePoolNeedCreds": "Preencha o token da API e o ID do cluster primeiro, depois carregue os pools.",
2564
+ "fieldEnvironment": "Ambiente",
2565
+ "optionHomologation": "Homologação (testes)",
2566
+ "optionProduction": "Produção (notas reais)",
2567
+ "fieldTaxId": "CNPJ do emitente",
2568
+ "fieldLegalName": "Razão social",
2569
+ "fieldTradeName": "Nome fantasia",
2570
+ "fieldMunicipalRegistration": "Inscrição municipal",
2571
+ "fieldIbgeCityCode": "Código IBGE do município",
2572
+ "fieldAddressStreet": "Logradouro",
2573
+ "fieldAddressNumber": "Número",
2574
+ "fieldAddressComplement": "Complemento",
2575
+ "fieldAddressDistrict": "Bairro",
2576
+ "fieldAddressZip": "CEP",
2577
+ "fieldAddressState": "Estado",
2578
+ "fieldEmail": "E-mail",
2579
+ "fieldPhone": "Telefone",
2580
+ "fieldTaxRegime": "Regime tributário",
2581
+ "optionSimplesNacional": "Simples Nacional",
2582
+ "optionSimplesNacionalExcesso": "Simples Nacional (excesso de sublimite)",
2583
+ "optionRegimeNormal": "Regime normal",
2584
+ "optionMei": "MEI",
2585
+ "fieldSpecialTaxRegime": "Regime especial de tributação",
2586
+ "fieldCulturalIncentive": "Incentivador cultural",
2587
+ "fieldCertificatePfx": "Certificado A1 (.pfx/.p12)",
2588
+ "fieldCertificatePassword": "Senha do certificado",
2589
+ "fieldBaseUrl": "URL base da API",
2590
+ "fieldTimeoutMs": "Timeout (ms)",
2591
+ "fieldMaxRetries": "Máximo de tentativas",
2592
+ "fileStored": "Arquivo armazenado e cifrado. Clique para substituir.",
2593
+ "fileSelected": "Novo arquivo selecionado. Será cifrado ao salvar."
2540
2594
  }
2541
2595
  }