From 6282161b5a4d015b7cfbf03ab6b2a497e0a6160e Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 22 Sep 2026 04:48:46 +0530 Subject: [PATCH 1/5] fix(frontend): replace stacked spinners on agent pages with skeletons --- frontend/src/agents/AgentLogs.tsx | 23 ++----- frontend/src/agents/AgentsList.tsx | 76 ++++++++++++++-------- frontend/src/components/SkeletonLoader.tsx | 22 +++++++ 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/frontend/src/agents/AgentLogs.tsx b/frontend/src/agents/AgentLogs.tsx index 9fbe165e..4651f15e 100644 --- a/frontend/src/agents/AgentLogs.tsx +++ b/frontend/src/agents/AgentLogs.tsx @@ -4,7 +4,6 @@ import { useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; import userService from '../api/services/userService'; -import Spinner from '../components/Spinner'; import { selectToken } from '../preferences/preferenceSlice'; import Analytics from '../settings/Analytics'; import Logs from '../settings/Logs'; @@ -67,22 +66,12 @@ export default function AgentLogs() { )} - {loadingAgent ? ( -
- -
- ) : ( - agent && - )} - {!loadingAgent && agent && } - {loadingAgent ? ( -
- -
- ) : ( - agent && ( - - ) + {agentId && (loadingAgent || agent) && ( + <> + + + + )} ); diff --git a/frontend/src/agents/AgentsList.tsx b/frontend/src/agents/AgentsList.tsx index 446e8295..d5d99f80 100644 --- a/frontend/src/agents/AgentsList.tsx +++ b/frontend/src/agents/AgentsList.tsx @@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { useNavigate, useSearchParams } from 'react-router-dom'; import userService from '../api/services/userService'; -import Spinner from '../components/Spinner'; +import SkeletonLoader from '../components/SkeletonLoader'; import { Button } from '../components/ui/button'; import { Input } from '../components/ui/input'; import { @@ -155,7 +155,14 @@ export default function AgentsList() { return hasAgentsInSection; }); + const showPageLoader = + activeFilter === 'all' && + agentSectionsConfig.some( + (config) => !isDataLoaded[config.id as AgentSectionId], + ); + const showSearchEmptyState = + !showPageLoader && searchQuery && hasAnyAgents && !hasFilteredResults && @@ -207,29 +214,46 @@ export default function AgentsList() { - {visibleSections.map((sectionConfig) => ( - - ))} + {showPageLoader ? ( +
+
+
+
+
+
+ +
+
+ ) : ( + visibleSections.map((sectionConfig) => ( + + )) + )} {showSearchEmptyState && (
@@ -574,8 +598,8 @@ function AgentSection({
{isLoading ? ( -
- +
+
) : ( <> diff --git a/frontend/src/components/SkeletonLoader.tsx b/frontend/src/components/SkeletonLoader.tsx index 00f23249..26a1fe2b 100644 --- a/frontend/src/components/SkeletonLoader.tsx +++ b/frontend/src/components/SkeletonLoader.tsx @@ -13,6 +13,7 @@ interface SkeletonLoaderProps { | 'sourceCards' | 'toolCards' | 'addToolCards' + | 'agentCards' | 'connectedState' | 'filesSection'; } @@ -264,6 +265,26 @@ const SkeletonLoader: React.FC = ({ ); + const renderAgentCards = () => ( + <> + {Array.from({ length: count }).map((_, idx) => ( +
+
+
+
+
+
+
+
+
+
+ ))} + + ); + const renderToolCards = () => ( <> {Array.from({ length: count }).map((_, idx) => ( @@ -325,6 +346,7 @@ const SkeletonLoader: React.FC = ({ sourceCards: renderSourceCards, toolCards: renderToolCards, addToolCards: renderAddToolCards, + agentCards: renderAgentCards, connectedState: renderConnectedState, filesSection: renderFilesSection, }; From a0ffafd19f23a3de223ba934a5a61fa5dfa6acfb Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 22 Sep 2026 05:28:13 +0530 Subject: [PATCH 2/5] fix(i18n): add missing keys and plural forms, translate agent card menu --- frontend/src/agents/AgentCard.tsx | 34 +++++++++++-------- .../src/conversation/ConversationMessages.tsx | 2 +- frontend/src/locale/de.json | 11 +++++- frontend/src/locale/en.json | 27 +++++++++++---- frontend/src/locale/es.json | 15 ++++++-- frontend/src/locale/jp.json | 11 +++++- frontend/src/locale/ru.json | 21 +++++++++++- frontend/src/locale/zh-TW.json | 11 +++++- frontend/src/locale/zh.json | 11 +++++- frontend/src/modals/MCPServerModal.tsx | 4 +-- frontend/src/modals/MoveToFolderModal.tsx | 2 +- frontend/src/preferences/PromptsModal.tsx | 4 +-- frontend/src/settings/Prompts.tsx | 9 +++-- frontend/src/settings/TestRetrievalModal.tsx | 2 +- 14 files changed, 126 insertions(+), 38 deletions(-) diff --git a/frontend/src/agents/AgentCard.tsx b/frontend/src/agents/AgentCard.tsx index 64ae3dc3..bea9b14e 100644 --- a/frontend/src/agents/AgentCard.tsx +++ b/frontend/src/agents/AgentCard.tsx @@ -75,7 +75,7 @@ export default function AgentCard({ template: [ { icon: Duplicate, - label: 'Duplicate', + label: t('modals.prompts.duplicate'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); handleDuplicate(); @@ -88,7 +88,7 @@ export default function AgentCard({ user: [ { icon: Monitoring, - label: 'Logs', + label: t('agents.form.buttons.logs'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); navigate(`/agents/logs/${agent.id}`); @@ -99,7 +99,7 @@ export default function AgentCard({ }, { icon: Edit, - label: 'Edit', + label: t('agents.edit'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); if (agent.agent_type === 'workflow') { @@ -144,7 +144,9 @@ export default function AgentCard({ ? [ { icon: agent.pinned ? UnPin : Pin, - label: agent.pinned ? 'Unpin' : 'Pin agent', + label: agent.pinned + ? t('agents.card.unpin') + : t('agents.card.pin'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); @@ -168,7 +170,7 @@ export default function AgentCard({ }, { icon: Trash, - label: 'Delete', + label: t('agents.form.buttons.delete'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); setDeleteConfirmation('ACTIVE'); @@ -185,7 +187,7 @@ export default function AgentCard({ team: [ { icon: Edit, - label: 'Edit', + label: t('agents.edit'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); if (agent.agent_type === 'workflow') { @@ -202,7 +204,9 @@ export default function AgentCard({ ? [ { icon: agent.pinned ? UnPin : Pin, - label: agent.pinned ? 'Unpin' : 'Pin agent', + label: agent.pinned + ? t('agents.card.unpin') + : t('agents.card.pin'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); @@ -217,7 +221,7 @@ export default function AgentCard({ shared: [ { icon: Link, - label: 'Open', + label: t('agents.card.open'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); navigate(`/agents/shared/${agent.shared_token}`); @@ -228,7 +232,7 @@ export default function AgentCard({ }, { icon: agent.pinned ? UnPin : Pin, - label: agent.pinned ? 'Unpin' : 'Pin agent', + label: agent.pinned ? t('agents.card.unpin') : t('agents.card.pin'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); @@ -239,7 +243,7 @@ export default function AgentCard({ }, { icon: Trash, - label: 'Remove', + label: t('agents.card.remove'), onClick: (e: SyntheticEvent) => { e.stopPropagation(); handleHideSharedAgent(); @@ -453,7 +457,9 @@ export default function AgentCard({ imgClassName="h-7 w-7 rounded-full object-contain" /> {agent.status === 'draft' && ( -

{`(Draft)`}

+

+ ({t('agents.card.draft')}) +

)}
@@ -469,15 +475,15 @@ export default function AgentCard({
{ handleDelete(); setDeleteConfirmation('INACTIVE'); }} - cancelLabel="Cancel" + cancelLabel={t('cancel')} variant="danger" /> handleInputChange('username', e.target.value)} - placeholder={t('settings.tools.mcp.username')} + placeholder={t('settings.tools.mcp.placeholders.username')} aria-invalid={!!errors.username || undefined} className="rounded-xl" /> @@ -542,7 +542,7 @@ export default function MCPServerModal({ type="password" value={formData.password} onChange={(e) => handleInputChange('password', e.target.value)} - placeholder={t('settings.tools.mcp.password')} + placeholder={t('settings.tools.mcp.placeholders.password')} aria-invalid={!!errors.password || undefined} className="rounded-xl" /> diff --git a/frontend/src/modals/MoveToFolderModal.tsx b/frontend/src/modals/MoveToFolderModal.tsx index cc7e3859..ae25db68 100644 --- a/frontend/src/modals/MoveToFolderModal.tsx +++ b/frontend/src/modals/MoveToFolderModal.tsx @@ -193,7 +193,7 @@ export default function MoveToFolderModal({ {isLoading ? (
- {t('loading')}... + {t('modals.searchConversations.loading')}
) : ( diff --git a/frontend/src/preferences/PromptsModal.tsx b/frontend/src/preferences/PromptsModal.tsx index 0491e188..b5c18187 100644 --- a/frontend/src/preferences/PromptsModal.tsx +++ b/frontend/src/preferences/PromptsModal.tsx @@ -387,7 +387,7 @@ function AddPrompt({ - + - No results found + + {t('settings.sources.noResults')} + {prompts.map((prompt) => { const isActive = selectedPrompt?.id === prompt.id; const canModify = prompt.type !== 'public'; diff --git a/frontend/src/settings/TestRetrievalModal.tsx b/frontend/src/settings/TestRetrievalModal.tsx index 6cf5daf1..6de11f45 100644 --- a/frontend/src/settings/TestRetrievalModal.tsx +++ b/frontend/src/settings/TestRetrievalModal.tsx @@ -246,7 +246,7 @@ export default function TestRetrievalModal({
{tr('resultSummary', { - total: result.total, + count: result.total, retriever: result.retriever, })} From c2e04fa7bf87a4c1acddde0d9980712584065beb Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 22 Sep 2026 10:02:56 +0100 Subject: [PATCH 3/5] Finish the MCP auth labels, the plural forms and the skeleton's status role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things the UI pass started but did not carry all the way. The MCP server dialog's Basic Authentication branch was fixed to use the label keys for its labels and the placeholder keys for its placeholders, but the API Key and Bearer Token branches above it in the same renderAuthFields were left reading placeholders.apiKey and placeholders.bearerToken as their