@hed-hog/core 0.0.327 → 0.0.329
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/ai/ai.service.d.ts +1 -1
- package/dist/auth/auth.controller.d.ts +2 -2
- package/dist/auth/auth.service.d.ts +2 -2
- package/dist/core/system.controller.d.ts +1 -1
- package/dist/core/system.service.d.ts +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +4 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +21 -21
- package/dist/dashboard/dashboard/dashboard.service.d.ts +21 -21
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +11 -11
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +11 -11
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +5 -5
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +5 -5
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +4 -4
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +4 -4
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +4 -4
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +4 -4
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +3 -3
- package/dist/file/file.controller.d.ts +6 -6
- package/dist/file/file.service.d.ts +12 -12
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/mail/mail.controller.d.ts +2 -2
- package/dist/mail/mail.service.d.ts +2 -2
- package/dist/mail-sent/mail-sent.controller.d.ts +3 -3
- package/dist/mail-sent/mail-sent.service.d.ts +3 -3
- package/dist/mcp/decorators/mcp-tool.decorator.d.ts +4 -0
- package/dist/mcp/decorators/mcp-tool.decorator.d.ts.map +1 -0
- package/dist/mcp/decorators/mcp-tool.decorator.js +8 -0
- package/dist/mcp/decorators/mcp-tool.decorator.js.map +1 -0
- package/dist/mcp/guards/mcp-auth.guard.d.ts +9 -0
- package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -0
- package/dist/mcp/guards/mcp-auth.guard.js +41 -0
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -0
- package/dist/mcp/guards/mcp-permission.guard.d.ts +8 -0
- package/dist/mcp/guards/mcp-permission.guard.d.ts.map +1 -0
- package/dist/mcp/guards/mcp-permission.guard.js +57 -0
- package/dist/mcp/guards/mcp-permission.guard.js.map +1 -0
- package/dist/mcp/interfaces/mcp-tool-definition.interface.d.ts +7 -0
- package/dist/mcp/interfaces/mcp-tool-definition.interface.d.ts.map +1 -0
- package/dist/mcp/interfaces/mcp-tool-definition.interface.js +3 -0
- package/dist/mcp/interfaces/mcp-tool-definition.interface.js.map +1 -0
- package/dist/mcp/mcp-audit.service.d.ts +17 -0
- package/dist/mcp/mcp-audit.service.d.ts.map +1 -0
- package/dist/mcp/mcp-audit.service.js +46 -0
- package/dist/mcp/mcp-audit.service.js.map +1 -0
- package/dist/mcp/mcp-registry.service.d.ts +21 -0
- package/dist/mcp/mcp-registry.service.d.ts.map +1 -0
- package/dist/mcp/mcp-registry.service.js +69 -0
- package/dist/mcp/mcp-registry.service.js.map +1 -0
- package/dist/mcp/mcp-server.service.d.ts +12 -0
- package/dist/mcp/mcp-server.service.d.ts.map +1 -0
- package/dist/mcp/mcp-server.service.js +94 -0
- package/dist/mcp/mcp-server.service.js.map +1 -0
- package/dist/mcp/mcp.controller.d.ts +8 -0
- package/dist/mcp/mcp.controller.d.ts.map +1 -0
- package/dist/mcp/mcp.controller.js +54 -0
- package/dist/mcp/mcp.controller.js.map +1 -0
- package/dist/mcp/mcp.module.d.ts +3 -0
- package/dist/mcp/mcp.module.d.ts.map +1 -0
- package/dist/mcp/mcp.module.js +49 -0
- package/dist/mcp/mcp.module.js.map +1 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts +12 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-settings.mcp-tools.js +66 -0
- package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-users.mcp-tools.d.ts +55 -0
- package/dist/mcp/tools/core-users.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-users.mcp-tools.js +295 -0
- package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -0
- package/dist/mcp/types/mcp-context.type.d.ts +7 -0
- package/dist/mcp/types/mcp-context.type.d.ts.map +1 -0
- package/dist/mcp/types/mcp-context.type.js +3 -0
- package/dist/mcp/types/mcp-context.type.js.map +1 -0
- package/dist/mcp-chat/dto/create-conversation.dto.d.ts +4 -0
- package/dist/mcp-chat/dto/create-conversation.dto.d.ts.map +1 -0
- package/dist/mcp-chat/dto/create-conversation.dto.js +22 -0
- package/dist/mcp-chat/dto/create-conversation.dto.js.map +1 -0
- package/dist/mcp-chat/dto/send-message.dto.d.ts +4 -0
- package/dist/mcp-chat/dto/send-message.dto.d.ts.map +1 -0
- package/dist/mcp-chat/dto/send-message.dto.js +22 -0
- package/dist/mcp-chat/dto/send-message.dto.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts +55 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.js +90 -0
- package/dist/mcp-chat/mcp-chat.controller.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.module.d.ts +3 -0
- package/dist/mcp-chat/mcp-chat.module.d.ts.map +1 -0
- package/dist/mcp-chat/mcp-chat.module.js +30 -0
- package/dist/mcp-chat/mcp-chat.module.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.service.d.ts +50 -0
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -0
- package/dist/mcp-chat/mcp-chat.service.js +290 -0
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -0
- package/dist/menu/menu.controller.d.ts +3 -3
- package/dist/menu/menu.service.d.ts +3 -3
- package/dist/profile/profile.controller.d.ts +2 -2
- package/dist/profile/profile.service.d.ts +2 -2
- package/dist/route/dto/create.dto.d.ts +6 -2
- package/dist/route/dto/create.dto.d.ts.map +1 -1
- package/dist/route/dto/create.dto.js +19 -1
- package/dist/route/dto/create.dto.js.map +1 -1
- package/dist/route/dto/update.dto.d.ts +4 -0
- package/dist/route/dto/update.dto.d.ts.map +1 -1
- package/dist/route/dto/update.dto.js +19 -3
- package/dist/route/dto/update.dto.js.map +1 -1
- package/dist/route/route.service.d.ts +1 -1
- package/dist/route/route.service.d.ts.map +1 -1
- package/dist/route/route.service.js +18 -11
- package/dist/route/route.service.js.map +1 -1
- package/dist/setting/setting.controller.d.ts +5 -5
- package/dist/setting/setting.service.d.ts +5 -5
- package/dist/user/user.controller.d.ts +3 -3
- package/dist/user/user.service.d.ts +6 -6
- package/hedhog/data/menu.yaml +40 -26
- package/hedhog/data/route.yaml +575 -152
- package/hedhog/data/setting_group.yaml +1 -1
- package/hedhog/frontend/app/configurations/[slug]/page.tsx.ejs +8 -1
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +152 -34
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +574 -0
- package/hedhog/frontend/messages/en.json +17 -0
- package/hedhog/frontend/messages/pt.json +17 -0
- package/hedhog/table/mcp_conversation.yaml +12 -0
- package/hedhog/table/mcp_conversation_message.yaml +23 -0
- package/hedhog/table/mcp_tool_call_log.yaml +22 -0
- package/hedhog/table/route.yaml +33 -22
- package/package.json +5 -4
- package/src/core.module.ts +14 -10
- package/src/index.ts +17 -10
- package/src/mcp/decorators/mcp-tool.decorator.ts +7 -0
- package/src/mcp/guards/mcp-auth.guard.ts +32 -0
- package/src/mcp/guards/mcp-permission.guard.ts +51 -0
- package/src/mcp/interfaces/mcp-tool-definition.interface.ts +6 -0
- package/src/mcp/mcp-audit.service.ts +36 -0
- package/src/mcp/mcp-registry.service.ts +69 -0
- package/src/mcp/mcp-server.service.ts +87 -0
- package/src/mcp/mcp.controller.ts +30 -0
- package/src/mcp/mcp.module.ts +36 -0
- package/src/mcp/tools/core-settings.mcp-tools.ts +53 -0
- package/src/mcp/tools/core-users.mcp-tools.ts +267 -0
- package/src/mcp/types/mcp-context.type.ts +6 -0
- package/src/mcp-chat/dto/create-conversation.dto.ts +7 -0
- package/src/mcp-chat/dto/send-message.dto.ts +7 -0
- package/src/mcp-chat/mcp-chat.controller.ts +60 -0
- package/src/mcp-chat/mcp-chat.module.ts +17 -0
- package/src/mcp-chat/mcp-chat.service.ts +332 -0
- package/src/route/dto/create.dto.ts +32 -14
- package/src/route/dto/update.dto.ts +31 -16
- package/src/route/route.service.ts +23 -12
|
@@ -1410,7 +1410,7 @@
|
|
|
1410
1410
|
icon: folder
|
|
1411
1411
|
name:
|
|
1412
1412
|
en: File Storage
|
|
1413
|
-
pt:
|
|
1413
|
+
pt: Arquivos
|
|
1414
1414
|
description:
|
|
1415
1415
|
en: Configure file storage backend, accepted file types, and size limits for uploads
|
|
1416
1416
|
pt: Configure backend de armazenamento de arquivos, tipos de arquivo aceitos e limites de tamanho para uploads
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { Badge } from '@/components/ui/badge';
|
|
3
4
|
import {
|
|
4
5
|
Card,
|
|
5
6
|
CardContent,
|
|
@@ -143,7 +144,7 @@ export default function Page() {
|
|
|
143
144
|
{section.settings.map((setting: Setting) => (
|
|
144
145
|
<div
|
|
145
146
|
key={setting.id}
|
|
146
|
-
className="flex min-w-0 flex-col gap-3 border-b border-border pb-4 last:border-0 last:pb-0 md:flex-row md:items-center md:justify-between md:gap-4"
|
|
147
|
+
className="group flex min-w-0 flex-col gap-3 border-b border-border pb-4 last:border-0 last:pb-0 md:flex-row md:items-center md:justify-between md:gap-4"
|
|
147
148
|
>
|
|
148
149
|
<div className="min-w-0 flex-1">
|
|
149
150
|
<label className="block font-semibold">
|
|
@@ -151,6 +152,12 @@ export default function Page() {
|
|
|
151
152
|
</label>
|
|
152
153
|
<p className="text-muted-foreground text-sm wrap-break-word">
|
|
153
154
|
{setting.description}
|
|
155
|
+
<Badge
|
|
156
|
+
variant="outline"
|
|
157
|
+
className="ml-1 align-middle font-mono text-xs opacity-0 transition-opacity group-hover:opacity-100"
|
|
158
|
+
>
|
|
159
|
+
{setting.slug}
|
|
160
|
+
</Badge>
|
|
154
161
|
</p>
|
|
155
162
|
</div>
|
|
156
163
|
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
DropdownMenuItem,
|
|
19
19
|
DropdownMenuTrigger,
|
|
20
20
|
} from '@/components/ui/dropdown-menu';
|
|
21
|
-
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area';
|
|
22
21
|
import {
|
|
23
22
|
Select,
|
|
24
23
|
SelectContent,
|
|
@@ -30,7 +29,7 @@ import { cn } from '@/lib/utils';
|
|
|
30
29
|
import { PaginatedResult } from '@/types/pagination-result';
|
|
31
30
|
import { SettingGroup } from '@hed-hog/api-types';
|
|
32
31
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
33
|
-
import { Download, MenuIcon, Upload } from 'lucide-react';
|
|
32
|
+
import { Check, ChevronDown, Download, MenuIcon, Upload } from 'lucide-react';
|
|
34
33
|
import { useTranslations } from 'next-intl';
|
|
35
34
|
import Link from 'next/link';
|
|
36
35
|
import { usePathname, useRouter } from 'next/navigation';
|
|
@@ -71,7 +70,10 @@ export default function ConfigurationsLayout({ children }: IProps) {
|
|
|
71
70
|
const [importDialogOpen, setImportDialogOpen] = useState(false);
|
|
72
71
|
const [importData, setImportData] = useState<SettingsValidation | null>(null);
|
|
73
72
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
74
|
-
const
|
|
73
|
+
const navContainerRef = useRef<HTMLDivElement>(null);
|
|
74
|
+
const tabRefs = useRef<(HTMLAnchorElement | null)[]>([]);
|
|
75
|
+
const tabWidths = useRef<number[]>([]);
|
|
76
|
+
const [visibleCount, setVisibleCount] = useState(Infinity);
|
|
75
77
|
|
|
76
78
|
const groups = settingGroups?.data || [];
|
|
77
79
|
const activeGroup = groups.find(
|
|
@@ -79,16 +81,50 @@ export default function ConfigurationsLayout({ children }: IProps) {
|
|
|
79
81
|
);
|
|
80
82
|
|
|
81
83
|
useEffect(() => {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
);
|
|
84
|
+
const container = navContainerRef.current;
|
|
85
|
+
if (!container) return;
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
const OVERFLOW_BTN_WIDTH = 96;
|
|
88
|
+
const GAP_WIDTH = 8;
|
|
89
|
+
|
|
90
|
+
const calculate = () => {
|
|
91
|
+
const available = container.clientWidth;
|
|
92
|
+
|
|
93
|
+
tabRefs.current.forEach((el, idx) => {
|
|
94
|
+
if (el && el.offsetWidth > 0) {
|
|
95
|
+
tabWidths.current[idx] = el.offsetWidth;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const total = groups.length;
|
|
100
|
+
if (total === 0) return;
|
|
101
|
+
|
|
102
|
+
let used = 0;
|
|
103
|
+
let count = 0;
|
|
104
|
+
|
|
105
|
+
for (let i = 0; i < total; i++) {
|
|
106
|
+
const w = (tabWidths.current[i] ?? 100) + (count > 0 ? GAP_WIDTH : 0);
|
|
107
|
+
const allFit = count + 1 === total;
|
|
108
|
+
const budget = allFit
|
|
109
|
+
? available
|
|
110
|
+
: available - OVERFLOW_BTN_WIDTH - GAP_WIDTH;
|
|
111
|
+
|
|
112
|
+
if (used + w <= budget) {
|
|
113
|
+
used += w;
|
|
114
|
+
count++;
|
|
115
|
+
} else {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
setVisibleCount(count);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const observer = new ResizeObserver(calculate);
|
|
124
|
+
observer.observe(container);
|
|
125
|
+
calculate();
|
|
126
|
+
return () => observer.disconnect();
|
|
127
|
+
}, [groups.length]);
|
|
92
128
|
|
|
93
129
|
const handleExport = (includeSecrets: boolean) => {
|
|
94
130
|
request<Blob>({
|
|
@@ -170,6 +206,31 @@ export default function ConfigurationsLayout({ children }: IProps) {
|
|
|
170
206
|
}
|
|
171
207
|
}, [importData, request, refetch, showToastHandler, t]);
|
|
172
208
|
|
|
209
|
+
const activeIndex = groups.findIndex(
|
|
210
|
+
(item) => pathname === `/core/configurations/${item.slug}`
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const rawVisible = isFinite(visibleCount)
|
|
214
|
+
? Math.min(Math.max(0, visibleCount), groups.length)
|
|
215
|
+
: groups.length;
|
|
216
|
+
|
|
217
|
+
let visibleIdxs: number[];
|
|
218
|
+
if (rawVisible >= groups.length) {
|
|
219
|
+
visibleIdxs = groups.map((_, i) => i);
|
|
220
|
+
} else {
|
|
221
|
+
visibleIdxs = Array.from({ length: rawVisible }, (_, i) => i);
|
|
222
|
+
if (activeIndex >= rawVisible && activeIndex >= 0) {
|
|
223
|
+
visibleIdxs[rawVisible - 1] = activeIndex;
|
|
224
|
+
visibleIdxs.sort((a, b) => a - b);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const visibleSet = new Set(visibleIdxs);
|
|
229
|
+
const overflowIdxs = groups
|
|
230
|
+
.map((_, i) => i)
|
|
231
|
+
.filter((i) => !visibleSet.has(i));
|
|
232
|
+
const activeInOverflow = activeIndex >= 0 && !visibleSet.has(activeIndex);
|
|
233
|
+
|
|
173
234
|
return (
|
|
174
235
|
<div className="flex min-w-0 flex-col overflow-x-hidden px-4">
|
|
175
236
|
<PageHeader
|
|
@@ -329,36 +390,93 @@ export default function ConfigurationsLayout({ children }: IProps) {
|
|
|
329
390
|
</Select>
|
|
330
391
|
</div>
|
|
331
392
|
|
|
332
|
-
<div className="hidden min-w-0
|
|
333
|
-
<
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
pathname === `/core/configurations/${item.slug}`;
|
|
393
|
+
<div className="hidden min-w-0 md:block">
|
|
394
|
+
<nav
|
|
395
|
+
ref={navContainerRef}
|
|
396
|
+
className="flex w-full items-end gap-2"
|
|
397
|
+
aria-label="Configuration tabs"
|
|
398
|
+
>
|
|
399
|
+
{groups.map((item: SettingGroup, idx: number) => {
|
|
400
|
+
const isActive = idx === activeIndex;
|
|
401
|
+
const isOverflow = !visibleSet.has(idx);
|
|
342
402
|
|
|
403
|
+
if (isOverflow) {
|
|
343
404
|
return (
|
|
344
|
-
<
|
|
405
|
+
<span
|
|
345
406
|
key={item.slug}
|
|
346
|
-
|
|
347
|
-
|
|
407
|
+
ref={(el) => {
|
|
408
|
+
tabRefs.current[idx] =
|
|
409
|
+
el as unknown as HTMLAnchorElement;
|
|
410
|
+
}}
|
|
411
|
+
aria-hidden="true"
|
|
412
|
+
className="invisible absolute shrink-0 whitespace-nowrap px-3 py-3 text-sm font-medium"
|
|
413
|
+
>
|
|
414
|
+
{item.name}
|
|
415
|
+
</span>
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<Link
|
|
421
|
+
key={item.slug}
|
|
422
|
+
href={item.slug}
|
|
423
|
+
ref={(el) => {
|
|
424
|
+
tabRefs.current[idx] = el;
|
|
425
|
+
}}
|
|
426
|
+
data-active={isActive}
|
|
427
|
+
className={cn(
|
|
428
|
+
'shrink-0 border-b-2 px-3 py-3 text-sm font-medium whitespace-nowrap transition-colors',
|
|
429
|
+
isActive
|
|
430
|
+
? 'border-primary text-primary'
|
|
431
|
+
: 'border-transparent text-muted-foreground hover:text-foreground hover:border-muted-foreground'
|
|
432
|
+
)}
|
|
433
|
+
>
|
|
434
|
+
{item.name}
|
|
435
|
+
</Link>
|
|
436
|
+
);
|
|
437
|
+
})}
|
|
438
|
+
|
|
439
|
+
{overflowIdxs.length > 0 && (
|
|
440
|
+
<DropdownMenu>
|
|
441
|
+
<DropdownMenuTrigger asChild>
|
|
442
|
+
<Button
|
|
443
|
+
variant="ghost"
|
|
348
444
|
className={cn(
|
|
349
|
-
'shrink-0 border-b-2 px-3 py-3 text-sm font-medium whitespace-nowrap transition-colors',
|
|
350
|
-
|
|
445
|
+
'ml-auto h-auto shrink-0 cursor-pointer rounded-none border-b-2 px-3 py-3 text-sm font-medium whitespace-nowrap transition-colors',
|
|
446
|
+
activeInOverflow
|
|
351
447
|
? 'border-primary text-primary'
|
|
352
448
|
: 'border-transparent text-muted-foreground hover:text-foreground hover:border-muted-foreground'
|
|
353
449
|
)}
|
|
354
450
|
>
|
|
355
|
-
{
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
451
|
+
{overflowIdxs.length} mais
|
|
452
|
+
<ChevronDown className="ml-1 h-3 w-3" />
|
|
453
|
+
</Button>
|
|
454
|
+
</DropdownMenuTrigger>
|
|
455
|
+
<DropdownMenuContent align="end">
|
|
456
|
+
{overflowIdxs.map((idx) => {
|
|
457
|
+
const item = groups[idx];
|
|
458
|
+
if (!item) return null;
|
|
459
|
+
const isActive = idx === activeIndex;
|
|
460
|
+
return (
|
|
461
|
+
<DropdownMenuItem
|
|
462
|
+
key={item.slug}
|
|
463
|
+
onClick={() =>
|
|
464
|
+
router.push(`/core/configurations/${item.slug}`)
|
|
465
|
+
}
|
|
466
|
+
className={cn(
|
|
467
|
+
'cursor-pointer',
|
|
468
|
+
isActive && 'text-primary'
|
|
469
|
+
)}
|
|
470
|
+
>
|
|
471
|
+
{item.name}
|
|
472
|
+
{isActive && <Check className="ml-auto h-4 w-4" />}
|
|
473
|
+
</DropdownMenuItem>
|
|
474
|
+
);
|
|
475
|
+
})}
|
|
476
|
+
</DropdownMenuContent>
|
|
477
|
+
</DropdownMenu>
|
|
478
|
+
)}
|
|
479
|
+
</nav>
|
|
362
480
|
</div>
|
|
363
481
|
</div>
|
|
364
482
|
</div>
|