@hed-hog/core 0.0.370 → 0.0.373
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/LICENSE.md +21 -0
- package/README.md +2 -0
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +10 -7
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/app-command/app-command.module.d.ts +3 -0
- package/dist/app-command/app-command.module.d.ts.map +1 -0
- package/dist/app-command/app-command.module.js +22 -0
- package/dist/app-command/app-command.module.js.map +1 -0
- package/dist/app-command/app-command.registry.d.ts +22 -0
- package/dist/app-command/app-command.registry.d.ts.map +1 -0
- package/dist/{webhook-integration/webhook-command.registry.js → app-command/app-command.registry.js} +6 -6
- package/dist/app-command/app-command.registry.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +2 -2
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +20 -7
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.service.d.ts +3 -3
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +10 -36
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/auth/dto/forget.dto.d.ts +1 -0
- package/dist/auth/dto/forget.dto.d.ts.map +1 -1
- package/dist/auth/dto/forget.dto.js +5 -0
- package/dist/auth/dto/forget.dto.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +4 -1
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +8 -7
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +27 -19
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/file/dto/upload.dto.d.ts +3 -0
- package/dist/file/dto/upload.dto.d.ts.map +1 -1
- package/dist/file/dto/upload.dto.js +22 -0
- package/dist/file/dto/upload.dto.js.map +1 -1
- package/dist/file/file.controller.d.ts +2 -1
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +29 -16
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +51 -1
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +250 -18
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/image-optimization.service.d.ts +17 -4
- package/dist/file/image-optimization.service.d.ts.map +1 -1
- package/dist/file/image-optimization.service.js +101 -46
- package/dist/file/image-optimization.service.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +15 -7
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/file/provider/spaces.provider.d.ts.map +1 -1
- package/dist/file/provider/spaces.provider.js +18 -8
- package/dist/file/provider/spaces.provider.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/integration/services/event-subscriber.registry.d.ts +5 -0
- package/dist/integration/services/event-subscriber.registry.d.ts.map +1 -1
- package/dist/integration/services/event-subscriber.registry.js +15 -0
- package/dist/integration/services/event-subscriber.registry.js.map +1 -1
- package/dist/integration/services/outbox.processor.d.ts.map +1 -1
- package/dist/integration/services/outbox.processor.js +2 -4
- package/dist/integration/services/outbox.processor.js.map +1 -1
- package/dist/integration/services/outbox.service.d.ts +4 -2
- package/dist/integration/services/outbox.service.d.ts.map +1 -1
- package/dist/integration/services/outbox.service.js +26 -15
- package/dist/integration/services/outbox.service.js.map +1 -1
- package/dist/integration-profile/integration-credential-crypto.service.d.ts +43 -0
- package/dist/integration-profile/integration-credential-crypto.service.d.ts.map +1 -0
- package/dist/integration-profile/integration-credential-crypto.service.js +142 -0
- package/dist/integration-profile/integration-credential-crypto.service.js.map +1 -0
- package/dist/integration-profile/integration-profile.controller.d.ts +6 -7
- package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.controller.js +4 -3
- package/dist/integration-profile/integration-profile.controller.js.map +1 -1
- package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.module.js +5 -2
- package/dist/integration-profile/integration-profile.module.js.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.d.ts +16 -0
- package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -0
- package/dist/integration-profile/integration-profile.secrets.js +56 -0
- package/dist/integration-profile/integration-profile.secrets.js.map +1 -0
- package/dist/integration-profile/integration-profile.service.d.ts +125 -8
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +257 -68
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.d.ts +17 -0
- package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +31 -0
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/language/en.json +178 -0
- package/dist/language/pt.json +178 -0
- package/dist/mail/mail.controller.d.ts.map +1 -1
- package/dist/mail/mail.controller.js +5 -28
- package/dist/mail/mail.controller.js.map +1 -1
- package/dist/mail/mail.module.js +18 -18
- package/dist/mail/mail.module.js.map +1 -1
- package/dist/mail/mail.service.d.ts +13 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +25 -15
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +6 -5
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/oauth/providers/facebook.provider.js +5 -5
- package/dist/oauth/providers/facebook.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.js +5 -5
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/google.provider.js +5 -5
- package/dist/oauth/providers/google.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +5 -5
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft.provider.js +5 -5
- package/dist/oauth/providers/microsoft.provider.js.map +1 -1
- package/dist/pdf/pdf.service.d.ts +4 -0
- package/dist/pdf/pdf.service.d.ts.map +1 -1
- package/dist/pdf/pdf.service.js +16 -9
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +7 -7
- package/dist/profile/profile.controller.d.ts.map +1 -1
- package/dist/profile/profile.controller.js +28 -21
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/profile/profile.service.d.ts +7 -7
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +21 -25
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +1 -0
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +15 -2
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +2 -1
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +9 -0
- package/dist/user/user.controller.d.ts.map +1 -1
- package/dist/user/user.controller.js +13 -0
- package/dist/user/user.controller.js.map +1 -1
- package/dist/user/user.service.d.ts +7 -0
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +19 -0
- package/dist/user/user.service.js.map +1 -1
- package/dist/utils/webauthn-origin.d.ts +11 -0
- package/dist/utils/webauthn-origin.d.ts.map +1 -0
- package/dist/utils/webauthn-origin.js +37 -0
- package/dist/utils/webauthn-origin.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +13 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +29 -0
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.module.js +3 -3
- package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +18 -2
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +110 -6
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/hedhog/data/integration_provider.yaml +9 -0
- package/hedhog/data/integration_type.yaml +6 -0
- package/hedhog/data/menu.yaml +6 -0
- package/hedhog/data/role.yaml +7 -0
- package/hedhog/data/route.yaml +36 -0
- package/hedhog/data/setting_group.yaml +119 -13
- package/hedhog/frontend/app/access-log/page.tsx.ejs +35 -3
- package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +36 -3
- package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +39 -4
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +39 -4
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +35 -2
- package/hedhog/frontend/app/configurations/[slug]/components/byte-size-input.tsx.ejs +160 -0
- package/hedhog/frontend/app/configurations/[slug]/components/duration-input.tsx.ejs +157 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +244 -63
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +33 -1
- package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +35 -3
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +36 -4
- package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +35 -3
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +36 -4
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +35 -3
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +156 -38
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +118 -11
- package/hedhog/frontend/app/mail/log/page.tsx.ejs +37 -4
- package/hedhog/frontend/app/menu/page.tsx.ejs +34 -2
- package/hedhog/frontend/app/preferences/page.tsx.ejs +77 -0
- package/hedhog/frontend/app/roles/menus.tsx.ejs +35 -3
- package/hedhog/frontend/app/roles/page.tsx.ejs +34 -2
- package/hedhog/frontend/app/roles/routes.tsx.ejs +36 -4
- package/hedhog/frontend/app/roles/users.tsx.ejs +36 -4
- package/hedhog/frontend/app/routes/page.tsx.ejs +34 -2
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +34 -2
- package/hedhog/frontend/app/users/page.tsx.ejs +51 -21
- package/hedhog/frontend/messages/en.json +69 -4
- package/hedhog/frontend/messages/pt.json +69 -4
- package/hedhog/table/setting.yaml +2 -0
- package/hedhog/table/webhook_call_log.yaml +49 -46
- package/package.json +9 -4
- package/src/ai/ai.service.ts +9 -6
- package/src/app-command/app-command.module.ts +9 -0
- package/src/{webhook-integration/webhook-command.registry.ts → app-command/app-command.registry.ts} +9 -9
- package/src/auth/auth.controller.ts +20 -4
- package/src/auth/auth.service.ts +10 -36
- package/src/auth/dto/forget.dto.ts +5 -1
- package/src/auth/guards/auth.guard.ts +4 -1
- package/src/challenge/challenge.service.ts +30 -19
- package/src/file/dto/upload.dto.ts +25 -1
- package/src/file/file.controller.ts +31 -18
- package/src/file/file.service.ts +341 -16
- package/src/file/image-optimization.service.ts +111 -46
- package/src/file/provider/s3.provider.ts +16 -7
- package/src/file/provider/spaces.provider.ts +15 -5
- package/src/index.ts +4 -1
- package/src/integration/services/event-subscriber.registry.ts +15 -0
- package/src/integration/services/outbox.processor.ts +2 -5
- package/src/integration/services/outbox.service.ts +35 -17
- package/src/integration-profile/integration-credential-crypto.service.ts +146 -0
- package/src/integration-profile/integration-profile.controller.ts +2 -0
- package/src/integration-profile/integration-profile.module.ts +5 -2
- package/src/integration-profile/integration-profile.secrets.ts +51 -0
- package/src/integration-profile/integration-profile.service.ts +335 -54
- package/src/integration-profile/integration-profile.utils.ts +56 -0
- package/src/language/en.json +5 -1
- package/src/language/pt.json +5 -1
- package/src/mail/mail.controller.ts +5 -29
- package/src/mail/mail.module.ts +5 -5
- package/src/mail/mail.service.ts +37 -13
- package/src/mcp-chat/mcp-chat.service.ts +5 -5
- package/src/oauth/oauth-callback-coordinator.service.spec.ts +159 -0
- package/src/oauth/providers/facebook.provider.ts +3 -3
- package/src/oauth/providers/github.provider.ts +3 -3
- package/src/oauth/providers/google.provider.ts +3 -3
- package/src/oauth/providers/microsoft-entra-id.provider.ts +3 -3
- package/src/oauth/providers/microsoft.provider.ts +3 -3
- package/src/pdf/pdf.service.ts +19 -6
- package/src/profile/profile.controller.ts +21 -14
- package/src/profile/profile.service.ts +23 -20
- package/src/security/security.service.spec.ts +222 -0
- package/src/setting/setting.service.ts +15 -2
- package/src/token/token.service.ts +2 -1
- package/src/user/user.controller.ts +26 -16
- package/src/user/user.service.ts +25 -0
- package/src/utils/webauthn-origin.ts +38 -0
- package/src/webhook-integration/webhook-integration.controller.ts +23 -0
- package/src/webhook-integration/webhook-integration.module.ts +3 -3
- package/src/webhook-integration/webhook-integration.service.ts +115 -5
- package/dist/webhook-integration/webhook-command.registry.d.ts +0 -22
- package/dist/webhook-integration/webhook-command.registry.d.ts.map +0 -1
- package/dist/webhook-integration/webhook-command.registry.js.map +0 -1
- package/src/menu/menu.service.spec.ts +0 -247
- package/src/route/route.service.spec.ts +0 -300
- package/src/screen/screen.service.spec.ts +0 -298
- package/src/user/user.service.spec.ts +0 -294
|
@@ -505,12 +505,43 @@ function getPublicWebhookUrl(uuid: string, publicUrl?: string | null) {
|
|
|
505
505
|
return `${baseUrl.replace(/\/+$/, '')}/webhook/${uuid}`;
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
+
const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
|
|
509
|
+
|
|
508
510
|
export default function IntegrationsWebhooksPage() {
|
|
509
511
|
const t = useTranslations('core.IntegrationsWebhooksPage');
|
|
510
512
|
const { request, currentLocaleCode, getSettingValue, locales, accessToken } =
|
|
511
513
|
useApp();
|
|
512
514
|
const queryClient = useQueryClient();
|
|
513
|
-
|
|
515
|
+
|
|
516
|
+
const { data: generalSettings } = useQuery<{
|
|
517
|
+
data: Array<{ slug: string; value: string }>;
|
|
518
|
+
}>({
|
|
519
|
+
queryKey: ['setting-group-general'],
|
|
520
|
+
queryFn: async () => {
|
|
521
|
+
const response = await request<{
|
|
522
|
+
data: Array<{ slug: string; value: string }>;
|
|
523
|
+
}>({ url: '/setting/group/general', method: 'GET' });
|
|
524
|
+
return response.data;
|
|
525
|
+
},
|
|
526
|
+
staleTime: 5 * 60 * 1000,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
const pageSizeOptions = useMemo(() => {
|
|
530
|
+
const setting = generalSettings?.data?.find(
|
|
531
|
+
(s) => s.slug === 'pagination-page-sizes'
|
|
532
|
+
);
|
|
533
|
+
if (!setting?.value) return DEFAULT_PAGE_SIZES;
|
|
534
|
+
try {
|
|
535
|
+
const parsed = JSON.parse(setting.value) as string[];
|
|
536
|
+
const sizes = parsed
|
|
537
|
+
.map(Number)
|
|
538
|
+
.filter((n) => !isNaN(n) && n > 0)
|
|
539
|
+
.sort((a, b) => a - b);
|
|
540
|
+
return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
|
|
541
|
+
} catch {
|
|
542
|
+
return DEFAULT_PAGE_SIZES;
|
|
543
|
+
}
|
|
544
|
+
}, [generalSettings]);
|
|
514
545
|
|
|
515
546
|
const catalog = usePagination({
|
|
516
547
|
url: '/integration-event-catalog',
|
|
@@ -566,6 +597,8 @@ export default function IntegrationsWebhooksPage() {
|
|
|
566
597
|
const [incomingLogsPageSize, setIncomingLogsPageSize] = useState(12);
|
|
567
598
|
const [logOrder, setLogOrder] = useState<'desc' | 'asc'>('desc');
|
|
568
599
|
const [selectedLog, setSelectedLog] = useState<IncomingCallLog | null>(null);
|
|
600
|
+
const [retryTarget, setRetryTarget] = useState<IncomingCallLog | null>(null);
|
|
601
|
+
const [isRetryingLog, setIsRetryingLog] = useState(false);
|
|
569
602
|
const sseAbortRef = useRef<AbortController | null>(null);
|
|
570
603
|
|
|
571
604
|
const [eventWebhookOpen, setEventWebhookOpen] = useState(false);
|
|
@@ -1467,6 +1500,32 @@ export default function IntegrationsWebhooksPage() {
|
|
|
1467
1500
|
await incoming.refetch();
|
|
1468
1501
|
};
|
|
1469
1502
|
|
|
1503
|
+
const retryIncomingLog = async (log: IncomingCallLog) => {
|
|
1504
|
+
if (!incomingEdit) return;
|
|
1505
|
+
setIsRetryingLog(true);
|
|
1506
|
+
try {
|
|
1507
|
+
const response = await request<{ success?: boolean }>({
|
|
1508
|
+
url: `/webhook-integration/${incomingEdit.id}/log/${log.id}/retry`,
|
|
1509
|
+
method: 'POST',
|
|
1510
|
+
});
|
|
1511
|
+
// A new call log is always created by the retry, so refresh the list.
|
|
1512
|
+
await queryClient.invalidateQueries({
|
|
1513
|
+
queryKey: ['incoming-webhook-logs', incomingEdit.id],
|
|
1514
|
+
});
|
|
1515
|
+
if (response.data?.success) {
|
|
1516
|
+
toast.success(t('logRetrySuccess'));
|
|
1517
|
+
} else {
|
|
1518
|
+
toast.error(t('logRetryFailedAgain'));
|
|
1519
|
+
}
|
|
1520
|
+
setSelectedLog(null);
|
|
1521
|
+
setRetryTarget(null);
|
|
1522
|
+
} catch {
|
|
1523
|
+
toast.error(t('logRetryError'));
|
|
1524
|
+
} finally {
|
|
1525
|
+
setIsRetryingLog(false);
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
|
|
1470
1529
|
const regenerateToken = async () => {
|
|
1471
1530
|
if (!incomingEdit) return;
|
|
1472
1531
|
const response = await request<IncomingIntegration>({
|
|
@@ -2011,7 +2070,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
2011
2070
|
</SheetTitle>
|
|
2012
2071
|
<SheetDescription>{t('eventFormDescription')}</SheetDescription>
|
|
2013
2072
|
</SheetHeader>
|
|
2014
|
-
<div className="space-y-4 px-3 pb-8 sm:px-4">
|
|
2073
|
+
<div className="min-h-0 flex-1 space-y-4 overflow-y-auto px-3 pb-8 sm:px-4">
|
|
2015
2074
|
<Field label={t('eventName')}>
|
|
2016
2075
|
<Input
|
|
2017
2076
|
value={catalogForm.name}
|
|
@@ -2092,7 +2151,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
2092
2151
|
<Tabs
|
|
2093
2152
|
value={incomingSheetTab}
|
|
2094
2153
|
onValueChange={setIncomingSheetTab}
|
|
2095
|
-
className="mt-4"
|
|
2154
|
+
className="mt-4 flex min-h-0 flex-1 flex-col"
|
|
2096
2155
|
>
|
|
2097
2156
|
<div className="px-3 sm:px-4">
|
|
2098
2157
|
<TabsList className="grid w-full grid-cols-3">
|
|
@@ -2110,7 +2169,10 @@ export default function IntegrationsWebhooksPage() {
|
|
|
2110
2169
|
</TabsTrigger>
|
|
2111
2170
|
</TabsList>
|
|
2112
2171
|
</div>
|
|
2113
|
-
<TabsContent
|
|
2172
|
+
<TabsContent
|
|
2173
|
+
value="settings"
|
|
2174
|
+
className="mt-0 min-h-0 flex-1 overflow-y-auto"
|
|
2175
|
+
>
|
|
2114
2176
|
<div className="space-y-6 px-3 pb-8 sm:px-4">
|
|
2115
2177
|
<div className="grid gap-4 md:grid-cols-2">
|
|
2116
2178
|
<Field label={t('name')}>
|
|
@@ -2352,7 +2414,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
2352
2414
|
|
|
2353
2415
|
<TabsContent
|
|
2354
2416
|
value="actions"
|
|
2355
|
-
className="mt-0 space-y-4 px-3 pb-8 sm:px-4"
|
|
2417
|
+
className="mt-0 min-h-0 flex-1 space-y-4 overflow-y-auto px-3 pb-8 sm:px-4"
|
|
2356
2418
|
>
|
|
2357
2419
|
{!incomingEdit ? (
|
|
2358
2420
|
<EmptyState
|
|
@@ -2433,7 +2495,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
2433
2495
|
|
|
2434
2496
|
<TabsContent
|
|
2435
2497
|
value="logs"
|
|
2436
|
-
className="mt-0 space-y-4 px-3 pb-8 sm:px-4"
|
|
2498
|
+
className="mt-0 min-h-0 flex-1 space-y-4 overflow-y-auto px-3 pb-8 sm:px-4"
|
|
2437
2499
|
>
|
|
2438
2500
|
{!incomingEdit ? (
|
|
2439
2501
|
<EmptyState
|
|
@@ -2583,7 +2645,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
2583
2645
|
</SheetTitle>
|
|
2584
2646
|
<SheetDescription>{t('actionSection')}</SheetDescription>
|
|
2585
2647
|
</SheetHeader>
|
|
2586
|
-
<div className="space-y-5 px-3 pb-8 sm:px-4">
|
|
2648
|
+
<div className="min-h-0 flex-1 space-y-5 overflow-y-auto px-3 pb-8 sm:px-4">
|
|
2587
2649
|
<div className="grid gap-3 md:grid-cols-3">
|
|
2588
2650
|
<Field label={t('actionType')}>
|
|
2589
2651
|
<Select
|
|
@@ -3358,7 +3420,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
3358
3420
|
{t('eventWebhookFormDescription')}
|
|
3359
3421
|
</SheetDescription>
|
|
3360
3422
|
</SheetHeader>
|
|
3361
|
-
<div className="space-y-5 px-3 pb-8 sm:px-4">
|
|
3423
|
+
<div className="min-h-0 flex-1 space-y-5 overflow-y-auto px-3 pb-8 sm:px-4">
|
|
3362
3424
|
<div className="grid gap-4 md:grid-cols-2">
|
|
3363
3425
|
<Field label={t('name')}>
|
|
3364
3426
|
<Input
|
|
@@ -3554,7 +3616,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
3554
3616
|
</SheetDescription>
|
|
3555
3617
|
</SheetHeader>
|
|
3556
3618
|
|
|
3557
|
-
<div className="space-y-6 px-3 pb-8 sm:px-4">
|
|
3619
|
+
<div className="min-h-0 flex-1 space-y-6 overflow-y-auto px-3 pb-8 sm:px-4">
|
|
3558
3620
|
<div className="grid gap-6 md:grid-cols-2">
|
|
3559
3621
|
<Field label={t('name')}>
|
|
3560
3622
|
<Input
|
|
@@ -3841,7 +3903,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
3841
3903
|
</SheetDescription>
|
|
3842
3904
|
</SheetHeader>
|
|
3843
3905
|
|
|
3844
|
-
<div className="space-y-6 px-3 pb-8 sm:px-4">
|
|
3906
|
+
<div className="min-h-0 flex-1 space-y-6 overflow-y-auto px-3 pb-8 sm:px-4">
|
|
3845
3907
|
<div className="grid gap-6 md:grid-cols-2">
|
|
3846
3908
|
<Field label={t('technicalName')}>
|
|
3847
3909
|
<Input
|
|
@@ -3942,7 +4004,7 @@ export default function IntegrationsWebhooksPage() {
|
|
|
3942
4004
|
</SheetHeader>
|
|
3943
4005
|
|
|
3944
4006
|
{selectedLog ? (
|
|
3945
|
-
<div className="space-y-6 px-3 pb-8 sm:px-4">
|
|
4007
|
+
<div className="min-h-0 flex-1 space-y-6 overflow-y-auto px-3 pb-8 sm:px-4">
|
|
3946
4008
|
<div className="flex flex-wrap gap-3 pt-2">
|
|
3947
4009
|
<Badge
|
|
3948
4010
|
variant="outline"
|
|
@@ -3964,6 +4026,21 @@ export default function IntegrationsWebhooksPage() {
|
|
|
3964
4026
|
</span>
|
|
3965
4027
|
</div>
|
|
3966
4028
|
|
|
4029
|
+
{selectedLog.status === 'failed' ? (
|
|
4030
|
+
<div>
|
|
4031
|
+
<Button
|
|
4032
|
+
type="button"
|
|
4033
|
+
variant="outline"
|
|
4034
|
+
size="sm"
|
|
4035
|
+
onClick={() => setRetryTarget(selectedLog)}
|
|
4036
|
+
disabled={isRetryingLog}
|
|
4037
|
+
>
|
|
4038
|
+
<RotateCcw className="mr-2 h-4 w-4" />
|
|
4039
|
+
{t('logRetry')}
|
|
4040
|
+
</Button>
|
|
4041
|
+
</div>
|
|
4042
|
+
) : null}
|
|
4043
|
+
|
|
3967
4044
|
{selectedLog.error_message ? (
|
|
3968
4045
|
<div>
|
|
3969
4046
|
<p className="mb-1 text-xs font-medium text-destructive">
|
|
@@ -4127,6 +4204,36 @@ export default function IntegrationsWebhooksPage() {
|
|
|
4127
4204
|
</AlertDialogFooter>
|
|
4128
4205
|
</AlertDialogContent>
|
|
4129
4206
|
</AlertDialog>
|
|
4207
|
+
|
|
4208
|
+
<AlertDialog
|
|
4209
|
+
open={Boolean(retryTarget)}
|
|
4210
|
+
onOpenChange={(open) => {
|
|
4211
|
+
if (!open && !isRetryingLog) setRetryTarget(null);
|
|
4212
|
+
}}
|
|
4213
|
+
>
|
|
4214
|
+
<AlertDialogContent>
|
|
4215
|
+
<AlertDialogHeader>
|
|
4216
|
+
<AlertDialogTitle>{t('logRetryConfirmTitle')}</AlertDialogTitle>
|
|
4217
|
+
<AlertDialogDescription>
|
|
4218
|
+
{t('logRetryConfirmDescription')}
|
|
4219
|
+
</AlertDialogDescription>
|
|
4220
|
+
</AlertDialogHeader>
|
|
4221
|
+
<AlertDialogFooter>
|
|
4222
|
+
<AlertDialogCancel disabled={isRetryingLog}>
|
|
4223
|
+
{t('cancel')}
|
|
4224
|
+
</AlertDialogCancel>
|
|
4225
|
+
<AlertDialogAction
|
|
4226
|
+
onClick={(event) => {
|
|
4227
|
+
event.preventDefault();
|
|
4228
|
+
if (retryTarget) retryIncomingLog(retryTarget);
|
|
4229
|
+
}}
|
|
4230
|
+
disabled={isRetryingLog}
|
|
4231
|
+
>
|
|
4232
|
+
{t('logRetry')}
|
|
4233
|
+
</AlertDialogAction>
|
|
4234
|
+
</AlertDialogFooter>
|
|
4235
|
+
</AlertDialogContent>
|
|
4236
|
+
</AlertDialog>
|
|
4130
4237
|
</Page>
|
|
4131
4238
|
);
|
|
4132
4239
|
}
|
|
@@ -97,6 +97,8 @@ type DeliveryStatusFilter = 'all' | 'received' | 'read' | 'error';
|
|
|
97
97
|
type HasErrorFilter = 'all' | 'true' | 'false';
|
|
98
98
|
type ViewMode = 'cards' | 'table';
|
|
99
99
|
|
|
100
|
+
const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
|
|
101
|
+
|
|
100
102
|
export default function MailLogPage() {
|
|
101
103
|
const t = useTranslations('core.MailLog');
|
|
102
104
|
const [selectedLog, setSelectedLog] = useState<MailSent | null>(null);
|
|
@@ -110,13 +112,44 @@ export default function MailLogPage() {
|
|
|
110
112
|
const [viewMode, setViewMode] = useState<ViewMode>('cards');
|
|
111
113
|
const debouncedSearch = useDebounce(searchTerm);
|
|
112
114
|
const debouncedRecipientEmail = useDebounce(recipientEmail);
|
|
115
|
+
const { request, getSettingValue } = useApp();
|
|
116
|
+
|
|
117
|
+
const { data: generalSettings } = useQuery<{
|
|
118
|
+
data: Array<{ slug: string; value: string }>;
|
|
119
|
+
}>({
|
|
120
|
+
queryKey: ['setting-group-general'],
|
|
121
|
+
queryFn: async () => {
|
|
122
|
+
const response = await request<{
|
|
123
|
+
data: Array<{ slug: string; value: string }>;
|
|
124
|
+
}>({ url: '/setting/group/general', method: 'GET' });
|
|
125
|
+
return response.data;
|
|
126
|
+
},
|
|
127
|
+
staleTime: 5 * 60 * 1000,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const pageSizeOptions = useMemo(() => {
|
|
131
|
+
const setting = generalSettings?.data?.find(
|
|
132
|
+
(s) => s.slug === 'pagination-page-sizes'
|
|
133
|
+
);
|
|
134
|
+
if (!setting?.value) return DEFAULT_PAGE_SIZES;
|
|
135
|
+
try {
|
|
136
|
+
const parsed = JSON.parse(setting.value) as string[];
|
|
137
|
+
const sizes = parsed
|
|
138
|
+
.map(Number)
|
|
139
|
+
.filter((n) => !isNaN(n) && n > 0)
|
|
140
|
+
.sort((a, b) => a - b);
|
|
141
|
+
return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
|
|
142
|
+
} catch {
|
|
143
|
+
return DEFAULT_PAGE_SIZES;
|
|
144
|
+
}
|
|
145
|
+
}, [generalSettings]);
|
|
146
|
+
|
|
113
147
|
const [page, setPage] = useState(1);
|
|
114
148
|
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
115
149
|
storageKey: 'pagination:global:pageSize',
|
|
116
|
-
defaultValue:
|
|
117
|
-
allowedValues:
|
|
150
|
+
defaultValue: 12,
|
|
151
|
+
allowedValues: pageSizeOptions,
|
|
118
152
|
});
|
|
119
|
-
const { request, getSettingValue } = useApp();
|
|
120
153
|
|
|
121
154
|
const {
|
|
122
155
|
data: logsResult,
|
|
@@ -559,7 +592,7 @@ export default function MailLogPage() {
|
|
|
559
592
|
setPageSize(newSize);
|
|
560
593
|
setPage(1);
|
|
561
594
|
}}
|
|
562
|
-
pageSizeOptions={
|
|
595
|
+
pageSizeOptions={pageSizeOptions}
|
|
563
596
|
/>
|
|
564
597
|
|
|
565
598
|
{selectedLog && (
|
|
@@ -1283,6 +1283,8 @@ const NO_PARENT = '__none__';
|
|
|
1283
1283
|
const MENU_CREATE_DRAFT_STORAGE_KEY = 'core-menu-create-draft';
|
|
1284
1284
|
const MENU_EDIT_DRAFT_STORAGE_KEY = 'core-menu-edit-draft';
|
|
1285
1285
|
|
|
1286
|
+
const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
|
|
1287
|
+
|
|
1286
1288
|
export default function MenuPage() {
|
|
1287
1289
|
const t = useTranslations('core.MenuPage');
|
|
1288
1290
|
const { request, currentLocaleCode, locales, getSettingValue } = useApp();
|
|
@@ -1298,10 +1300,40 @@ export default function MenuPage() {
|
|
|
1298
1300
|
const [isRefreshingMenu, setIsRefreshingMenu] = useState(false);
|
|
1299
1301
|
|
|
1300
1302
|
const [page, setPage] = useState(1);
|
|
1303
|
+
const { data: generalSettings } = useQuery<{
|
|
1304
|
+
data: Array<{ slug: string; value: string }>;
|
|
1305
|
+
}>({
|
|
1306
|
+
queryKey: ['setting-group-general'],
|
|
1307
|
+
queryFn: async () => {
|
|
1308
|
+
const response = await request<{
|
|
1309
|
+
data: Array<{ slug: string; value: string }>;
|
|
1310
|
+
}>({ url: '/setting/group/general', method: 'GET' });
|
|
1311
|
+
return response.data;
|
|
1312
|
+
},
|
|
1313
|
+
staleTime: 5 * 60 * 1000,
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
const pageSizeOptions = useMemo(() => {
|
|
1317
|
+
const setting = generalSettings?.data?.find(
|
|
1318
|
+
(s) => s.slug === 'pagination-page-sizes'
|
|
1319
|
+
);
|
|
1320
|
+
if (!setting?.value) return DEFAULT_PAGE_SIZES;
|
|
1321
|
+
try {
|
|
1322
|
+
const parsed = JSON.parse(setting.value) as string[];
|
|
1323
|
+
const sizes = parsed
|
|
1324
|
+
.map(Number)
|
|
1325
|
+
.filter((n) => !isNaN(n) && n > 0)
|
|
1326
|
+
.sort((a, b) => a - b);
|
|
1327
|
+
return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
|
|
1328
|
+
} catch {
|
|
1329
|
+
return DEFAULT_PAGE_SIZES;
|
|
1330
|
+
}
|
|
1331
|
+
}, [generalSettings]);
|
|
1332
|
+
|
|
1301
1333
|
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
1302
1334
|
storageKey: 'pagination:core-menu:pageSize',
|
|
1303
1335
|
defaultValue: 12,
|
|
1304
|
-
allowedValues:
|
|
1336
|
+
allowedValues: pageSizeOptions,
|
|
1305
1337
|
});
|
|
1306
1338
|
|
|
1307
1339
|
const { data: allMenus, refetch: refetchAllMenus } = useQuery<MenuItem[]>({
|
|
@@ -2578,7 +2610,7 @@ export default function MenuPage() {
|
|
|
2578
2610
|
setPageSize(size);
|
|
2579
2611
|
setPage(1);
|
|
2580
2612
|
}}
|
|
2581
|
-
pageSizeOptions={
|
|
2613
|
+
pageSizeOptions={pageSizeOptions}
|
|
2582
2614
|
/>
|
|
2583
2615
|
</div>
|
|
2584
2616
|
|
|
@@ -44,6 +44,10 @@ export default function PreferencesPage() {
|
|
|
44
44
|
const {
|
|
45
45
|
currentTheme,
|
|
46
46
|
setCurrentTheme,
|
|
47
|
+
density,
|
|
48
|
+
setDensity,
|
|
49
|
+
zoom,
|
|
50
|
+
setZoom,
|
|
47
51
|
refetchUser,
|
|
48
52
|
request,
|
|
49
53
|
getSettingValue,
|
|
@@ -121,6 +125,21 @@ export default function PreferencesPage() {
|
|
|
121
125
|
}
|
|
122
126
|
};
|
|
123
127
|
|
|
128
|
+
const handleSpacingDensityChange = (
|
|
129
|
+
value: 'compact' | 'comfortable' | 'spacious'
|
|
130
|
+
) => {
|
|
131
|
+
setDensity(value);
|
|
132
|
+
showToastHandler(
|
|
133
|
+
'success',
|
|
134
|
+
t('spacingDensityUpdated') || 'Spacing density updated successfully'
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const handleZoomChange = (value: string) => {
|
|
139
|
+
setZoom(value);
|
|
140
|
+
showToastHandler('success', t('zoomUpdated') || 'Zoom updated successfully');
|
|
141
|
+
};
|
|
142
|
+
|
|
124
143
|
const handleLanguageChange = async (code: string) => {
|
|
125
144
|
try {
|
|
126
145
|
await request({
|
|
@@ -226,6 +245,64 @@ export default function PreferencesPage() {
|
|
|
226
245
|
</Select>
|
|
227
246
|
</div>
|
|
228
247
|
</div>
|
|
248
|
+
|
|
249
|
+
<div className="flex justify-between mt-4">
|
|
250
|
+
<div className="flex-col">
|
|
251
|
+
<label className="font-semibold">
|
|
252
|
+
{t('spacingDensity')}
|
|
253
|
+
</label>
|
|
254
|
+
<p className="text-muted-foreground text-sm">
|
|
255
|
+
{t('setPreferredSpacingDensity')}
|
|
256
|
+
</p>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<div className="h-full flex items-center">
|
|
260
|
+
<Select
|
|
261
|
+
value={density}
|
|
262
|
+
onValueChange={handleSpacingDensityChange}
|
|
263
|
+
>
|
|
264
|
+
<SelectTrigger className="w-[180px] bg-background">
|
|
265
|
+
<SelectValue placeholder={t('selectSpacingDensity')} />
|
|
266
|
+
</SelectTrigger>
|
|
267
|
+
<SelectContent>
|
|
268
|
+
<SelectItem value="compact">
|
|
269
|
+
{t('densityCompact')}
|
|
270
|
+
</SelectItem>
|
|
271
|
+
<SelectItem value="comfortable">
|
|
272
|
+
{t('densityComfortable')}
|
|
273
|
+
</SelectItem>
|
|
274
|
+
<SelectItem value="spacious">
|
|
275
|
+
{t('densitySpacious')}
|
|
276
|
+
</SelectItem>
|
|
277
|
+
</SelectContent>
|
|
278
|
+
</Select>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div className="flex justify-between mt-4">
|
|
283
|
+
<div className="flex-col">
|
|
284
|
+
<label className="font-semibold">{t('zoom')}</label>
|
|
285
|
+
<p className="text-muted-foreground text-sm">
|
|
286
|
+
{t('setPreferredZoom')}
|
|
287
|
+
</p>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div className="h-full flex items-center">
|
|
291
|
+
<Select value={zoom} onValueChange={handleZoomChange}>
|
|
292
|
+
<SelectTrigger className="w-[180px] bg-background">
|
|
293
|
+
<SelectValue placeholder={t('selectZoom')} />
|
|
294
|
+
</SelectTrigger>
|
|
295
|
+
<SelectContent>
|
|
296
|
+
<SelectItem value="80%">80%</SelectItem>
|
|
297
|
+
<SelectItem value="90%">90%</SelectItem>
|
|
298
|
+
<SelectItem value="100%">100%</SelectItem>
|
|
299
|
+
<SelectItem value="110%">110%</SelectItem>
|
|
300
|
+
<SelectItem value="125%">125%</SelectItem>
|
|
301
|
+
<SelectItem value="150%">150%</SelectItem>
|
|
302
|
+
</SelectContent>
|
|
303
|
+
</Select>
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
229
306
|
</CardContent>
|
|
230
307
|
</Card>
|
|
231
308
|
|
|
@@ -55,6 +55,8 @@ type RoleMenusSectionProps = {
|
|
|
55
55
|
|
|
56
56
|
const EMPTY_MENUS: Menu[] = [];
|
|
57
57
|
|
|
58
|
+
const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
|
|
59
|
+
|
|
58
60
|
export function RoleMenusSection({
|
|
59
61
|
roleId,
|
|
60
62
|
onMenuChange,
|
|
@@ -63,10 +65,40 @@ export function RoleMenusSection({
|
|
|
63
65
|
const { request, currentLocaleCode } = useApp();
|
|
64
66
|
const [togglingMenuId, setTogglingMenuId] = useState<number | null>(null);
|
|
65
67
|
const [page, setPage] = useState(1);
|
|
68
|
+
const { data: generalSettings } = useQuery<{
|
|
69
|
+
data: Array<{ slug: string; value: string }>;
|
|
70
|
+
}>({
|
|
71
|
+
queryKey: ['setting-group-general'],
|
|
72
|
+
queryFn: async () => {
|
|
73
|
+
const response = await request<{
|
|
74
|
+
data: Array<{ slug: string; value: string }>;
|
|
75
|
+
}>({ url: '/setting/group/general', method: 'GET' });
|
|
76
|
+
return response.data;
|
|
77
|
+
},
|
|
78
|
+
staleTime: 5 * 60 * 1000,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const pageSizeOptions = useMemo(() => {
|
|
82
|
+
const setting = generalSettings?.data?.find(
|
|
83
|
+
(s) => s.slug === 'pagination-page-sizes'
|
|
84
|
+
);
|
|
85
|
+
if (!setting?.value) return DEFAULT_PAGE_SIZES;
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(setting.value) as string[];
|
|
88
|
+
const sizes = parsed
|
|
89
|
+
.map(Number)
|
|
90
|
+
.filter((n) => !isNaN(n) && n > 0)
|
|
91
|
+
.sort((a, b) => a - b);
|
|
92
|
+
return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
|
|
93
|
+
} catch {
|
|
94
|
+
return DEFAULT_PAGE_SIZES;
|
|
95
|
+
}
|
|
96
|
+
}, [generalSettings]);
|
|
97
|
+
|
|
66
98
|
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
67
99
|
storageKey: 'pagination:global:pageSize',
|
|
68
|
-
defaultValue:
|
|
69
|
-
allowedValues:
|
|
100
|
+
defaultValue: 12,
|
|
101
|
+
allowedValues: pageSizeOptions,
|
|
70
102
|
});
|
|
71
103
|
const [expandedMenus, setExpandedMenus] = useState<string[]>([]);
|
|
72
104
|
|
|
@@ -466,7 +498,7 @@ export function RoleMenusSection({
|
|
|
466
498
|
<SelectValue placeholder={pageSize} />
|
|
467
499
|
</SelectTrigger>
|
|
468
500
|
<SelectContent side="top">
|
|
469
|
-
{
|
|
501
|
+
{pageSizeOptions.map((size) => (
|
|
470
502
|
<SelectItem key={size} value={`${size}`}>
|
|
471
503
|
{size}
|
|
472
504
|
</SelectItem>
|
|
@@ -156,6 +156,8 @@ function getErrorMessage(error: unknown, fallbackMessage: string) {
|
|
|
156
156
|
return fallbackMessage;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
|
|
160
|
+
|
|
159
161
|
export default function RolePage() {
|
|
160
162
|
const t = useTranslations('core.RolePage');
|
|
161
163
|
const { request, currentLocaleCode, locales, getSettingValue } = useApp();
|
|
@@ -168,10 +170,40 @@ export default function RolePage() {
|
|
|
168
170
|
const [selectedLocale, setSelectedLocale] = useState(currentLocaleCode);
|
|
169
171
|
|
|
170
172
|
const [page, setPage] = useState(1);
|
|
173
|
+
const { data: generalSettings } = useQuery<{
|
|
174
|
+
data: Array<{ slug: string; value: string }>;
|
|
175
|
+
}>({
|
|
176
|
+
queryKey: ['setting-group-general'],
|
|
177
|
+
queryFn: async () => {
|
|
178
|
+
const response = await request<{
|
|
179
|
+
data: Array<{ slug: string; value: string }>;
|
|
180
|
+
}>({ url: '/setting/group/general', method: 'GET' });
|
|
181
|
+
return response.data;
|
|
182
|
+
},
|
|
183
|
+
staleTime: 5 * 60 * 1000,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const pageSizeOptions = useMemo(() => {
|
|
187
|
+
const setting = generalSettings?.data?.find(
|
|
188
|
+
(s) => s.slug === 'pagination-page-sizes'
|
|
189
|
+
);
|
|
190
|
+
if (!setting?.value) return DEFAULT_PAGE_SIZES;
|
|
191
|
+
try {
|
|
192
|
+
const parsed = JSON.parse(setting.value) as string[];
|
|
193
|
+
const sizes = parsed
|
|
194
|
+
.map(Number)
|
|
195
|
+
.filter((n) => !isNaN(n) && n > 0)
|
|
196
|
+
.sort((a, b) => a - b);
|
|
197
|
+
return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
|
|
198
|
+
} catch {
|
|
199
|
+
return DEFAULT_PAGE_SIZES;
|
|
200
|
+
}
|
|
201
|
+
}, [generalSettings]);
|
|
202
|
+
|
|
171
203
|
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
172
204
|
storageKey: 'pagination:core-roles:pageSize',
|
|
173
205
|
defaultValue: 12,
|
|
174
|
-
allowedValues:
|
|
206
|
+
allowedValues: pageSizeOptions,
|
|
175
207
|
});
|
|
176
208
|
const [activeTab, setActiveTab] = useState('basic-info');
|
|
177
209
|
const [openDeleteModal, setOpenDeleteModal] = useState(false);
|
|
@@ -681,7 +713,7 @@ export default function RolePage() {
|
|
|
681
713
|
setPageSize(size);
|
|
682
714
|
setPage(1);
|
|
683
715
|
}}
|
|
684
|
-
pageSizeOptions={
|
|
716
|
+
pageSizeOptions={pageSizeOptions}
|
|
685
717
|
/>
|
|
686
718
|
</div>
|
|
687
719
|
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
Search,
|
|
27
27
|
} from 'lucide-react';
|
|
28
28
|
import { useTranslations } from 'next-intl';
|
|
29
|
-
import { useState } from 'react';
|
|
29
|
+
import { useMemo, useState } from 'react';
|
|
30
30
|
import { toast } from 'sonner';
|
|
31
31
|
|
|
32
32
|
type RouteType = {
|
|
@@ -54,6 +54,8 @@ const normalizeRouteMethod = (method: string | null) => {
|
|
|
54
54
|
return normalizedMethod || UNKNOWN_METHOD_LABEL;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
+
const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
|
|
58
|
+
|
|
57
59
|
export function RoleRoutesSection({
|
|
58
60
|
roleId,
|
|
59
61
|
onRouteChange,
|
|
@@ -62,10 +64,40 @@ export function RoleRoutesSection({
|
|
|
62
64
|
const { request } = useApp();
|
|
63
65
|
const [togglingRouteId, setTogglingRouteId] = useState<number | null>(null);
|
|
64
66
|
const [page, setPage] = useState(1);
|
|
67
|
+
const { data: generalSettings } = useQuery<{
|
|
68
|
+
data: Array<{ slug: string; value: string }>;
|
|
69
|
+
}>({
|
|
70
|
+
queryKey: ['setting-group-general'],
|
|
71
|
+
queryFn: async () => {
|
|
72
|
+
const response = await request<{
|
|
73
|
+
data: Array<{ slug: string; value: string }>;
|
|
74
|
+
}>({ url: '/setting/group/general', method: 'GET' });
|
|
75
|
+
return response.data;
|
|
76
|
+
},
|
|
77
|
+
staleTime: 5 * 60 * 1000,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const pageSizeOptions = useMemo(() => {
|
|
81
|
+
const setting = generalSettings?.data?.find(
|
|
82
|
+
(s) => s.slug === 'pagination-page-sizes'
|
|
83
|
+
);
|
|
84
|
+
if (!setting?.value) return DEFAULT_PAGE_SIZES;
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(setting.value) as string[];
|
|
87
|
+
const sizes = parsed
|
|
88
|
+
.map(Number)
|
|
89
|
+
.filter((n) => !isNaN(n) && n > 0)
|
|
90
|
+
.sort((a, b) => a - b);
|
|
91
|
+
return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
|
|
92
|
+
} catch {
|
|
93
|
+
return DEFAULT_PAGE_SIZES;
|
|
94
|
+
}
|
|
95
|
+
}, [generalSettings]);
|
|
96
|
+
|
|
65
97
|
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
66
98
|
storageKey: 'pagination:global:pageSize',
|
|
67
|
-
defaultValue:
|
|
68
|
-
allowedValues:
|
|
99
|
+
defaultValue: 12,
|
|
100
|
+
allowedValues: pageSizeOptions,
|
|
69
101
|
});
|
|
70
102
|
const [searchTerm, setSearchTerm] = useState('');
|
|
71
103
|
const [searchType, setSearchType] = useState<SearchType>('contains');
|
|
@@ -355,7 +387,7 @@ export function RoleRoutesSection({
|
|
|
355
387
|
<SelectValue placeholder={pageSize} />
|
|
356
388
|
</SelectTrigger>
|
|
357
389
|
<SelectContent side="top">
|
|
358
|
-
{
|
|
390
|
+
{pageSizeOptions.map((size) => (
|
|
359
391
|
<SelectItem key={size} value={`${size}`}>
|
|
360
392
|
{size}
|
|
361
393
|
</SelectItem>
|