@promptbook/cli 0.104.0-1 → 0.104.0-11
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/apps/agents-server/config.ts +1 -3
- package/apps/agents-server/next.config.ts +2 -2
- package/apps/agents-server/package.json +7 -3
- package/apps/agents-server/public/fonts/OpenMoji-color-cbdt.woff2 +0 -0
- package/apps/agents-server/public/swagger.json +115 -0
- package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +54 -0
- package/apps/agents-server/scripts/generate-reserved-paths/tsconfig.json +19 -0
- package/apps/agents-server/src/app/AddAgentButton.tsx +47 -21
- package/apps/agents-server/src/app/actions.ts +22 -5
- package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +211 -0
- package/apps/agents-server/src/app/admin/browser-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +221 -274
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +94 -137
- package/apps/agents-server/src/app/admin/files/FilesGalleryClient.tsx +263 -0
- package/apps/agents-server/src/app/admin/files/actions.ts +61 -0
- package/apps/agents-server/src/app/admin/files/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/image-generator-test/ImageGeneratorTestClient.tsx +169 -0
- package/apps/agents-server/src/app/admin/image-generator-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/images/ImagesGalleryClient.tsx +256 -0
- package/apps/agents-server/src/app/admin/images/actions.ts +60 -0
- package/apps/agents-server/src/app/admin/images/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +294 -0
- package/apps/agents-server/src/app/admin/messages/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +104 -0
- package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +35 -0
- package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +23 -19
- package/apps/agents-server/src/app/admin/search-engine-test/SearchEngineTestClient.tsx +109 -0
- package/apps/agents-server/src/app/admin/search-engine-test/actions.ts +17 -0
- package/apps/agents-server/src/app/admin/search-engine-test/page.tsx +13 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +15 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +51 -9
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +47 -4
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +53 -11
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +23 -3
- package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +8 -8
- package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +17 -26
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +20 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +6 -11
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +5 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +5 -2
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +20 -16
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +12 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +68 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +223 -0
- package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +5 -0
- package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +31 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +194 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +14 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +11 -4
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +11 -2
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +18 -10
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +100 -0
- package/apps/agents-server/src/app/api/admin-email/route.ts +12 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +13 -14
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +20 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +43 -1
- package/apps/agents-server/src/app/api/agents/route.ts +28 -3
- package/apps/agents-server/src/app/api/api-tokens/route.ts +6 -7
- package/apps/agents-server/src/app/api/browser-test/act/route.ts +141 -0
- package/apps/agents-server/src/app/api/browser-test/screenshot/route.ts +30 -0
- package/apps/agents-server/src/app/api/browser-test/scroll-facebook/route.ts +62 -0
- package/apps/agents-server/src/app/api/docs/book.md/route.ts +61 -0
- package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
- package/apps/agents-server/src/app/api/federated-agents/route.ts +12 -0
- package/apps/agents-server/src/app/api/images/[filename]/route.ts +128 -0
- package/apps/agents-server/src/app/api/messages/route.ts +102 -0
- package/apps/agents-server/src/app/api/metadata/route.ts +5 -6
- package/apps/agents-server/src/app/api/upload/route.ts +128 -45
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +2 -3
- package/apps/agents-server/src/app/docs/page.tsx +12 -12
- package/apps/agents-server/src/app/globals.css +140 -33
- package/apps/agents-server/src/app/humans.txt/route.ts +1 -1
- package/apps/agents-server/src/app/layout.tsx +27 -22
- package/apps/agents-server/src/app/page.tsx +54 -6
- package/apps/agents-server/src/app/recycle-bin/actions.ts +20 -14
- package/apps/agents-server/src/app/recycle-bin/page.tsx +27 -41
- package/apps/agents-server/src/app/robots.txt/route.ts +1 -1
- package/apps/agents-server/src/app/security.txt/route.ts +1 -1
- package/apps/agents-server/src/app/sitemap.xml/route.ts +9 -7
- package/apps/agents-server/src/app/swagger/page.tsx +14 -0
- package/apps/agents-server/src/components/AgentProfile/AgentCapabilityChips.tsx +38 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +44 -116
- package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +92 -0
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -1
- package/apps/agents-server/src/components/AgentProfile/useAgentBackground.ts +97 -0
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +5 -4
- package/apps/agents-server/src/components/DeletedAgentBanner.tsx +26 -0
- package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +38 -0
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +11 -9
- package/apps/agents-server/src/components/Footer/Footer.tsx +5 -5
- package/apps/agents-server/src/components/ForgottenPasswordDialog/ForgottenPasswordDialog.tsx +61 -0
- package/apps/agents-server/src/components/Header/Header.tsx +130 -40
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +150 -23
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +93 -15
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +66 -0
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +12 -3
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +19 -10
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +3 -2
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +50 -1
- package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +88 -0
- package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +7 -2
- package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +16 -7
- package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +4 -4
- package/apps/agents-server/src/components/RegisterUserDialog/RegisterUserDialog.tsx +61 -0
- package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +2 -0
- package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +12 -10
- package/apps/agents-server/src/components/_utils/headlessParam.tsx +7 -3
- package/apps/agents-server/src/database/$getTableName.ts +1 -0
- package/apps/agents-server/src/database/$provideSupabaseForBrowser.ts +3 -3
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +1 -1
- package/apps/agents-server/src/database/$provideSupabaseForWorker.ts +3 -3
- package/apps/agents-server/src/database/metadataDefaults.ts +19 -1
- package/apps/agents-server/src/database/migrate.ts +34 -1
- package/apps/agents-server/src/database/migrations/2025-11-0001-initial-schema.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-12-0240-agent-public-id.sql +3 -0
- package/apps/agents-server/src/database/migrations/2025-12-0360-agent-deleted-at.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0370-image-table.sql +19 -0
- package/apps/agents-server/src/database/migrations/2025-12-0380-agent-visibility.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0390-upload-tracking.sql +20 -0
- package/apps/agents-server/src/database/migrations/2025-12-0401-file-upload-status.sql +13 -0
- package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +42 -0
- package/apps/agents-server/src/database/migrations/2025-12-0403-generation-lock-table.sql +15 -0
- package/apps/agents-server/src/database/migrations/2025-12-0640-openai-assistant-cache.sql +12 -0
- package/apps/agents-server/src/database/migrations/2025-12-0820-agent-history-permanent-id.sql +29 -0
- package/apps/agents-server/src/database/migrations/2025-12-0830-image-purpose.sql +5 -0
- package/apps/agents-server/src/database/migrations/2025-12-0890-file-agent-id.sql +5 -0
- package/apps/agents-server/src/database/schema.ts +244 -4
- package/apps/agents-server/src/generated/reservedPaths.ts +32 -0
- package/apps/agents-server/src/message-providers/email/_common/Email.ts +73 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +1 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +108 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +62 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +117 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +119 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +74 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +14 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +44 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
- package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +51 -0
- package/apps/agents-server/src/message-providers/index.ts +13 -0
- package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +11 -0
- package/apps/agents-server/src/middleware.ts +19 -23
- package/apps/agents-server/src/tools/$provideBrowserForServer.ts +32 -0
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +7 -2
- package/apps/agents-server/src/utils/auth.ts +117 -17
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +57 -0
- package/apps/agents-server/src/utils/cdn/classes/VercelBlobStorage.ts +4 -0
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +18 -0
- package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
- package/apps/agents-server/src/utils/getUserIdFromRequest.ts +35 -0
- package/apps/agents-server/src/utils/handleChatCompletion.ts +65 -5
- package/apps/agents-server/src/utils/messages/sendMessage.ts +91 -0
- package/apps/agents-server/src/utils/messagesAdmin.ts +72 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +36 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +25 -0
- package/apps/agents-server/src/utils/validateApiKey.ts +7 -11
- package/esm/index.es.js +1534 -1330
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +8 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +16 -2
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +29 -1
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
- package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
- package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
- package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +9 -13
- package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +3 -3
- package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
- package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
- package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -12
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +27 -15
- package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
- package/esm/typings/src/commitments/index.d.ts +2 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
- package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
- package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
- package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
- package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
- package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
- package/esm/typings/src/types/Message.d.ts +49 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
- package/esm/typings/src/types/typeAliases.d.ts +23 -1
- package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
- package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
- package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
- package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
- package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +1542 -1338
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/package-lock.json +0 -27
- package/apps/agents-server/public/fonts/download-font.js +0 -22
- package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +0 -18
- package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
|
@@ -54,10 +54,7 @@ function getMessagePreview(message: unknown, maxLength = 120): string {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
if (typeof message === 'object') {
|
|
57
|
-
const content =
|
|
58
|
-
(message as { content?: unknown }).content ??
|
|
59
|
-
(message as { text?: unknown }).text ??
|
|
60
|
-
message;
|
|
57
|
+
const content = (message as { content?: unknown }).content ?? (message as { text?: unknown }).text ?? message;
|
|
61
58
|
|
|
62
59
|
let text: string;
|
|
63
60
|
|
|
@@ -303,11 +300,12 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
303
300
|
const message = row.message as { role?: string; content?: string };
|
|
304
301
|
const role = (message.role || 'USER').toUpperCase();
|
|
305
302
|
return {
|
|
303
|
+
// channel: 'PROMPTBOOK_CHAT',
|
|
306
304
|
id: String(row.id),
|
|
307
|
-
|
|
305
|
+
sender: role === 'USER' ? 'USER' : 'ASSISTANT',
|
|
308
306
|
content: message.content || JSON.stringify(message),
|
|
309
307
|
isComplete: true,
|
|
310
|
-
|
|
308
|
+
createdAt: new Date(row.createdAt),
|
|
311
309
|
} satisfies ChatMessage;
|
|
312
310
|
});
|
|
313
311
|
}, [items, viewMode]);
|
|
@@ -317,17 +315,9 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
317
315
|
<div>
|
|
318
316
|
{total > 0 ? (
|
|
319
317
|
<>
|
|
320
|
-
Showing{' '}
|
|
321
|
-
<span className="font-semibold">
|
|
322
|
-
|
|
323
|
-
</span>{' '}
|
|
324
|
-
–{' '}
|
|
325
|
-
<span className="font-semibold">
|
|
326
|
-
{Math.min(page * pageSize, total)}
|
|
327
|
-
</span>{' '}
|
|
328
|
-
of{' '}
|
|
329
|
-
<span className="font-semibold">{total}</span>{' '}
|
|
330
|
-
messages
|
|
318
|
+
Showing <span className="font-semibold">{Math.min((page - 1) * pageSize + 1, total)}</span> –{' '}
|
|
319
|
+
<span className="font-semibold">{Math.min(page * pageSize, total)}</span> of{' '}
|
|
320
|
+
<span className="font-semibold">{total}</span> messages
|
|
331
321
|
</>
|
|
332
322
|
) : (
|
|
333
323
|
'No messages'
|
|
@@ -403,97 +393,90 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
403
393
|
</a>
|
|
404
394
|
</div>
|
|
405
395
|
<div>
|
|
406
|
-
<div className="text-xl font-semibold text-gray-900">
|
|
407
|
-
|
|
408
|
-
</div>
|
|
409
|
-
<div className="text-xs uppercase tracking-wide text-gray-400">
|
|
410
|
-
Total messages
|
|
411
|
-
</div>
|
|
396
|
+
<div className="text-xl font-semibold text-gray-900">{total.toLocaleString()}</div>
|
|
397
|
+
<div className="text-xs uppercase tracking-wide text-gray-400">Total messages</div>
|
|
412
398
|
</div>
|
|
413
399
|
</div>
|
|
414
400
|
</div>
|
|
415
401
|
<Card>
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
402
|
+
<div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
|
|
403
|
+
<form onSubmit={handleSearchSubmit} className="flex flex-col gap-2 md:flex-row md:items-end">
|
|
404
|
+
<div className="flex flex-col gap-1">
|
|
405
|
+
<label htmlFor="search" className="text-sm font-medium text-gray-700">
|
|
406
|
+
Search
|
|
407
|
+
</label>
|
|
408
|
+
<input
|
|
409
|
+
id="search"
|
|
410
|
+
type="text"
|
|
411
|
+
value={searchInput}
|
|
412
|
+
onChange={(event) => setSearchInput(event.target.value)}
|
|
413
|
+
placeholder="Search by agent name, URL or IP"
|
|
414
|
+
className="w-full md:w-72 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
415
|
+
/>
|
|
416
|
+
</div>
|
|
417
|
+
<button
|
|
418
|
+
type="submit"
|
|
419
|
+
className="mt-2 inline-flex items-center justify-center rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 md:mt-0 md:ml-3"
|
|
420
|
+
>
|
|
421
|
+
Apply
|
|
422
|
+
</button>
|
|
423
|
+
</form>
|
|
424
|
+
|
|
425
|
+
<div className="flex flex-col gap-2 md:flex-row md:items-end md:gap-4">
|
|
426
|
+
<div className="flex flex-col gap-1">
|
|
427
|
+
<label htmlFor="agentFilter" className="text-sm font-medium text-gray-700">
|
|
428
|
+
Agent filter
|
|
429
|
+
</label>
|
|
430
|
+
<select
|
|
431
|
+
id="agentFilter"
|
|
432
|
+
value={agentName}
|
|
433
|
+
onChange={handleAgentChange}
|
|
434
|
+
className="w-full md:w-64 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
434
435
|
>
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
</label>
|
|
444
|
-
<select
|
|
445
|
-
id="agentFilter"
|
|
446
|
-
value={agentName}
|
|
447
|
-
onChange={handleAgentChange}
|
|
448
|
-
className="w-full md:w-64 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
449
|
-
>
|
|
450
|
-
<option value="">All agents</option>
|
|
451
|
-
{agents.map((agent) => (
|
|
452
|
-
<option key={agent.agentName} value={agent.agentName}>
|
|
453
|
-
{agent.fullname || agent.agentName}
|
|
454
|
-
</option>
|
|
455
|
-
))}
|
|
456
|
-
</select>
|
|
457
|
-
{agentsLoading && (
|
|
458
|
-
<span className="text-xs text-gray-400">Loading agents…</span>
|
|
459
|
-
)}
|
|
460
|
-
</div>
|
|
461
|
-
|
|
462
|
-
<div className="flex flex-col gap-1">
|
|
463
|
-
<label htmlFor="pageSize" className="text-sm font-medium text-gray-700">
|
|
464
|
-
Page size
|
|
465
|
-
</label>
|
|
466
|
-
<select
|
|
467
|
-
id="pageSize"
|
|
468
|
-
value={pageSize}
|
|
469
|
-
onChange={handlePageSizeChange}
|
|
470
|
-
className="w-28 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
471
|
-
>
|
|
472
|
-
<option value={10}>10</option>
|
|
473
|
-
<option value={20}>20</option>
|
|
474
|
-
<option value={50}>50</option>
|
|
475
|
-
<option value={100}>100</option>
|
|
476
|
-
</select>
|
|
477
|
-
</div>
|
|
436
|
+
<option value="">All agents</option>
|
|
437
|
+
{agents.map((agent) => (
|
|
438
|
+
<option key={agent.agentName} value={agent.agentName}>
|
|
439
|
+
{agent.fullname || agent.agentName}
|
|
440
|
+
</option>
|
|
441
|
+
))}
|
|
442
|
+
</select>
|
|
443
|
+
{agentsLoading && <span className="text-xs text-gray-400">Loading agents…</span>}
|
|
478
444
|
</div>
|
|
479
|
-
</div>
|
|
480
445
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
className="inline-flex items-center justify-center rounded-md border border-red-300 bg-white px-3 py-1.5 text-xs font-medium text-red-700 hover:bg-red-50"
|
|
446
|
+
<div className="flex flex-col gap-1">
|
|
447
|
+
<label htmlFor="pageSize" className="text-sm font-medium text-gray-700">
|
|
448
|
+
Page size
|
|
449
|
+
</label>
|
|
450
|
+
<select
|
|
451
|
+
id="pageSize"
|
|
452
|
+
value={pageSize}
|
|
453
|
+
onChange={handlePageSizeChange}
|
|
454
|
+
className="w-28 px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
491
455
|
>
|
|
492
|
-
|
|
493
|
-
|
|
456
|
+
<option value={10}>10</option>
|
|
457
|
+
<option value={20}>20</option>
|
|
458
|
+
<option value={50}>50</option>
|
|
459
|
+
<option value={100}>100</option>
|
|
460
|
+
</select>
|
|
494
461
|
</div>
|
|
495
|
-
|
|
496
|
-
</
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
464
|
+
|
|
465
|
+
{agentName && (
|
|
466
|
+
<div className="mt-4 flex items-center justify-between gap-4 rounded-md border border-amber-200 bg-amber-50 px-4 py-3">
|
|
467
|
+
<p className="text-sm text-amber-800">
|
|
468
|
+
Showing chat history for agent <span className="font-semibold break-all">{agentName}</span>.
|
|
469
|
+
</p>
|
|
470
|
+
<button
|
|
471
|
+
type="button"
|
|
472
|
+
onClick={handleClearAgentHistory}
|
|
473
|
+
className="inline-flex items-center justify-center rounded-md border border-red-300 bg-white px-3 py-1.5 text-xs font-medium text-red-700 hover:bg-red-50"
|
|
474
|
+
>
|
|
475
|
+
Clear history for this agent
|
|
476
|
+
</button>
|
|
477
|
+
</div>
|
|
478
|
+
)}
|
|
479
|
+
</Card>
|
|
497
480
|
|
|
498
481
|
{viewMode === 'chat' ? (
|
|
499
482
|
<div className="bg-white rounded-lg shadow border border-gray-200 overflow-hidden flex flex-col">
|
|
@@ -505,22 +488,14 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
505
488
|
isSaveButtonEnabled={true}
|
|
506
489
|
/>
|
|
507
490
|
</div>
|
|
508
|
-
<div className="p-4 bg-gray-50 border-t border-gray-200">
|
|
509
|
-
{pagination}
|
|
510
|
-
</div>
|
|
491
|
+
<div className="p-4 bg-gray-50 border-t border-gray-200">{pagination}</div>
|
|
511
492
|
</div>
|
|
512
493
|
) : (
|
|
513
494
|
<Card>
|
|
514
495
|
<div className="flex items-center justify-between mb-4">
|
|
515
|
-
<h2 className="text-lg font-medium text-gray-900">
|
|
516
|
-
Messages ({total})
|
|
517
|
-
</h2>
|
|
496
|
+
<h2 className="text-lg font-medium text-gray-900">Messages ({total})</h2>
|
|
518
497
|
</div>
|
|
519
|
-
{error &&
|
|
520
|
-
<div className="mb-4 rounded-md bg-red-50 px-4 py-3 text-sm text-red-800">
|
|
521
|
-
{error}
|
|
522
|
-
</div>
|
|
523
|
-
)}
|
|
498
|
+
{error && <div className="mb-4 rounded-md bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>}
|
|
524
499
|
|
|
525
500
|
{loading && items.length === 0 ? (
|
|
526
501
|
<div className="py-8 text-center text-gray-500">Loading chat history…</div>
|
|
@@ -555,27 +530,13 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
555
530
|
)}
|
|
556
531
|
</button>
|
|
557
532
|
</th>
|
|
558
|
-
<th className="px-4 py-3 text-left font-medium text-gray-500">
|
|
559
|
-
|
|
560
|
-
</th>
|
|
561
|
-
<th className="px-4 py-3 text-left font-medium text-gray-500">
|
|
562
|
-
|
|
563
|
-
</th>
|
|
564
|
-
<th className="px-4 py-3 text-
|
|
565
|
-
URL
|
|
566
|
-
</th>
|
|
567
|
-
<th className="px-4 py-3 text-left font-medium text-gray-500">
|
|
568
|
-
IP
|
|
569
|
-
</th>
|
|
570
|
-
<th className="px-4 py-3 text-left font-medium text-gray-500">
|
|
571
|
-
Language
|
|
572
|
-
</th>
|
|
573
|
-
<th className="px-4 py-3 text-left font-medium text-gray-500">
|
|
574
|
-
Platform
|
|
575
|
-
</th>
|
|
576
|
-
<th className="px-4 py-3 text-right font-medium text-gray-500">
|
|
577
|
-
Actions
|
|
578
|
-
</th>
|
|
533
|
+
<th className="px-4 py-3 text-left font-medium text-gray-500">Role</th>
|
|
534
|
+
<th className="px-4 py-3 text-left font-medium text-gray-500">Message</th>
|
|
535
|
+
<th className="px-4 py-3 text-left font-medium text-gray-500">URL</th>
|
|
536
|
+
<th className="px-4 py-3 text-left font-medium text-gray-500">IP</th>
|
|
537
|
+
<th className="px-4 py-3 text-left font-medium text-gray-500">Language</th>
|
|
538
|
+
<th className="px-4 py-3 text-left font-medium text-gray-500">Platform</th>
|
|
539
|
+
<th className="px-4 py-3 text-right font-medium text-gray-500">Actions</th>
|
|
579
540
|
</tr>
|
|
580
541
|
</thead>
|
|
581
542
|
<tbody className="divide-y divide-gray-200 bg-white">
|
|
@@ -596,9 +557,7 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
596
557
|
</div>
|
|
597
558
|
</td>
|
|
598
559
|
<td className="max-w-xs px-4 py-3 text-gray-500">
|
|
599
|
-
<div className="truncate text-xs">
|
|
600
|
-
{row.url || '-'}
|
|
601
|
-
</div>
|
|
560
|
+
<div className="truncate text-xs">{row.url || '-'}</div>
|
|
602
561
|
</td>
|
|
603
562
|
<td className="whitespace-nowrap px-4 py-3 text-gray-500">
|
|
604
563
|
{row.ip || '-'}
|
|
@@ -607,9 +566,7 @@ export function ChatHistoryClient({ initialAgentName }: ChatHistoryClientProps)
|
|
|
607
566
|
{row.language || '-'}
|
|
608
567
|
</td>
|
|
609
568
|
<td className="max-w-xs px-4 py-3 text-gray-500">
|
|
610
|
-
<div className="truncate text-xs">
|
|
611
|
-
{row.platform || '-'}
|
|
612
|
-
</div>
|
|
569
|
+
<div className="truncate text-xs">{row.platform || '-'}</div>
|
|
613
570
|
</td>
|
|
614
571
|
<td className="whitespace-nowrap px-4 py-3 text-right text-xs font-medium">
|
|
615
572
|
<button
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ChevronLeft, ChevronRight, File, Grid, LayoutList, Loader2 } from 'lucide-react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { useEffect, useRef, useState } from 'react';
|
|
6
|
+
import { FileWithAgent, listFiles } from './actions';
|
|
7
|
+
|
|
8
|
+
type ViewMode = 'TABLE' | 'GRID';
|
|
9
|
+
|
|
10
|
+
export function FilesGalleryClient() {
|
|
11
|
+
const [viewMode, setViewMode] = useState<ViewMode>('TABLE');
|
|
12
|
+
const [files, setFiles] = useState<FileWithAgent[]>([]);
|
|
13
|
+
const [total, setTotal] = useState(0);
|
|
14
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
15
|
+
const [page, setPage] = useState(1);
|
|
16
|
+
const [limit] = useState(20);
|
|
17
|
+
const [hasMore, setHasMore] = useState(true);
|
|
18
|
+
|
|
19
|
+
const loadFiles = async (pageNum: number, isNewView: boolean) => {
|
|
20
|
+
setIsLoading(true);
|
|
21
|
+
try {
|
|
22
|
+
const result = await listFiles({ page: pageNum, limit });
|
|
23
|
+
if (isNewView) {
|
|
24
|
+
setFiles(result.files);
|
|
25
|
+
} else {
|
|
26
|
+
setFiles((prev) => [...prev, ...result.files]);
|
|
27
|
+
}
|
|
28
|
+
setTotal(result.total);
|
|
29
|
+
setHasMore(result.files.length === limit);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error(error);
|
|
32
|
+
} finally {
|
|
33
|
+
setIsLoading(false);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
loadFiles(1, true);
|
|
39
|
+
setPage(1);
|
|
40
|
+
setHasMore(true);
|
|
41
|
+
}, [viewMode]);
|
|
42
|
+
|
|
43
|
+
const handleLoadMore = () => {
|
|
44
|
+
if (!isLoading && hasMore) {
|
|
45
|
+
const nextPage = page + 1;
|
|
46
|
+
setPage(nextPage);
|
|
47
|
+
loadFiles(nextPage, false);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Table view pagination
|
|
52
|
+
const handlePageChange = (newPage: number) => {
|
|
53
|
+
setPage(newPage);
|
|
54
|
+
loadFiles(newPage, true);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const observerTarget = useRef<HTMLDivElement>(null);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const observer = new IntersectionObserver(
|
|
61
|
+
(entries) => {
|
|
62
|
+
if (entries[0].isIntersecting && hasMore && !isLoading && viewMode === 'GRID') {
|
|
63
|
+
handleLoadMore();
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{ threshold: 0.1 }
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (observerTarget.current) {
|
|
70
|
+
observer.observe(observerTarget.current);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
75
|
+
if (observerTarget.current) {
|
|
76
|
+
observer.unobserve(observerTarget.current);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}, [hasMore, isLoading, viewMode, page]);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="container mx-auto px-4 py-8 space-y-6">
|
|
83
|
+
<div className="flex justify-between items-center mt-20 mb-4">
|
|
84
|
+
<h1 className="text-3xl text-gray-900 font-light">Files Gallery</h1>
|
|
85
|
+
<div className="flex items-center gap-2 bg-gray-100 p-1 rounded-lg">
|
|
86
|
+
<button
|
|
87
|
+
onClick={() => setViewMode('TABLE')}
|
|
88
|
+
className={`p-2 rounded-md transition-colors ${
|
|
89
|
+
viewMode === 'TABLE' ? 'bg-white shadow-sm text-blue-600' : 'text-gray-500 hover:text-gray-900'
|
|
90
|
+
}`}
|
|
91
|
+
title="Table View"
|
|
92
|
+
>
|
|
93
|
+
<LayoutList className="w-5 h-5" />
|
|
94
|
+
</button>
|
|
95
|
+
<button
|
|
96
|
+
onClick={() => setViewMode('GRID')}
|
|
97
|
+
className={`p-2 rounded-md transition-colors ${
|
|
98
|
+
viewMode === 'GRID' ? 'bg-white shadow-sm text-blue-600' : 'text-gray-500 hover:text-gray-900'
|
|
99
|
+
}`}
|
|
100
|
+
title="Grid View"
|
|
101
|
+
>
|
|
102
|
+
<Grid className="w-5 h-5" />
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{viewMode === 'TABLE' ? (
|
|
108
|
+
<div className="bg-white border rounded-lg overflow-hidden shadow-sm">
|
|
109
|
+
<div className="overflow-x-auto">
|
|
110
|
+
<table className="w-full text-sm text-left text-gray-500">
|
|
111
|
+
<thead className="text-xs text-gray-700 uppercase bg-gray-50 border-b">
|
|
112
|
+
<tr>
|
|
113
|
+
<th className="px-6 py-3">File Name</th>
|
|
114
|
+
<th className="px-6 py-3">Type</th>
|
|
115
|
+
<th className="px-6 py-3">Size</th>
|
|
116
|
+
<th className="px-6 py-3">Agent</th>
|
|
117
|
+
<th className="px-6 py-3">Purpose</th>
|
|
118
|
+
<th className="px-6 py-3">Status</th>
|
|
119
|
+
<th className="px-6 py-3">Created At</th>
|
|
120
|
+
</tr>
|
|
121
|
+
</thead>
|
|
122
|
+
<tbody>
|
|
123
|
+
{files.map((file) => (
|
|
124
|
+
<tr key={file.id} className="bg-white border-b hover:bg-gray-50">
|
|
125
|
+
<td className="px-6 py-4">
|
|
126
|
+
{file.storageUrl ? (
|
|
127
|
+
<a href={file.storageUrl} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline">
|
|
128
|
+
{file.fileName}
|
|
129
|
+
</a>
|
|
130
|
+
) : (
|
|
131
|
+
file.fileName
|
|
132
|
+
)}
|
|
133
|
+
</td>
|
|
134
|
+
<td className="px-6 py-4">{file.fileType}</td>
|
|
135
|
+
<td className="px-6 py-4">{(file.fileSize / 1024).toFixed(2)} KB</td>
|
|
136
|
+
<td className="px-6 py-4">
|
|
137
|
+
{file.agent ? (
|
|
138
|
+
<Link href={`/${file.agent.agentName}`} className="text-blue-600 hover:underline">
|
|
139
|
+
{file.agent.agentName}
|
|
140
|
+
</Link>
|
|
141
|
+
) : (
|
|
142
|
+
<span className="text-gray-400">-</span>
|
|
143
|
+
)}
|
|
144
|
+
</td>
|
|
145
|
+
<td className="px-6 py-4">
|
|
146
|
+
<span className="bg-gray-100 text-gray-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded">
|
|
147
|
+
{file.purpose}
|
|
148
|
+
</span>
|
|
149
|
+
</td>
|
|
150
|
+
<td className="px-6 py-4">
|
|
151
|
+
<span className={`px-2 py-1 rounded-full text-xs font-medium ${
|
|
152
|
+
file.status === 'COMPLETED' ? 'bg-green-100 text-green-800' :
|
|
153
|
+
file.status === 'FAILED' ? 'bg-red-100 text-red-800' : 'bg-blue-100 text-blue-800'
|
|
154
|
+
}`}>
|
|
155
|
+
{file.status}
|
|
156
|
+
</span>
|
|
157
|
+
</td>
|
|
158
|
+
<td className="px-6 py-4 whitespace-nowrap">
|
|
159
|
+
{new Date(file.createdAt).toLocaleString()}
|
|
160
|
+
</td>
|
|
161
|
+
</tr>
|
|
162
|
+
))}
|
|
163
|
+
{files.length === 0 && !isLoading && (
|
|
164
|
+
<tr>
|
|
165
|
+
<td colSpan={7} className="px-6 py-4 text-center text-gray-500">
|
|
166
|
+
No files found.
|
|
167
|
+
</td>
|
|
168
|
+
</tr>
|
|
169
|
+
)}
|
|
170
|
+
</tbody>
|
|
171
|
+
</table>
|
|
172
|
+
</div>
|
|
173
|
+
{/* Pagination for Table */}
|
|
174
|
+
<div className="flex items-center justify-between px-6 py-4 border-t bg-gray-50">
|
|
175
|
+
<span className="text-sm text-gray-700">
|
|
176
|
+
Showing <span className="font-medium">{(page - 1) * limit + 1}</span> to <span className="font-medium">{Math.min(page * limit, total)}</span> of <span className="font-medium">{total}</span> results
|
|
177
|
+
</span>
|
|
178
|
+
<div className="flex gap-2">
|
|
179
|
+
<button
|
|
180
|
+
onClick={() => handlePageChange(page - 1)}
|
|
181
|
+
disabled={page === 1 || isLoading}
|
|
182
|
+
className="p-2 border rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
183
|
+
>
|
|
184
|
+
<ChevronLeft className="w-4 h-4" />
|
|
185
|
+
</button>
|
|
186
|
+
<button
|
|
187
|
+
onClick={() => handlePageChange(page + 1)}
|
|
188
|
+
disabled={page * limit >= total || isLoading}
|
|
189
|
+
className="p-2 border rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
190
|
+
>
|
|
191
|
+
<ChevronRight className="w-4 h-4" />
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
) : (
|
|
197
|
+
<>
|
|
198
|
+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
|
|
199
|
+
{files.map((file) => (
|
|
200
|
+
<div key={file.id} className="group relative border rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-md transition-shadow">
|
|
201
|
+
<a href={file.storageUrl || '#'} target="_blank" rel="noopener noreferrer" className="block aspect-square relative bg-gray-100 flex items-center justify-center">
|
|
202
|
+
{file.fileType.startsWith('image/') && file.storageUrl ? (
|
|
203
|
+
/* eslint-disable-next-line @next/next/no-img-element */
|
|
204
|
+
<img
|
|
205
|
+
src={file.storageUrl}
|
|
206
|
+
alt={file.fileName}
|
|
207
|
+
className="object-cover w-full h-full transition-transform duration-300 group-hover:scale-105"
|
|
208
|
+
loading="lazy"
|
|
209
|
+
/>
|
|
210
|
+
) : (
|
|
211
|
+
<File className="w-16 h-16 text-gray-400" />
|
|
212
|
+
)}
|
|
213
|
+
</a>
|
|
214
|
+
<div className="p-3">
|
|
215
|
+
<div className="flex items-center justify-between gap-2 mb-1">
|
|
216
|
+
{file.agent ? (
|
|
217
|
+
<Link href={`/${file.agent.agentName}`} className="text-xs font-medium text-blue-600 hover:underline truncate">
|
|
218
|
+
{file.agent.agentName}
|
|
219
|
+
</Link>
|
|
220
|
+
) : (
|
|
221
|
+
<span className="text-xs text-gray-400">No agent</span>
|
|
222
|
+
)}
|
|
223
|
+
<span className="text-[10px] text-gray-400 whitespace-nowrap">
|
|
224
|
+
{new Date(file.createdAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}
|
|
225
|
+
</span>
|
|
226
|
+
</div>
|
|
227
|
+
<p className="text-xs text-gray-600 truncate" title={file.fileName}>
|
|
228
|
+
{file.fileName}
|
|
229
|
+
</p>
|
|
230
|
+
<div className="mt-1 flex justify-between items-center">
|
|
231
|
+
<span className="text-[10px] text-gray-500">{(file.fileSize / 1024).toFixed(1)} KB</span>
|
|
232
|
+
<span className={`px-1.5 py-0.5 rounded-full text-[10px] font-medium ${
|
|
233
|
+
file.status === 'COMPLETED' ? 'bg-green-100 text-green-800' :
|
|
234
|
+
file.status === 'FAILED' ? 'bg-red-100 text-red-800' : 'bg-blue-100 text-blue-800'
|
|
235
|
+
}`}>
|
|
236
|
+
{file.status}
|
|
237
|
+
</span>
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
))}
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
{files.length === 0 && !isLoading && (
|
|
245
|
+
<div className="text-center text-gray-500 py-12">
|
|
246
|
+
No files found.
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
{/* Infinite Scroll Loader */}
|
|
251
|
+
<div className="py-8 flex justify-center" ref={observerTarget}>
|
|
252
|
+
{isLoading && (
|
|
253
|
+
<Loader2 className="w-8 h-8 animate-spin text-blue-500" />
|
|
254
|
+
)}
|
|
255
|
+
{!isLoading && !hasMore && files.length > 0 && (
|
|
256
|
+
<p className="text-gray-400 text-sm">No more files</p>
|
|
257
|
+
)}
|
|
258
|
+
</div>
|
|
259
|
+
</>
|
|
260
|
+
)}
|
|
261
|
+
</div>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { $getTableName } from '@/src/database/$getTableName';
|
|
4
|
+
import { TODO_any } from '@promptbook-local/types';
|
|
5
|
+
import { $provideSupabaseForServer } from '../../../database/$provideSupabaseForServer';
|
|
6
|
+
|
|
7
|
+
export type FileWithAgent = {
|
|
8
|
+
id: number;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
fileName: string;
|
|
11
|
+
fileSize: number;
|
|
12
|
+
fileType: string;
|
|
13
|
+
storageUrl: string | null;
|
|
14
|
+
shortUrl: string | null;
|
|
15
|
+
purpose: string;
|
|
16
|
+
status: 'UPLOADING' | 'COMPLETED' | 'FAILED';
|
|
17
|
+
agentId: number | null;
|
|
18
|
+
agent: {
|
|
19
|
+
id: number;
|
|
20
|
+
agentName: string;
|
|
21
|
+
} | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export async function listFiles(options: {
|
|
25
|
+
page: number;
|
|
26
|
+
limit: number;
|
|
27
|
+
}): Promise<{ files: FileWithAgent[]; total: number }> {
|
|
28
|
+
const { page, limit } = options;
|
|
29
|
+
const offset = (page - 1) * limit;
|
|
30
|
+
|
|
31
|
+
const supabase = $provideSupabaseForServer();
|
|
32
|
+
|
|
33
|
+
const {
|
|
34
|
+
data: files,
|
|
35
|
+
error,
|
|
36
|
+
count,
|
|
37
|
+
} = await supabase
|
|
38
|
+
.from(await $getTableName('File'))
|
|
39
|
+
.select(
|
|
40
|
+
`
|
|
41
|
+
*,
|
|
42
|
+
agent:agentId (
|
|
43
|
+
id,
|
|
44
|
+
agentName
|
|
45
|
+
)
|
|
46
|
+
`,
|
|
47
|
+
{ count: 'exact' },
|
|
48
|
+
)
|
|
49
|
+
.range(offset, offset + limit - 1)
|
|
50
|
+
.order('createdAt', { ascending: false });
|
|
51
|
+
|
|
52
|
+
if (error) {
|
|
53
|
+
console.error('Error fetching files:', error);
|
|
54
|
+
throw new Error(error.message);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
files: (files as TODO_any[]) || [],
|
|
59
|
+
total: count || 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ForbiddenPage } from '../../../components/ForbiddenPage/ForbiddenPage';
|
|
2
|
+
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
3
|
+
import { FilesGalleryClient } from './FilesGalleryClient';
|
|
4
|
+
|
|
5
|
+
export default async function FilesGalleryPage() {
|
|
6
|
+
const isAdmin = await isUserAdmin();
|
|
7
|
+
|
|
8
|
+
if (!isAdmin) {
|
|
9
|
+
return <ForbiddenPage />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return <FilesGalleryClient />;
|
|
13
|
+
}
|