@hed-hog/core 0.0.360 → 0.0.362
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/access-log/access-log.controller.d.ts +1 -1
- package/dist/access-log/access-log.service.d.ts +1 -1
- package/dist/access-log/access-log.service.d.ts.map +1 -1
- package/dist/access-log/access-log.service.js +43 -1
- package/dist/access-log/access-log.service.js.map +1 -1
- package/dist/ai/ai.service.d.ts +1 -1
- package/dist/auth/auth.controller.d.ts +27 -26
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +6 -2
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.service.d.ts +35 -34
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +15 -5
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts +1 -0
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +11 -4
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +12 -12
- package/dist/core/system.controller.d.ts +2 -2
- package/dist/core/system.service.d.ts +2 -2
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +66 -66
- package/dist/dashboard/dashboard/dashboard.service.d.ts +66 -66
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +26 -26
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +26 -26
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +34 -34
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +34 -34
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +8 -8
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +8 -8
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +5 -5
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +5 -5
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +25 -25
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +25 -25
- package/dist/file/file.controller.d.ts +6 -6
- package/dist/file/file.module.d.ts.map +1 -1
- package/dist/file/file.module.js +3 -2
- package/dist/file/file.module.js.map +1 -1
- package/dist/file/file.service.d.ts +121 -25
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +217 -32
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/image-optimization.service.d.ts +20 -0
- package/dist/file/image-optimization.service.d.ts.map +1 -0
- package/dist/file/image-optimization.service.js +126 -0
- package/dist/file/image-optimization.service.js.map +1 -0
- package/dist/file/provider/local.provider.d.ts +1 -1
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +2 -9
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/integration-profile.controller.d.ts +15 -15
- package/dist/integration-profile/integration-profile.service.d.ts +15 -15
- package/dist/locale/locale.controller.d.ts +4 -4
- package/dist/locale/locale.service.d.ts +4 -4
- package/dist/mail/mail.controller.d.ts +7 -7
- package/dist/mail/mail.service.d.ts +7 -7
- package/dist/mail-sent/mail-sent.controller.d.ts +12 -12
- package/dist/mail-sent/mail-sent.service.d.ts +12 -12
- package/dist/mcp/mcp-api-key.controller.d.ts +2 -2
- package/dist/mcp/mcp-api-key.service.d.ts +2 -2
- package/dist/mcp/tools/core-users.mcp-tools.d.ts +1 -1
- package/dist/mcp/tools/core-users.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-users.mcp-tools.js +2 -2
- package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.controller.d.ts +8 -8
- package/dist/mcp-chat/mcp-chat.service.d.ts +8 -8
- package/dist/menu/menu.controller.d.ts +10 -10
- package/dist/menu/menu.service.d.ts +10 -10
- package/dist/notification/notification.controller.d.ts +36 -36
- package/dist/notification/notification.service.d.ts +36 -36
- package/dist/profile/profile.controller.d.ts +16 -16
- package/dist/profile/profile.service.d.ts +16 -16
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +44 -23
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/role/role.controller.d.ts +6 -6
- package/dist/role/role.service.d.ts +6 -6
- package/dist/screen/screen.controller.d.ts +3 -3
- package/dist/screen/screen.service.d.ts +3 -3
- package/dist/session/session.controller.d.ts +2 -2
- package/dist/session/session.service.d.ts +6 -6
- package/dist/session/session.service.d.ts.map +1 -1
- package/dist/session/session.service.js +7 -2
- package/dist/session/session.service.js.map +1 -1
- package/dist/setting/setting.controller.d.ts +18 -18
- package/dist/setting/setting.service.d.ts +18 -18
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +0 -1
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/token/token.service.d.ts +1 -0
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +23 -6
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +30 -30
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +4 -3
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +68 -68
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +6 -6
- package/dist/user/user.service.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.d.ts +2 -2
- package/dist/webhook-integration/webhook-integration.service.d.ts +2 -2
- package/hedhog/data/route.yaml +2 -0
- package/hedhog/data/setting_group.yaml +117 -26
- package/hedhog/data/setting_subgroup.yaml +8 -0
- package/hedhog/frontend/app/access-log/page.tsx.ejs +170 -11
- package/hedhog/frontend/app/account/components/remove-mfa-dialog.tsx.ejs +1 -1
- package/hedhog/frontend/app/account/components/verify-before-add-dialog.tsx.ejs +1 -1
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +113 -38
- package/hedhog/frontend/app/users/page.tsx.ejs +7 -7
- package/hedhog/frontend/app/users/permissions.tsx.ejs +137 -83
- package/hedhog/frontend/app/users/user-access-sheet.tsx.ejs +28 -26
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +207 -75
- package/hedhog/frontend/messages/en.json +9 -2
- package/hedhog/frontend/messages/pt.json +9 -2
- package/hedhog/table/setting_runtime_state.yaml +9 -0
- package/package.json +12 -6
- package/src/access-log/access-log.service.ts +19 -1
- package/src/auth/auth.controller.ts +5 -0
- package/src/auth/auth.service.ts +14 -4
- package/src/auth/guards/auth.guard.ts +10 -3
- package/src/file/file.module.ts +3 -2
- package/src/file/file.service.ts +448 -46
- package/src/file/image-optimization.service.ts +123 -0
- package/src/file/provider/local.provider.ts +2 -9
- package/src/index.ts +1 -0
- package/src/mcp/tools/core-users.mcp-tools.ts +267 -267
- package/src/profile/profile.service.ts +40 -22
- package/src/session/session.service.ts +10 -2
- package/src/setting/setting.service.ts +0 -1
- package/src/token/token.service.ts +26 -6
- package/src/user/user.controller.ts +5 -2
- package/src/user/user.service.ts +11 -8
- package/dist/menu/menu.service.spec.d.ts +0 -1
- package/dist/menu/menu.service.spec.d.ts.map +0 -1
- package/dist/menu/menu.service.spec.js +0 -208
- package/dist/menu/menu.service.spec.js.map +0 -1
- package/dist/route/route.service.spec.d.ts +0 -1
- package/dist/route/route.service.spec.d.ts.map +0 -1
- package/dist/route/route.service.spec.js +0 -262
- package/dist/route/route.service.spec.js.map +0 -1
- package/dist/screen/screen.service.spec.d.ts +0 -1
- package/dist/screen/screen.service.spec.d.ts.map +0 -1
- package/dist/screen/screen.service.spec.js +0 -259
- package/dist/screen/screen.service.spec.js.map +0 -1
- package/dist/user/user.service.spec.d.ts +0 -1
- package/dist/user/user.service.spec.d.ts.map +0 -1
- package/dist/user/user.service.spec.js +0 -261
- package/dist/user/user.service.spec.js.map +0 -1
|
@@ -87,6 +87,7 @@ function getLocalizedIntegrationName(
|
|
|
87
87
|
);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
const MAIL_INTEGRATION_PROFILE_SETTING_SLUG = 'mail-integration-profile-id';
|
|
90
91
|
const DAILY_REPORT_EMAIL_INTEGRATION_SETTING_SLUG =
|
|
91
92
|
'operations.daily-report.email-integration-profile-id';
|
|
92
93
|
const DAILY_REPORT_WHATSAPP_INTEGRATION_SETTING_SLUG =
|
|
@@ -103,14 +104,6 @@ const OAUTH_PROFILE_SLUG_TO_PROVIDER: Record<string, string> = {
|
|
|
103
104
|
'oauth-microsoft-profile-id': 'microsoft-oauth',
|
|
104
105
|
'oauth-microsoft-entra-id-profile-id': 'microsoft-entra-id-oauth',
|
|
105
106
|
};
|
|
106
|
-
const ADMIN_LOGIN_OAUTH_SETTING_SLUG = 'admin-login-page-oauth-providers';
|
|
107
|
-
const ADMIN_LOGIN_PROVIDER_ENABLED_SLUG_BY_PROVIDER: Record<string, string> = {
|
|
108
|
-
facebook: 'oauth-facebook-enabled',
|
|
109
|
-
github: 'oauth-github-enabled',
|
|
110
|
-
google: 'oauth-google-enabled',
|
|
111
|
-
microsoft: 'oauth-microsoft-enabled',
|
|
112
|
-
'microsoft-entra-id': 'oauth-microsoft-entra-id-enabled',
|
|
113
|
-
};
|
|
114
107
|
const INTEGRATION_PROFILE_PICKER_SLUGS = [
|
|
115
108
|
'file-storage-profile-id',
|
|
116
109
|
...AI_PROFILE_SETTING_SLUGS,
|
|
@@ -524,8 +517,6 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
|
|
|
524
517
|
const selectedValues: string[] = Array.isArray(parsedValue)
|
|
525
518
|
? parsedValue
|
|
526
519
|
: [];
|
|
527
|
-
const isAdminLoginOAuthSetting =
|
|
528
|
-
setting.slug === ADMIN_LOGIN_OAUTH_SETTING_SLUG;
|
|
529
520
|
|
|
530
521
|
return (
|
|
531
522
|
<div
|
|
@@ -535,25 +526,12 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
|
|
|
535
526
|
)}
|
|
536
527
|
>
|
|
537
528
|
{options.map((option) => {
|
|
538
|
-
const enabledSettingSlug =
|
|
539
|
-
ADMIN_LOGIN_PROVIDER_ENABLED_SLUG_BY_PROVIDER[option.value];
|
|
540
|
-
const isProviderGloballyEnabled = enabledSettingSlug
|
|
541
|
-
? getSettingValue(enabledSettingSlug) === true
|
|
542
|
-
: true;
|
|
543
|
-
const isOptionDisabled =
|
|
544
|
-
isAdminLoginOAuthSetting && !isProviderGloballyEnabled;
|
|
545
|
-
|
|
546
529
|
return (
|
|
547
530
|
<div key={option.id} className="flex items-center space-x-2">
|
|
548
531
|
<Checkbox
|
|
549
532
|
className="bg-background"
|
|
550
533
|
checked={selectedValues.includes(option.value)}
|
|
551
|
-
disabled={isOptionDisabled}
|
|
552
534
|
onCheckedChange={(checked) => {
|
|
553
|
-
if (isOptionDisabled) {
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
535
|
let newValues = [...selectedValues];
|
|
558
536
|
if (checked) {
|
|
559
537
|
newValues.push(option.value);
|
|
@@ -565,19 +543,10 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
|
|
|
565
543
|
handleChangeValue(formatValue(newValues), true);
|
|
566
544
|
}}
|
|
567
545
|
/>
|
|
568
|
-
<Label
|
|
569
|
-
{option.value}
|
|
570
|
-
</Label>
|
|
546
|
+
<Label>{option.value}</Label>
|
|
571
547
|
</div>
|
|
572
548
|
);
|
|
573
549
|
})}
|
|
574
|
-
{isAdminLoginOAuthSetting && (
|
|
575
|
-
<p className="text-xs text-muted-foreground">
|
|
576
|
-
{currentLocaleCode.startsWith('pt')
|
|
577
|
-
? 'Providers desabilitados globalmente (oauth-*-enabled = false) ficam indisponíveis nesta lista.'
|
|
578
|
-
: 'Providers disabled globally (oauth-*-enabled = false) are unavailable in this list.'}
|
|
579
|
-
</p>
|
|
580
|
-
)}
|
|
581
550
|
</div>
|
|
582
551
|
);
|
|
583
552
|
}
|
|
@@ -667,7 +636,10 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
|
|
|
667
636
|
setting.slug
|
|
668
637
|
);
|
|
669
638
|
|
|
670
|
-
if (
|
|
639
|
+
if (
|
|
640
|
+
setting.slug === 'file-storage-profile-id' ||
|
|
641
|
+
setting.slug === 'lms-bulk-upload-storage-profile-id'
|
|
642
|
+
) {
|
|
671
643
|
const loadStorageTypeId = async () => {
|
|
672
644
|
const typesResponse = await request<IntegrationTypeOption[]>({
|
|
673
645
|
url: '/integration-profile/types',
|
|
@@ -1004,10 +976,113 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
|
|
|
1004
976
|
);
|
|
1005
977
|
}
|
|
1006
978
|
|
|
1007
|
-
if (
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
979
|
+
if (setting.slug === MAIL_INTEGRATION_PROFILE_SETTING_SLUG) {
|
|
980
|
+
return (
|
|
981
|
+
<>
|
|
982
|
+
<div className="flex w-full min-w-0 items-center gap-2 md:max-w-72">
|
|
983
|
+
<EntityPicker<IntegrationProfileOption & Record<string, unknown>>
|
|
984
|
+
placeholder={t('selectMailProfile')}
|
|
985
|
+
emptyStateDescription={t('mailProfileEmptyState')}
|
|
986
|
+
value={parsedValue ? Number(parsedValue) : null}
|
|
987
|
+
onChange={(id, option) => {
|
|
988
|
+
setStorageProfileSelectedLabel(option?.name ?? '');
|
|
989
|
+
handleChangeValue(id != null ? String(id) : '', true);
|
|
990
|
+
}}
|
|
991
|
+
valueType="number"
|
|
992
|
+
initialSelectedLabel={storageProfileSelectedLabel}
|
|
993
|
+
showCreateButton={false}
|
|
994
|
+
clearable={false}
|
|
995
|
+
loadOptions={async ({ page, pageSize, search }) => {
|
|
996
|
+
const qs = new URLSearchParams({
|
|
997
|
+
page: String(page),
|
|
998
|
+
pageSize: String(pageSize),
|
|
999
|
+
typeSlug: 'email',
|
|
1000
|
+
});
|
|
1001
|
+
if (search) qs.set('search', search);
|
|
1002
|
+
const response = await request<
|
|
1003
|
+
ApiPaginated<
|
|
1004
|
+
IntegrationProfileOption & Record<string, unknown>
|
|
1005
|
+
>
|
|
1006
|
+
>({
|
|
1007
|
+
url: `/integration-profile?${qs}`,
|
|
1008
|
+
method: 'GET',
|
|
1009
|
+
});
|
|
1010
|
+
const paged = response.data;
|
|
1011
|
+
return {
|
|
1012
|
+
items: paged?.data ?? [],
|
|
1013
|
+
hasMore: (paged?.page ?? 0) < (paged?.lastPage ?? 0),
|
|
1014
|
+
};
|
|
1015
|
+
}}
|
|
1016
|
+
getOptionValue={(opt) => opt.id}
|
|
1017
|
+
getOptionLabel={(opt) => String(opt.name ?? '')}
|
|
1018
|
+
getOptionDescription={(opt) => {
|
|
1019
|
+
const providerSlug = String(
|
|
1020
|
+
opt.integration_provider?.slug ?? ''
|
|
1021
|
+
);
|
|
1022
|
+
const providerName = getLocalizedIntegrationName(
|
|
1023
|
+
opt.integration_provider?.integration_provider_locale,
|
|
1024
|
+
currentLocaleCode
|
|
1025
|
+
);
|
|
1026
|
+
return [providerName || providerSlug, opt.slug]
|
|
1027
|
+
.filter(Boolean)
|
|
1028
|
+
.join(' • ');
|
|
1029
|
+
}}
|
|
1030
|
+
className={cn('flex-1 min-w-0', className)}
|
|
1031
|
+
/>
|
|
1032
|
+
|
|
1033
|
+
<Button
|
|
1034
|
+
type="button"
|
|
1035
|
+
variant="outline"
|
|
1036
|
+
size="icon"
|
|
1037
|
+
className="h-10 w-10 shrink-0"
|
|
1038
|
+
onClick={() => {
|
|
1039
|
+
setStorageProfileEditingId(
|
|
1040
|
+
parsedValue ? Number(parsedValue) : null
|
|
1041
|
+
);
|
|
1042
|
+
setIsStorageProfileSheetOpen(true);
|
|
1043
|
+
}}
|
|
1044
|
+
disabled={!parsedValue}
|
|
1045
|
+
aria-label="Editar perfil de email"
|
|
1046
|
+
title="Editar perfil de email"
|
|
1047
|
+
>
|
|
1048
|
+
<Pencil className="h-4 w-4" />
|
|
1049
|
+
</Button>
|
|
1050
|
+
|
|
1051
|
+
<Button
|
|
1052
|
+
type="button"
|
|
1053
|
+
variant="outline"
|
|
1054
|
+
size="icon"
|
|
1055
|
+
className="h-10 w-10 shrink-0"
|
|
1056
|
+
onClick={() => {
|
|
1057
|
+
setStorageProfileEditingId(null);
|
|
1058
|
+
setIsStorageProfileSheetOpen(true);
|
|
1059
|
+
}}
|
|
1060
|
+
aria-label="Criar perfil de email"
|
|
1061
|
+
title="Criar perfil de email"
|
|
1062
|
+
>
|
|
1063
|
+
<Plus className="h-4 w-4" />
|
|
1064
|
+
</Button>
|
|
1065
|
+
</div>
|
|
1066
|
+
|
|
1067
|
+
<IntegrationProfileSheet
|
|
1068
|
+
open={isStorageProfileSheetOpen}
|
|
1069
|
+
onOpenChange={(nextOpen) => {
|
|
1070
|
+
setIsStorageProfileSheetOpen(nextOpen);
|
|
1071
|
+
if (!nextOpen) setStorageProfileEditingId(null);
|
|
1072
|
+
}}
|
|
1073
|
+
profileId={storageProfileEditingId}
|
|
1074
|
+
initialTypeSlug="email"
|
|
1075
|
+
lockedTypeSlug="email"
|
|
1076
|
+
onSaved={(profile: IntegrationProfileSheetSavedProfile) => {
|
|
1077
|
+
setStorageProfileSelectedLabel(profile.name ?? '');
|
|
1078
|
+
handleChangeValue(String(profile.id), true);
|
|
1079
|
+
}}
|
|
1080
|
+
/>
|
|
1081
|
+
</>
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
if (!dailyReportIntegrationTypeSlug) {
|
|
1011
1086
|
return (
|
|
1012
1087
|
<Input
|
|
1013
1088
|
type="text"
|
|
@@ -17,6 +17,12 @@ import {
|
|
|
17
17
|
CardHeader,
|
|
18
18
|
CardTitle,
|
|
19
19
|
} from '@/components/ui/card';
|
|
20
|
+
import {
|
|
21
|
+
DropdownMenu,
|
|
22
|
+
DropdownMenuContent,
|
|
23
|
+
DropdownMenuItem,
|
|
24
|
+
DropdownMenuTrigger,
|
|
25
|
+
} from '@/components/ui/dropdown-menu';
|
|
20
26
|
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
21
27
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
22
28
|
import {
|
|
@@ -53,12 +59,6 @@ import {
|
|
|
53
59
|
import { useTranslations } from 'next-intl';
|
|
54
60
|
import { useEffect, useMemo, useState } from 'react';
|
|
55
61
|
import { UserSheet } from './user-sheet';
|
|
56
|
-
import {
|
|
57
|
-
DropdownMenu,
|
|
58
|
-
DropdownMenuContent,
|
|
59
|
-
DropdownMenuItem,
|
|
60
|
-
DropdownMenuTrigger,
|
|
61
|
-
} from '@/components/ui/dropdown-menu';
|
|
62
62
|
|
|
63
63
|
const USER_VIEW_STORAGE_KEY = 'core-user-view-mode';
|
|
64
64
|
type UserViewMode = 'table' | 'cards';
|
|
@@ -366,7 +366,7 @@ export default function UserPage() {
|
|
|
366
366
|
viewMode === 'cards' ? (
|
|
367
367
|
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
|
368
368
|
{Array.from({ length: 6 }).map((_, i) => (
|
|
369
|
-
<Card key={i} className="overflow-hidden
|
|
369
|
+
<Card key={i} className="overflow-hidden">
|
|
370
370
|
<CardContent className="space-y-3 p-4">
|
|
371
371
|
<div className="flex items-center gap-3">
|
|
372
372
|
<Skeleton className="h-12 w-12 rounded-full" />
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { EmptyState } from '@/components/entity-list';
|
|
4
|
+
import { Badge } from '@/components/ui/badge';
|
|
4
5
|
import { Button } from '@/components/ui/button';
|
|
5
|
-
import { Card, CardContent } from '@/components/ui/card';
|
|
6
6
|
import { Input } from '@/components/ui/input';
|
|
7
|
-
import { Label } from '@/components/ui/label';
|
|
8
7
|
import { Switch } from '@/components/ui/switch';
|
|
8
|
+
import {
|
|
9
|
+
Table,
|
|
10
|
+
TableBody,
|
|
11
|
+
TableCell,
|
|
12
|
+
TableHead,
|
|
13
|
+
TableHeader,
|
|
14
|
+
TableRow,
|
|
15
|
+
} from '@/components/ui/table';
|
|
16
|
+
import {
|
|
17
|
+
Tooltip,
|
|
18
|
+
TooltipContent,
|
|
19
|
+
TooltipTrigger,
|
|
20
|
+
} from '@/components/ui/tooltip';
|
|
9
21
|
import { Role } from '@hed-hog/api-types';
|
|
10
22
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
11
23
|
import { CheckCheck, Eye, Loader2, Search, ShieldCheck, X } from 'lucide-react';
|
|
@@ -167,36 +179,50 @@ export function PermissionsSection({
|
|
|
167
179
|
/>
|
|
168
180
|
</div>
|
|
169
181
|
{hasUnassigned && (
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
<Tooltip>
|
|
183
|
+
<TooltipTrigger asChild>
|
|
184
|
+
<Button
|
|
185
|
+
variant="outline"
|
|
186
|
+
size="icon"
|
|
187
|
+
className="h-8 w-8 shrink-0"
|
|
188
|
+
onClick={handleAssignAll}
|
|
189
|
+
disabled={isDisabled}
|
|
190
|
+
aria-label={t('addAllRoles')}
|
|
191
|
+
>
|
|
192
|
+
{isBulkLoading ? (
|
|
193
|
+
<Loader2 className="h-4 w-4 animate-spin" />
|
|
194
|
+
) : (
|
|
195
|
+
<CheckCheck className="h-4 w-4" />
|
|
196
|
+
)}
|
|
197
|
+
</Button>
|
|
198
|
+
</TooltipTrigger>
|
|
199
|
+
<TooltipContent>
|
|
200
|
+
<p>{t('addAllRoles')}</p>
|
|
201
|
+
</TooltipContent>
|
|
202
|
+
</Tooltip>
|
|
184
203
|
)}
|
|
185
204
|
{hasAssigned && (
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
205
|
+
<Tooltip>
|
|
206
|
+
<TooltipTrigger asChild>
|
|
207
|
+
<Button
|
|
208
|
+
variant="outline"
|
|
209
|
+
size="icon"
|
|
210
|
+
className="h-8 w-8 shrink-0"
|
|
211
|
+
onClick={handleRemoveAll}
|
|
212
|
+
disabled={isDisabled}
|
|
213
|
+
aria-label={t('removeAllRoles')}
|
|
214
|
+
>
|
|
215
|
+
{isBulkLoading ? (
|
|
216
|
+
<Loader2 className="h-4 w-4 animate-spin" />
|
|
217
|
+
) : (
|
|
218
|
+
<X className="h-4 w-4" />
|
|
219
|
+
)}
|
|
220
|
+
</Button>
|
|
221
|
+
</TooltipTrigger>
|
|
222
|
+
<TooltipContent>
|
|
223
|
+
<p>{t('removeAllRoles')}</p>
|
|
224
|
+
</TooltipContent>
|
|
225
|
+
</Tooltip>
|
|
200
226
|
)}
|
|
201
227
|
<Button
|
|
202
228
|
variant="outline"
|
|
@@ -215,61 +241,89 @@ export function PermissionsSection({
|
|
|
215
241
|
<p className="text-sm text-muted-foreground">{t('noRolesMatch')}</p>
|
|
216
242
|
</div>
|
|
217
243
|
) : (
|
|
218
|
-
<div className="
|
|
219
|
-
|
|
220
|
-
|
|
244
|
+
<div className="overflow-hidden rounded-lg border border-border/70 bg-background">
|
|
245
|
+
<Table className="table-fixed">
|
|
246
|
+
<TableHeader className="bg-muted/20">
|
|
247
|
+
<TableRow className="hover:bg-transparent">
|
|
248
|
+
<TableHead className="h-8 px-2 text-[11px] font-medium text-muted-foreground">
|
|
249
|
+
Cargo
|
|
250
|
+
</TableHead>
|
|
251
|
+
<TableHead className="h-8 w-37.5 px-2 text-[11px] font-medium text-muted-foreground">
|
|
252
|
+
Slug
|
|
253
|
+
</TableHead>
|
|
254
|
+
<TableHead className="h-8 w-19.5 px-2 text-right text-[11px] font-medium text-muted-foreground">
|
|
255
|
+
Acesso
|
|
256
|
+
</TableHead>
|
|
257
|
+
</TableRow>
|
|
258
|
+
</TableHeader>
|
|
259
|
+
<TableBody>
|
|
260
|
+
{filteredRoles.map((role, index) => {
|
|
261
|
+
const isToggling = togglingRoleId === role.id;
|
|
221
262
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}`}
|
|
230
|
-
>
|
|
231
|
-
<CardContent className="flex items-center justify-between px-4">
|
|
232
|
-
<div className="flex items-center gap-2 flex-1">
|
|
233
|
-
<div
|
|
234
|
-
className={`rounded-md p-2 ${
|
|
235
|
-
role.isAssigned ? 'bg-primary/10' : 'bg-muted'
|
|
236
|
-
}`}
|
|
237
|
-
>
|
|
238
|
-
<ShieldCheck
|
|
239
|
-
className={`h-5 w-5 ${
|
|
240
|
-
role.isAssigned
|
|
241
|
-
? 'text-primary'
|
|
242
|
-
: 'text-muted-foreground'
|
|
243
|
-
}`}
|
|
244
|
-
/>
|
|
245
|
-
</div>
|
|
246
|
-
<div className="flex-1">
|
|
247
|
-
<Label
|
|
248
|
-
htmlFor={`role-${role.id}`}
|
|
249
|
-
className="text-sm font-medium cursor-pointer"
|
|
250
|
-
>
|
|
251
|
-
{role.name} ({role.slug})
|
|
252
|
-
</Label>
|
|
253
|
-
{role.description && (
|
|
254
|
-
<p className="text-xs text-muted-foreground">
|
|
255
|
-
{role.description}
|
|
256
|
-
</p>
|
|
257
|
-
)}
|
|
258
|
-
</div>
|
|
259
|
-
</div>
|
|
260
|
-
<Switch
|
|
261
|
-
id={`role-${role.id}`}
|
|
262
|
-
checked={role.isAssigned}
|
|
263
|
-
disabled={isToggling || isDisabled}
|
|
264
|
-
onCheckedChange={() =>
|
|
265
|
-
handleToggleRole(role.id!, role.isAssigned)
|
|
263
|
+
return (
|
|
264
|
+
<TableRow
|
|
265
|
+
key={role.id ?? `role-${index}`}
|
|
266
|
+
className={
|
|
267
|
+
role.isAssigned
|
|
268
|
+
? 'bg-primary/5 hover:bg-primary/5'
|
|
269
|
+
: 'hover:bg-muted/20'
|
|
266
270
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
271
|
+
>
|
|
272
|
+
<TableCell className="px-2 py-1.5 align-middle">
|
|
273
|
+
<div className="flex min-w-0 items-start gap-1.5">
|
|
274
|
+
<div
|
|
275
|
+
className={`mt-0.5 rounded-md p-0.5 ${
|
|
276
|
+
role.isAssigned ? 'bg-primary/10' : 'bg-muted/70'
|
|
277
|
+
}`}
|
|
278
|
+
>
|
|
279
|
+
<ShieldCheck
|
|
280
|
+
className={`h-3.5 w-3.5 ${
|
|
281
|
+
role.isAssigned
|
|
282
|
+
? 'text-primary'
|
|
283
|
+
: 'text-muted-foreground'
|
|
284
|
+
}`}
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
<div className="min-w-0 flex-1">
|
|
288
|
+
<div className="truncate text-[13px] font-semibold leading-4 text-foreground">
|
|
289
|
+
{role.name}
|
|
290
|
+
</div>
|
|
291
|
+
{role.description && (
|
|
292
|
+
<p className="truncate text-[11px] leading-3 text-muted-foreground">
|
|
293
|
+
{role.description}
|
|
294
|
+
</p>
|
|
295
|
+
)}
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
</TableCell>
|
|
299
|
+
<TableCell className="px-2 py-1.5 align-middle">
|
|
300
|
+
{role.slug ? (
|
|
301
|
+
<Badge
|
|
302
|
+
variant="outline"
|
|
303
|
+
className="h-4 rounded-sm border-border/70 bg-muted/40 px-1 font-mono text-[9px] font-medium lowercase leading-none tracking-[0.02em] text-muted-foreground"
|
|
304
|
+
>
|
|
305
|
+
{role.slug}
|
|
306
|
+
</Badge>
|
|
307
|
+
) : null}
|
|
308
|
+
</TableCell>
|
|
309
|
+
<TableCell className="px-2 py-1.5 align-middle">
|
|
310
|
+
<div className="flex justify-end">
|
|
311
|
+
<Switch
|
|
312
|
+
id={`role-${role.id}`}
|
|
313
|
+
checked={role.isAssigned}
|
|
314
|
+
disabled={isToggling || isDisabled}
|
|
315
|
+
onCheckedChange={() =>
|
|
316
|
+
handleToggleRole(role.id!, role.isAssigned)
|
|
317
|
+
}
|
|
318
|
+
className="scale-90 origin-center"
|
|
319
|
+
/>
|
|
320
|
+
</div>
|
|
321
|
+
</TableCell>
|
|
322
|
+
</TableRow>
|
|
323
|
+
);
|
|
324
|
+
})}
|
|
325
|
+
</TableBody>
|
|
326
|
+
</Table>
|
|
273
327
|
</div>
|
|
274
328
|
)}
|
|
275
329
|
|
|
@@ -203,32 +203,34 @@ export function UserAccessSheet({
|
|
|
203
203
|
<div className="w-full border-t" />
|
|
204
204
|
|
|
205
205
|
<Tabs defaultValue="menu" className="px-6 pt-4">
|
|
206
|
-
<
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
206
|
+
<div className="sticky top-0 z-20 -mx-6 bg-background/95 px-6 backdrop-blur supports-backdrop-filter:bg-background/80">
|
|
207
|
+
<TabsList className="mb-4 w-full">
|
|
208
|
+
<TabsTrigger
|
|
209
|
+
value="menu"
|
|
210
|
+
className="flex-1 flex items-center gap-2"
|
|
211
|
+
>
|
|
212
|
+
<Menu className="h-4 w-4" />
|
|
213
|
+
{t('accessTabMenu')}
|
|
214
|
+
{!loadingMenus && (
|
|
215
|
+
<Badge variant="secondary" className="ml-1 text-xs">
|
|
216
|
+
{menus.length}
|
|
217
|
+
</Badge>
|
|
218
|
+
)}
|
|
219
|
+
</TabsTrigger>
|
|
220
|
+
<TabsTrigger
|
|
221
|
+
value="routes"
|
|
222
|
+
className="flex-1 flex items-center gap-2"
|
|
223
|
+
>
|
|
224
|
+
<Globe className="h-4 w-4" />
|
|
225
|
+
{t('accessTabRoutes')}
|
|
226
|
+
{!loadingRoutes && (
|
|
227
|
+
<Badge variant="secondary" className="ml-1 text-xs">
|
|
228
|
+
{routes.length}
|
|
229
|
+
</Badge>
|
|
230
|
+
)}
|
|
231
|
+
</TabsTrigger>
|
|
232
|
+
</TabsList>
|
|
233
|
+
</div>
|
|
232
234
|
|
|
233
235
|
<TabsContent value="menu" className="mt-0">
|
|
234
236
|
{loadingMenus ? (
|