Skip to content

feat(platform): add StatGrid component, improve icons and UI components#592

Merged
yannickmonney merged 3 commits into
mainfrom
feat/ui-component-updates
Feb 27, 2026
Merged

feat(platform): add StatGrid component, improve icons and UI components#592
yannickmonney merged 3 commits into
mainfrom
feat/ui-component-updates

Conversation

@yannickmonney
Copy link
Copy Markdown
Contributor

@yannickmonney yannickmonney commented Feb 27, 2026

Introduce StatGrid for structured data display using definition lists, refactor icon components to use responsive sizing with cn(), improve checkbox layout with description alignment, refactor detail dialogs to use StatGrid, and update Storybook stories across UI components.

Summary by CodeRabbit

Release Notes

  • New Features

    • Icons now support flexible sizing customization.
    • Improved data display formatting across product details, customer information, and approval dialogs with better visual hierarchy.
  • Bug Fixes & Improvements

    • Enhanced checkbox layout with descriptions for better readability.
    • Refined spacing and flex behavior in dashboard layouts.
    • Improved icon sizing in login and sign-up flows.

Introduce StatGrid for structured data display using definition lists,
refactor icon components to use responsive sizing with cn(), improve
checkbox layout with description alignment, refactor detail dialogs to
use StatGrid, and update Storybook stories across UI components.
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Feb 27, 2026

Greptile Summary

This PR introduces a new StatGrid component for displaying structured data using semantic definition lists, and refactors multiple UI components to adopt it across the application.

Key Changes:

  • Added StatGrid and StatItem components with comprehensive tests and Storybook stories
  • Refactored 11 icon components to use responsive sizing (size-full with cn()) instead of fixed dimensions
  • Improved checkbox layout - descriptions now align properly with labels using flexbox
  • Updated multiple detail dialogs (approvals, messages, products, websites, integrations) to use StatGrid for consistent data display
  • Updated 40+ Storybook stories across UI components for better documentation

Benefits:

  • Consistent, accessible data display using semantic HTML (<dl>, <dt>, <dd>)
  • Responsive icon sizing that adapts to container size
  • Better UX for checkboxes with descriptions
  • Reduced code duplication across dialog components

Confidence Score: 5/5

  • This PR is safe to merge with no identified issues
  • Well-structured refactoring with comprehensive test coverage for new components, consistent patterns across all changes, proper use of semantic HTML, and no breaking changes to existing functionality
  • No files require special attention

Important Files Changed

Filename Overview
services/platform/app/components/ui/data-display/stat-grid.tsx New StatGrid component using definition lists with responsive column layouts - clean implementation
services/platform/app/components/ui/data-display/stat-item.tsx StatItem component using semantic dt/dd elements with proper colSpan support
services/platform/app/components/ui/forms/checkbox.tsx Improved checkbox layout - description now aligns properly with label using flex column
services/platform/app/features/approvals/components/approval-detail-dialog.tsx Refactored to use StatGrid for displaying approval metadata - cleaner structured data display
services/platform/app/features/chat/components/message-info-dialog.tsx Uses StatGrid for token usage and performance metrics display
services/platform/app/features/products/components/product-view-dialog.tsx Product details now displayed with StatGrid for consistent UI
services/platform/app/features/websites/components/website-view-dialog.tsx Website details refactored to use StatGrid with colSpan support for longer fields

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class StatGrid {
        +items: StatGridItem[]
        +cols: 1|2|3|4
        +className: string
        +render() dl
    }
    
    class StatItem {
        +label: string
        +children: ReactNode
        +colSpan: 1|2
        +className: string
        +render() div with dt/dd
    }
    
    class StatGridItem {
        +label: string
        +value: ReactNode
        +colSpan: 1|2
    }
    
    class ApprovalDetailDialog {
        +uses StatGrid for metadata
    }
    
    class MessageInfoDialog {
        +uses StatGrid for tokens
        +uses StatGrid for performance
    }
    
    class ProductViewDialog {
        +uses StatGrid for details
    }
    
    class WebsiteViewDialog {
        +uses StatGrid for info
    }
    
    class IntegrationDetails {
        +uses StatGrid for SQL config
    }
    
    StatGrid --> StatItem : renders
    StatGrid ..> StatGridItem : uses
    ApprovalDetailDialog --> StatGrid : uses
    MessageInfoDialog --> StatGrid : uses
    ProductViewDialog --> StatGrid : uses
    WebsiteViewDialog --> StatGrid : uses
    IntegrationDetails --> StatGrid : uses
Loading

Last reviewed commit: f2f4a42

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 27, 2026

📝 Walkthrough

Walkthrough

This PR refactors multiple UI components and icon files to improve styling and layout patterns. It updates approximately 12 icon components (CirculyIcon, EnterKeyIcon, GmailIcon, LocaleIcon, MicrosoftIcon, OneDriveIcon, OutlookIcon, ProtelIcon, SharePointIcon, ShopifyIcon, WebsiteIcon) to use a cn utility function for className composition, replacing fixed width/height attributes. A new StatGrid component is introduced for displaying labeled statistics in grid layouts, with StatItem modified to support column spanning via semantic <dt>/<dd> elements. Over 20 Storybook story files are converted from render-function-based to args-based configuration patterns. Feature components across approvals, chat, customers, products, integrations, and websites are refactored to adopt the new StatGrid component instead of Field/FieldGroup patterns. Minor CSS class additions enhance flex and sizing behavior in layout components. Configuration is updated with a new routeFileIgnorePattern in tsr.config.json.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: adding a StatGrid component, improving icons, and updating UI components. It directly reflects the primary objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ui-component-updates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
services/platform/app/components/ui/layout/separator.stories.tsx (1)

48-59: 🧹 Nitpick | 🔵 Trivial

Args-based migration is correct; consider applying consistently to other stories.

The Horizontal story correctly adopts the args-based pattern, enabling dynamic prop control in Storybook. For consistency across the file, consider also migrating Vertical (line 61) and InToolbar (line 96) stories, which still use hardcoded orientation="vertical" props.

♻️ Suggested refactor for Vertical story
 export const Vertical: Story = {
+  args: {
+    orientation: 'vertical',
+  },
-  render: () => (
+  render: (args) => (
     <div className="flex h-8 items-center gap-4">
       <span className="text-sm">Item 1</span>
-      <Separator orientation="vertical" />
+      <Separator {...args} />
       <span className="text-sm">Item 2</span>
-      <Separator orientation="vertical" />
+      <Separator {...args} />
       <span className="text-sm">Item 3</span>
     </div>
   ),
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/ui/layout/separator.stories.tsx` around
lines 48 - 59, The Horizontal story now uses args to control Separator props;
update the other stories (Vertical and InToolbar) to the same args-based pattern
by moving the hardcoded orientation="vertical" into their args objects and using
render: (args) => <Separator {...args} /> (or wrap in the same container JSX
used by those stories), so both Vertical and InToolbar accept dynamic props via
args while still rendering the Separator component.
services/platform/app/components/icons/outlook-icon.tsx (1)

1-9: 🧹 Nitpick | 🔵 Trivial

LGTM! Consider adding aria-label for consistency.

The cn utility integration is correct. However, this icon lacks an aria-label attribute while other icons in this PR (e.g., LocaleIcon, EnterKeyIcon, CirculyIcon, ProtelIcon) include one. For consistency and accessibility, consider adding aria-label="Outlook icon" or aria-hidden if purely decorative.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/icons/outlook-icon.tsx` around lines 1 - 9,
The OutlookIcon component's <svg> (in the OutlookIcon function) is missing an
accessibility attribute for consistency; update the SVG element inside
OutlookIcon to include either aria-label="Outlook icon" (if it conveys meaning)
or aria-hidden="true" (if decorative) while keeping the existing className usage
via cn and props signature unchanged so other icons remain consistent.
services/platform/app/components/icons/gmail-icon.tsx (1)

1-11: 🧹 Nitpick | 🔵 Trivial

LGTM! Consider adding accessibility attribute for consistency.

The cn utility integration is correct. Similar to OutlookIcon, this component lacks an aria-label or aria-hidden attribute while other icons in this PR include them. Consider adding one for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/icons/gmail-icon.tsx` around lines 1 - 11,
GmailIcon is missing an accessibility attribute—match other icons (like
OutlookIcon) by adding either an aria-label when the icon is meaningful or
aria-hidden="true" when decorative; update the GmailIcon JSX root <svg> to
include the chosen attribute (or accept and forward an ariaLabel prop) so
accessibility usage is consistent with the other icon components and the cn
utility usage remains unchanged.
services/platform/app/features/websites/components/website-view-dialog.tsx (1)

104-120: ⚠️ Potential issue | 🟡 Minor

Localize hardcoded StatGrid labels.

Line 107 ('domain') and Line 119 ('apiEndpoint') bypass i18n and will render untranslated strings in localized UIs.

💡 Suggested patch
-            label: 'domain',
+            label: t('viewDialog.domain'),
@@
-            label: 'apiEndpoint',
+            label: t('viewDialog.apiEndpoint'),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/websites/components/website-view-dialog.tsx`
around lines 104 - 120, The StatGrid items currently contain hardcoded label
keys ('domain' and 'apiEndpoint') in the items array inside
website-view-dialog.tsx; replace those literal strings with calls to the app's
i18n helper (e.g., useTranslation/useIntl and t(...) or formatMessage(...)) so
the labels are localized before being passed into StatGrid, updating the items
construction in the WebsiteViewDialog component to use translated values for the
'domain' and 'apiEndpoint' labels.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@services/platform/app/components/icons/onedrive-icon.tsx`:
- Line 5: Add a non-empty <title> element for the SVG in the OnedriveIcon
component to satisfy the lint rule; insert a unique id (e.g., titleId) and
render <title id={titleId}>OneDrive</title> inside the <svg>, then add
aria-labelledby={titleId} (or role="img") on the same <svg> element instead of
aria-hidden so screen readers can read the title; update the component props to
generate/accept titleId if needed and keep existing className/cn usage intact.

In `@services/platform/app/components/ui/data-display/selectable-row.stories.tsx`:
- Around line 52-55: The stories render a block-level <Text> inside the
SelectableRow button causing invalid semantics; update the story args so the
children use an inline element (e.g., change the Text usage to Text with
as="span" or another phrasing element) for both the unselected and selected
story entries (look for the SelectableRow story args where children is currently
<Text>Unselected row</Text> and the other case at the following story with
children <Text>Selected row</Text> and replace them accordingly).

In `@services/platform/app/components/ui/data-display/stat-grid.stories.tsx`:
- Around line 90-121: The story "WithColSpan" currently relies on an implicit
2-column default but doesn't declare it; update the Story object (WithColSpan)
to explicitly set the grid column count so the colSpan: 2 example is
self-documenting — add a cols: 2 (or the appropriate prop name your StatGrid
expects) to the args alongside items so the example clearly shows the full-width
behavior for a 2-column grid.

In `@services/platform/app/components/ui/data-display/stat-grid.tsx`:
- Around line 42-46: The current map uses item.label as the React key which can
collide; update the StatGridItem type to include an optional unique id (e.g.,
id?: string) and change the mapping in StatGrid component to use a stable key
fallback like item.id ?? item.label ?? index (use the array index only as last
resort). Ensure StatItem rendering still receives label and colSpan props and
keep the key logic inside the items.map callback so duplicate labels no longer
cause key collisions.

In `@services/platform/app/components/ui/feedback/progress.stories.tsx`:
- Around line 150-163: The story hardcodes the label and percentage so Storybook
controls don't update the surrounding text; update UploadExample's render to
read from the story args (use args.label and args.value) and render the label
and percentage dynamically alongside <Progress {...args} /> so changing
args.value or args.label in controls updates both the bar and the displayed
text.

In `@services/platform/app/components/ui/feedback/spinner.stories.tsx`:
- Around line 101-107: The button in the story rendering the Spinner lacks an
explicit type and therefore defaults to type="submit"; update the JSX for the
button (the element wrapping <Spinner {...args} /> and "Submitting...") to
include an explicit type attribute (e.g., type="button") to prevent accidental
form submissions and follow accessibility/best-practice guidelines.

In `@services/platform/app/components/ui/overlays/dropdown-menu.stories.tsx`:
- Around line 207-214: Replace the semantically incorrect LogOut icon used for
the destructive "Delete" menu item: add Trash2 to the lucide-react import list
and change the menu item icon reference from LogOut to Trash2 in the dropdown
menu item (the object with type: 'item', label: 'Delete', destructive: true, and
onClick). Ensure the import and the menu item’s icon property both reference
Trash2 so the delete action uses a trash icon.

In `@services/platform/app/components/ui/typography/heading.stories.tsx`:
- Around line 64-69: The story sets args.truncate = true but doesn’t constrain
the container width so ellipsis won’t appear; update the Heading story that
defines the args object (the one with level, size, truncate, children) to either
wrap the rendered Heading in a fixed/max-width container (similar to the
Truncated story) or remove the truncate prop from args so the story accurately
demonstrates behavior.

In `@services/platform/app/components/ui/typography/text.stories.tsx`:
- Line 90: The story uses a sample string that looks like a production secret
("sk_live_abc123def456") which can trigger secret scanners; update the story
args (the object assigned to args in the Text story) to use a neutral example
token (e.g., "pk_test_example_123", "example_token_ABC123", or simply
"example-token") instead of any "sk_live_" prefixed value so the Storybook
example remains clear without resembling real secrets — locate and edit the args
entry that currently sets as: 'span', variant: 'code', children:
'sk_live_abc123def456' and replace the children value with a harmless example
token.

In `@services/platform/app/features/chat/components/message-info-dialog.tsx`:
- Around line 200-217: The IIFE that builds perfItems in message-info-dialog.tsx
should be extracted into a memoized value using useMemo to match the token items
pattern; replace the IIFE with a const perfItems = useMemo(() => { /* build
array from metadata.durationMs and metadata.timeToFirstTokenMs, filter out
null/undefined, map to {label: t(`messageInfo.${key}`), value:
<Text>{(value/1000).toFixed(2)}s</Text>} */ }, [metadata.durationMs,
metadata.timeToFirstTokenMs, t]) and render the Field/StatGrid conditionally
based on perfItems.length > 0 as before.
- Around line 157-198: Extract the IIFE that builds tokenItems into a top-level
constant (preferably using useMemo) to improve readability and memoize
calculations: create a const tokenItems = useMemo(() => { ... }, [metadata, t,
tCommon, locale]) that constructs the same array (including the conditional
ContextWindowToken entry and the filtered/mapped token tuples) and then replace
the inline IIFE in the JSX with a simple conditional render like
tokenItems.length > 0 && (<Field ...><StatGrid ... items={tokenItems}
/></Field>). Ensure you reference the same symbols (metadata,
ContextWindowToken, StatGrid, Field, t, tCommon, locale, formatNumber) and keep
the same filtering predicate ([number | undefined, string] => entry[0] != null
&& entry[0] > 0) so behavior is unchanged.

In
`@services/platform/app/features/customers/components/customer-information.tsx`:
- Around line 49-51: The UI currently hardcodes a fallback of 'en' when
customer.locale is missing in the customer-information component; update the
locale cell (the object with label: t('labels.locale') and value) to avoid
showing 'en' as a presumed locale and instead render a proper "not available"
indicator or the true system default: replace the hardcoded string usage of 'en'
with a translation placeholder (e.g., t('notAvailable')) or a conditional that
displays t('notAvailable') when customer.locale is falsy (or use the configured
system default source if available), updating the value expression where
customer.locale is referenced.

In
`@services/platform/app/features/settings/integrations/components/integration-details.tsx`:
- Around line 348-357: The displayed readOnly strings are hardcoded "Yes"/"No";
replace them with translated values by calling the i18n function (e.g., use
t('common.yes') and t('common.no')) where the value is set for
integration.sqlConnectionConfig.readOnly inside the integration-details.tsx
component so the label value becomes integration.sqlConnectionConfig.readOnly ?
t('common.yes') : t('common.no'); ensure you import/use the existing t function
already used in this file.

In
`@services/platform/app/features/settings/integrations/components/integration-manage/integration-active-view.tsx`:
- Around line 88-120: Replace the hardcoded/internal labels ('apiKey',
'accessToken', 'domain', 'apiEndpoint') used when building the displayed items
with user-facing, localized strings via the translation function (t). Update the
label entries in the arrays constructed in integration-active-view.tsx (the
objects created when secretBindings/SENSITIVE_KEYS, oauth2 auth branch using
hasOAuth2Config, and the integration.connectionConfig?.domain and ?.apiEndpoint
branches) to call t(...) with appropriate keys (e.g.
integrations.manageDialog.apiKey, integrations.manageDialog.accessToken,
integrations.manageDialog.domain, integrations.manageDialog.apiEndpoint) so the
UI shows translated labels consistently.

---

Outside diff comments:
In `@services/platform/app/components/icons/gmail-icon.tsx`:
- Around line 1-11: GmailIcon is missing an accessibility attribute—match other
icons (like OutlookIcon) by adding either an aria-label when the icon is
meaningful or aria-hidden="true" when decorative; update the GmailIcon JSX root
<svg> to include the chosen attribute (or accept and forward an ariaLabel prop)
so accessibility usage is consistent with the other icon components and the cn
utility usage remains unchanged.

In `@services/platform/app/components/icons/outlook-icon.tsx`:
- Around line 1-9: The OutlookIcon component's <svg> (in the OutlookIcon
function) is missing an accessibility attribute for consistency; update the SVG
element inside OutlookIcon to include either aria-label="Outlook icon" (if it
conveys meaning) or aria-hidden="true" (if decorative) while keeping the
existing className usage via cn and props signature unchanged so other icons
remain consistent.

In `@services/platform/app/components/ui/layout/separator.stories.tsx`:
- Around line 48-59: The Horizontal story now uses args to control Separator
props; update the other stories (Vertical and InToolbar) to the same args-based
pattern by moving the hardcoded orientation="vertical" into their args objects
and using render: (args) => <Separator {...args} /> (or wrap in the same
container JSX used by those stories), so both Vertical and InToolbar accept
dynamic props via args while still rendering the Separator component.

In `@services/platform/app/features/websites/components/website-view-dialog.tsx`:
- Around line 104-120: The StatGrid items currently contain hardcoded label keys
('domain' and 'apiEndpoint') in the items array inside website-view-dialog.tsx;
replace those literal strings with calls to the app's i18n helper (e.g.,
useTranslation/useIntl and t(...) or formatMessage(...)) so the labels are
localized before being passed into StatGrid, updating the items construction in
the WebsiteViewDialog component to use translated values for the 'domain' and
'apiEndpoint' labels.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 189911a and f2f4a42.

📒 Files selected for processing (66)
  • services/platform/app/components/icons/circuly-icon.tsx
  • services/platform/app/components/icons/enter-key-icon.tsx
  • services/platform/app/components/icons/gmail-icon.tsx
  • services/platform/app/components/icons/locale-icon.tsx
  • services/platform/app/components/icons/microsoft-icon.tsx
  • services/platform/app/components/icons/onedrive-icon.tsx
  • services/platform/app/components/icons/outlook-icon.tsx
  • services/platform/app/components/icons/protel-icon.tsx
  • services/platform/app/components/icons/sharepoint-icon.tsx
  • services/platform/app/components/icons/shopify-icon.tsx
  • services/platform/app/components/icons/website-icon.tsx
  • services/platform/app/components/ui/data-display/file-preview-card.tsx
  • services/platform/app/components/ui/data-display/inline-code.stories.tsx
  • services/platform/app/components/ui/data-display/selectable-row.stories.tsx
  • services/platform/app/components/ui/data-display/stat-grid.stories.tsx
  • services/platform/app/components/ui/data-display/stat-grid.test.tsx
  • services/platform/app/components/ui/data-display/stat-grid.tsx
  • services/platform/app/components/ui/data-display/stat-item.stories.tsx
  • services/platform/app/components/ui/data-display/stat-item.test.tsx
  • services/platform/app/components/ui/data-display/stat-item.tsx
  • services/platform/app/components/ui/data-display/table-date-cell.stories.tsx
  • services/platform/app/components/ui/dialog/form-dialog.stories.tsx
  • services/platform/app/components/ui/feedback/alert.stories.tsx
  • services/platform/app/components/ui/feedback/badge.stories.tsx
  • services/platform/app/components/ui/feedback/progress.stories.tsx
  • services/platform/app/components/ui/feedback/spinner.stories.tsx
  • services/platform/app/components/ui/feedback/validation-check-item.stories.tsx
  • services/platform/app/components/ui/forms/checkbox-group.stories.tsx
  • services/platform/app/components/ui/forms/checkbox.tsx
  • services/platform/app/components/ui/forms/description.stories.tsx
  • services/platform/app/components/ui/forms/form-section.stories.tsx
  • services/platform/app/components/ui/forms/radio-group.stories.tsx
  • services/platform/app/components/ui/forms/search-input.stories.tsx
  • services/platform/app/components/ui/layout/action-row.stories.tsx
  • services/platform/app/components/ui/layout/bordered-section.stories.tsx
  • services/platform/app/components/ui/layout/card.stories.tsx
  • services/platform/app/components/ui/layout/page-section.stories.tsx
  • services/platform/app/components/ui/layout/separator.stories.tsx
  • services/platform/app/components/ui/logo/logo.stories.tsx
  • services/platform/app/components/ui/navigation/collapsible-details.stories.tsx
  • services/platform/app/components/ui/navigation/tab-navigation.stories.tsx
  • services/platform/app/components/ui/navigation/tabs.stories.tsx
  • services/platform/app/components/ui/overlays/dropdown-menu.stories.tsx
  • services/platform/app/components/ui/overlays/popover.stories.tsx
  • services/platform/app/components/ui/overlays/tooltip.stories.tsx
  • services/platform/app/components/ui/primitives/button.stories.tsx
  • services/platform/app/components/ui/primitives/icon-button.stories.tsx
  • services/platform/app/components/ui/typography/heading.stories.tsx
  • services/platform/app/components/ui/typography/text.stories.tsx
  • services/platform/app/features/approvals/components/approval-detail-dialog.tsx
  • services/platform/app/features/chat/components/chat-input.tsx
  • services/platform/app/features/chat/components/message-info-dialog.tsx
  • services/platform/app/features/chat/components/sub-agent-details-dialog.tsx
  • services/platform/app/features/customers/components/customer-information.tsx
  • services/platform/app/features/products/components/product-view-dialog.tsx
  • services/platform/app/features/settings/integrations/components/integration-details.tsx
  • services/platform/app/features/settings/integrations/components/integration-manage/integration-active-view.tsx
  • services/platform/app/features/settings/integrations/components/sso-config-dialog.tsx
  • services/platform/app/features/vendors/components/vendor-information.tsx
  • services/platform/app/features/websites/components/website-view-dialog.tsx
  • services/platform/app/routes/_auth/log-in.tsx
  • services/platform/app/routes/_auth/sign-up.tsx
  • services/platform/app/routes/dashboard/$id/_knowledge.tsx
  • services/platform/app/routes/dashboard/$id/approvals.tsx
  • services/platform/app/routes/dashboard/$id/settings.tsx
  • services/platform/tsr.config.json

export const OneDriveIcon = ({ className }: { className?: string }) => {
return (
<svg viewBox="0 0 31 20" className={className} aria-hidden>
<svg viewBox="0 0 31 20" className={cn('size-full', className)} aria-hidden>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix Biome a11y lint failure on SVG title.

Line 5 currently triggers lint/a11y/noSvgWithoutTitle. Add a non-empty <title> (or adjust accessibility semantics) to unblock lint.

Proposed fix
-    <svg viewBox="0 0 31 20" className={cn('size-full', className)} aria-hidden>
+    <svg
+      viewBox="0 0 31 20"
+      className={cn('size-full', className)}
+      aria-hidden
+    >
+      <title>OneDrive</title>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<svg viewBox="0 0 31 20" className={cn('size-full', className)} aria-hidden>
<svg
viewBox="0 0 31 20"
className={cn('size-full', className)}
aria-hidden
>
<title>OneDrive</title>
🧰 Tools
🪛 Biome (2.4.4)

[error] 5-5: Alternative text title element cannot be empty

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/icons/onedrive-icon.tsx` at line 5, Add a
non-empty <title> element for the SVG in the OnedriveIcon component to satisfy
the lint rule; insert a unique id (e.g., titleId) and render <title
id={titleId}>OneDrive</title> inside the <svg>, then add
aria-labelledby={titleId} (or role="img") on the same <svg> element instead of
aria-hidden so screen readers can read the title; update the component props to
generate/accept titleId if needed and keep existing className/cn usage intact.

Comment on lines +52 to +55
args: {
selected: false,
children: <Text>Unselected row</Text>,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use inline text tags inside SelectableRow button content.

Text defaults to a <p> tag, so these stories currently render a block <p> inside a <button>. Please switch to as="span" (or another phrasing element) for valid semantics.

Suggested fix
 export const Default: Story = {
   args: {
     selected: false,
-    children: <Text>Unselected row</Text>,
+    children: <Text as="span">Unselected row</Text>,
   },
 };

 export const Selected: Story = {
   args: {
     selected: true,
-    children: <Text>Selected row</Text>,
+    children: <Text as="span">Selected row</Text>,
   },

Also applies to: 59-62

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/ui/data-display/selectable-row.stories.tsx`
around lines 52 - 55, The stories render a block-level <Text> inside the
SelectableRow button causing invalid semantics; update the story args so the
children use an inline element (e.g., change the Text usage to Text with
as="span" or another phrasing element) for both the unselected and selected
story entries (look for the SelectableRow story args where children is currently
<Text>Unselected row</Text> and the other case at the following story with
children <Text>Selected row</Text> and replace them accordingly).

Comment on lines +90 to +121
export const WithColSpan: Story = {
args: {
items: [
{ label: 'Domain', value: <Text>example.com</Text> },
{
label: 'Status',
value: (
<Badge variant="green" dot>
Active
</Badge>
),
},
{
label: 'Description',
value: (
<Text>
A full-width stat item that spans both columns in the grid.
</Text>
),
colSpan: 2,
},
],
},
parameters: {
docs: {
description: {
story:
'Use `colSpan: 2` on an item to span the full width of a 2-column grid.',
},
},
},
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider clarifying the default column count in the colSpan example.

The story description mentions "full width of a 2-column grid," but the story doesn't explicitly set cols. If 2 columns is the default, this works correctly. However, making it explicit would improve self-documentation.

📝 Optional: Make the column count explicit
 export const WithColSpan: Story = {
   args: {
+    cols: 2,
     items: [
       { label: 'Domain', value: <Text>example.com</Text> },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const WithColSpan: Story = {
args: {
items: [
{ label: 'Domain', value: <Text>example.com</Text> },
{
label: 'Status',
value: (
<Badge variant="green" dot>
Active
</Badge>
),
},
{
label: 'Description',
value: (
<Text>
A full-width stat item that spans both columns in the grid.
</Text>
),
colSpan: 2,
},
],
},
parameters: {
docs: {
description: {
story:
'Use `colSpan: 2` on an item to span the full width of a 2-column grid.',
},
},
},
};
export const WithColSpan: Story = {
args: {
cols: 2,
items: [
{ label: 'Domain', value: <Text>example.com</Text> },
{
label: 'Status',
value: (
<Badge variant="green" dot>
Active
</Badge>
),
},
{
label: 'Description',
value: (
<Text>
A full-width stat item that spans both columns in the grid.
</Text>
),
colSpan: 2,
},
],
},
parameters: {
docs: {
description: {
story:
'Use `colSpan: 2` on an item to span the full width of a 2-column grid.',
},
},
},
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/ui/data-display/stat-grid.stories.tsx`
around lines 90 - 121, The story "WithColSpan" currently relies on an implicit
2-column default but doesn't declare it; update the Story object (WithColSpan)
to explicitly set the grid column count so the colSpan: 2 example is
self-documenting — add a cols: 2 (or the appropriate prop name your StatGrid
expects) to the args alongside items so the example clearly shows the full-width
behavior for a 2-column grid.

Comment on lines +42 to +46
{items.map((item) => (
<StatItem key={item.label} label={item.label} colSpan={item.colSpan}>
{item.value}
</StatItem>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential key collision with duplicate labels.

Using item.label as the React key could cause issues if the same label appears multiple times in the items array. Consider adding an optional id field to StatGridItem or using the array index as a fallback.

🔑 Proposed fix to handle duplicate labels

Option 1: Use index as fallback key:

       {items.map((item, index) => (
-        <StatItem key={item.label} label={item.label} colSpan={item.colSpan}>
+        <StatItem key={`${item.label}-${index}`} label={item.label} colSpan={item.colSpan}>
           {item.value}
         </StatItem>
       ))}

Option 2: Add optional id to interface:

 export interface StatGridItem {
+  id?: string;
   label: string;
   value: ReactNode;
   colSpan?: 1 | 2;
 }

Then use:

-        <StatItem key={item.label} label={item.label} colSpan={item.colSpan}>
+        <StatItem key={item.id ?? item.label} label={item.label} colSpan={item.colSpan}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{items.map((item) => (
<StatItem key={item.label} label={item.label} colSpan={item.colSpan}>
{item.value}
</StatItem>
))}
{items.map((item, index) => (
<StatItem key={`${item.label}-${index}`} label={item.label} colSpan={item.colSpan}>
{item.value}
</StatItem>
))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/ui/data-display/stat-grid.tsx` around lines
42 - 46, The current map uses item.label as the React key which can collide;
update the StatGridItem type to include an optional unique id (e.g., id?:
string) and change the mapping in StatGrid component to use a stable key
fallback like item.id ?? item.label ?? index (use the array index only as last
resort). Ensure StatItem rendering still receives label and colSpan props and
keep the key logic inside the items.map callback so duplicate labels no longer
cause key collisions.

Comment on lines 150 to 163
export const UploadExample: Story = {
render: () => (
args: {
value: 67,
label: 'Uploading document.pdf',
},
render: (args) => (
<div className="flex flex-col gap-2">
<div className="flex justify-between text-sm">
<span>Uploading document.pdf</span>
<span>67%</span>
</div>
<Progress value={67} label="Uploading document.pdf" />
<Progress {...args} />
</div>
),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Hardcoded text won't sync with Storybook controls.

The displayed text ("Uploading document.pdf" on line 158 and "67%" on line 159) is hardcoded, but the args can be changed via Storybook controls. This means adjusting value or label in the controls panel will update the progress bar but not the surrounding text.

♻️ Suggested fix to derive text from args
 export const UploadExample: Story = {
   args: {
     value: 67,
     label: 'Uploading document.pdf',
   },
   render: (args) => (
     <div className="flex flex-col gap-2">
       <div className="flex justify-between text-sm">
-        <span>Uploading document.pdf</span>
-        <span>67%</span>
+        <span>{args.label}</span>
+        <span>{args.value}%</span>
       </div>
       <Progress {...args} />
     </div>
   ),
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const UploadExample: Story = {
render: () => (
args: {
value: 67,
label: 'Uploading document.pdf',
},
render: (args) => (
<div className="flex flex-col gap-2">
<div className="flex justify-between text-sm">
<span>Uploading document.pdf</span>
<span>67%</span>
</div>
<Progress value={67} label="Uploading document.pdf" />
<Progress {...args} />
</div>
),
export const UploadExample: Story = {
args: {
value: 67,
label: 'Uploading document.pdf',
},
render: (args) => (
<div className="flex flex-col gap-2">
<div className="flex justify-between text-sm">
<span>{args.label}</span>
<span>{args.value}%</span>
</div>
<Progress {...args} />
</div>
),
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/components/ui/feedback/progress.stories.tsx` around
lines 150 - 163, The story hardcodes the label and percentage so Storybook
controls don't update the surrounding text; update UploadExample's render to
read from the story args (use args.label and args.value) and render the label
and percentage dynamically alongside <Progress {...args} /> so changing
args.value or args.label in controls updates both the bar and the displayed
text.

Comment on lines +157 to +198
{(() => {
const tokenItems: StatGridItem[] = [
...(metadata.contextWindow
? [
{
label: t('messageInfo.contextWindow'),
value: (
<ContextWindowToken
contextWindow={metadata.contextWindow}
contextStats={metadata.contextStats}
t={t}
tCommon={tCommon}
locale={locale}
/>
),
},
]
: []),
...(
[
[metadata.inputTokens, 'input'],
[metadata.outputTokens, 'output'],
[metadata.totalTokens, 'total'],
[metadata.reasoningTokens, 'reasoning'],
[metadata.cachedInputTokens, 'cached'],
] as [number | undefined, string][]
)
.filter(
(entry): entry is [number, string] =>
entry[0] != null && entry[0] > 0,
)
.map(([value, key]) => ({
label: t(`messageInfo.${key}`),
value: <Text>{formatNumber(value, locale)}</Text>,
})),
];
return tokenItems.length > 0 ? (
<Field label={t('messageInfo.tokenUsage')}>
<StatGrid className="text-sm" items={tokenItems} />
</Field>
) : null;
})()}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider extracting IIFE logic to improve readability.

The inline IIFE pattern (() => { ... })() works but adds visual complexity. Consider extracting the tokenItems computation to a useMemo or a variable declared before the return statement for better readability and potential memoization benefits.

♻️ Suggested refactor to extract tokenItems

Move the token items computation before the return statement:

const tokenItems: StatGridItem[] = useMemo(() => [
  ...(metadata?.contextWindow
    ? [{
        label: t('messageInfo.contextWindow'),
        value: (
          <ContextWindowToken
            contextWindow={metadata.contextWindow}
            contextStats={metadata.contextStats}
            t={t}
            tCommon={tCommon}
            locale={locale}
          />
        ),
      }]
    : []),
  ...([
    [metadata?.inputTokens, 'input'],
    [metadata?.outputTokens, 'output'],
    [metadata?.totalTokens, 'total'],
    [metadata?.reasoningTokens, 'reasoning'],
    [metadata?.cachedInputTokens, 'cached'],
  ] as [number | undefined, string][])
    .filter((entry): entry is [number, string] => entry[0] != null && entry[0] > 0)
    .map(([value, key]) => ({
      label: t(`messageInfo.${key}`),
      value: <Text>{formatNumber(value, locale)}</Text>,
    })),
], [metadata, t, tCommon, locale]);

Then in the JSX:

{tokenItems.length > 0 && (
  <Field label={t('messageInfo.tokenUsage')}>
    <StatGrid className="text-sm" items={tokenItems} />
  </Field>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/chat/components/message-info-dialog.tsx`
around lines 157 - 198, Extract the IIFE that builds tokenItems into a top-level
constant (preferably using useMemo) to improve readability and memoize
calculations: create a const tokenItems = useMemo(() => { ... }, [metadata, t,
tCommon, locale]) that constructs the same array (including the conditional
ContextWindowToken entry and the filtered/mapped token tuples) and then replace
the inline IIFE in the JSX with a simple conditional render like
tokenItems.length > 0 && (<Field ...><StatGrid ... items={tokenItems}
/></Field>). Ensure you reference the same symbols (metadata,
ContextWindowToken, StatGrid, Field, t, tCommon, locale, formatNumber) and keep
the same filtering predicate ([number | undefined, string] => entry[0] != null
&& entry[0] > 0) so behavior is unchanged.

Comment on lines +200 to +217
{(() => {
const perfItems: StatGridItem[] = (
[
[metadata.durationMs, 'duration'],
[metadata.timeToFirstTokenMs, 'timeToFirstToken'],
] as [number | undefined, string][]
)
.filter((entry): entry is [number, string] => entry[0] != null)
.map(([value, key]) => ({
label: t(`messageInfo.${key}`),
value: <Text>{(value / 1000).toFixed(2)}s</Text>,
}));
return perfItems.length > 0 ? (
<Field label={t('messageInfo.performance')}>
<StatGrid className="text-sm" items={perfItems} />
</Field>
) : null;
})()}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Same IIFE pattern observation applies here.

The performance items IIFE follows the same pattern. Consider extracting to a useMemo alongside the token items for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/chat/components/message-info-dialog.tsx`
around lines 200 - 217, The IIFE that builds perfItems in
message-info-dialog.tsx should be extracted into a memoized value using useMemo
to match the token items pattern; replace the IIFE with a const perfItems =
useMemo(() => { /* build array from metadata.durationMs and
metadata.timeToFirstTokenMs, filter out null/undefined, map to {label:
t(`messageInfo.${key}`), value: <Text>{(value/1000).toFixed(2)}s</Text>} */ },
[metadata.durationMs, metadata.timeToFirstTokenMs, t]) and render the
Field/StatGrid conditionally based on perfItems.length > 0 as before.

Comment on lines +49 to +51
label: t('labels.locale'),
value: <Text>{customer.locale || 'en'}</Text>,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Don’t default missing customer locale to en in display.

Line 50 can misstate unknown data as English. Prefer showing notAvailable (or a true system default locale source) instead of a hardcoded fallback.

💡 Suggested patch
-      value: <Text>{customer.locale || 'en'}</Text>,
+      value: <Text>{customer.locale || t('labels.notAvailable')}</Text>,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
label: t('labels.locale'),
value: <Text>{customer.locale || 'en'}</Text>,
},
label: t('labels.locale'),
value: <Text>{customer.locale || t('labels.notAvailable')}</Text>,
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/customers/components/customer-information.tsx`
around lines 49 - 51, The UI currently hardcodes a fallback of 'en' when
customer.locale is missing in the customer-information component; update the
locale cell (the object with label: t('labels.locale') and value) to avoid
showing 'en' as a presumed locale and instead render a proper "not available"
indicator or the true system default: replace the hardcoded string usage of 'en'
with a translation placeholder (e.g., t('notAvailable')) or a conditional that
displays t('notAvailable') when customer.locale is falsy (or use the configured
system default source if available), updating the value expression where
customer.locale is referenced.

Comment on lines +348 to +357
...(integration.sqlConnectionConfig.readOnly != null
? [
{
label: t('integrations.upload.readOnly'),
value: integration.sqlConnectionConfig.readOnly
? 'Yes'
: 'No',
},
]
: []),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Internationalize "Yes"/"No" strings.

The readOnly value renders hardcoded "Yes"/"No" strings. These should use the i18n translation function for consistency with the rest of the UI.

🌐 Proposed fix for i18n
                   {
                     label: t('integrations.upload.readOnly'),
-                    value: integration.sqlConnectionConfig.readOnly
-                      ? 'Yes'
-                      : 'No',
+                    value: integration.sqlConnectionConfig.readOnly
+                      ? t('common.yes')
+                      : t('common.no'),
                   },

Note: This assumes t('common.yes') and t('common.no') exist in the common namespace. Verify the correct translation keys are available.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
...(integration.sqlConnectionConfig.readOnly != null
? [
{
label: t('integrations.upload.readOnly'),
value: integration.sqlConnectionConfig.readOnly
? 'Yes'
: 'No',
},
]
: []),
...(integration.sqlConnectionConfig.readOnly != null
? [
{
label: t('integrations.upload.readOnly'),
value: integration.sqlConnectionConfig.readOnly
? t('common.yes')
: t('common.no'),
},
]
: []),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/platform/app/features/settings/integrations/components/integration-details.tsx`
around lines 348 - 357, The displayed readOnly strings are hardcoded "Yes"/"No";
replace them with translated values by calling the i18n function (e.g., use
t('common.yes') and t('common.no')) where the value is set for
integration.sqlConnectionConfig.readOnly inside the integration-details.tsx
component so the label value becomes integration.sqlConnectionConfig.readOnly ?
t('common.yes') : t('common.no'); ensure you import/use the existing t function
already used in this file.

Comment on lines +88 to +120
label:
secretBindings.find((b) => SENSITIVE_KEYS.has(b)) ?? 'apiKey',
value: <Text variant="code">{'\u00d7'.repeat(8)}</Text>,
},
]
: []),
...(integration.authMethod === 'oauth2' && integration.oauth2Auth
? [
{
label: hasOAuth2Config
? t('integrations.manageDialog.connectedViaOAuth2')
: 'accessToken',
value: <Text variant="code">{'\u00d7'.repeat(8)}</Text>,
},
]
: []),
...(integration.connectionConfig?.domain
? [
{
label: 'domain',
value: (
<Text variant="code" truncate>
{maskValue(integration.connectionConfig.domain)}
</Text>
),
},
]
: []),
...(integration.connectionConfig?.apiEndpoint
? [
{
label: 'apiEndpoint',
value: (
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid raw/internal auth labels in UI.

Several labels are hardcoded/internal ('apiKey', 'accessToken', 'domain', 'apiEndpoint'). These should be translated/user-facing for consistent localized settings UI.

💡 Suggested direction
-              secretBindings.find((b) => SENSITIVE_KEYS.has(b)) ?? 'apiKey',
+              secretBindings.find((b) => SENSITIVE_KEYS.has(b)) ??
+                t('integrations.manageDialog.apiKey'),
@@
-              : 'accessToken',
+              : t('integrations.manageDialog.accessToken'),
@@
-            label: 'domain',
+            label: t('integrations.manageDialog.domain'),
@@
-            label: 'apiEndpoint',
+            label: t('integrations.manageDialog.apiEndpoint'),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
label:
secretBindings.find((b) => SENSITIVE_KEYS.has(b)) ?? 'apiKey',
value: <Text variant="code">{'\u00d7'.repeat(8)}</Text>,
},
]
: []),
...(integration.authMethod === 'oauth2' && integration.oauth2Auth
? [
{
label: hasOAuth2Config
? t('integrations.manageDialog.connectedViaOAuth2')
: 'accessToken',
value: <Text variant="code">{'\u00d7'.repeat(8)}</Text>,
},
]
: []),
...(integration.connectionConfig?.domain
? [
{
label: 'domain',
value: (
<Text variant="code" truncate>
{maskValue(integration.connectionConfig.domain)}
</Text>
),
},
]
: []),
...(integration.connectionConfig?.apiEndpoint
? [
{
label: 'apiEndpoint',
value: (
label:
secretBindings.find((b) => SENSITIVE_KEYS.has(b)) ??
t('integrations.manageDialog.apiKey'),
value: <Text variant="code">{'\u00d7'.repeat(8)}</Text>,
},
]
: []),
...(integration.authMethod === 'oauth2' && integration.oauth2Auth
? [
{
label: hasOAuth2Config
? t('integrations.manageDialog.connectedViaOAuth2')
: t('integrations.manageDialog.accessToken'),
value: <Text variant="code">{'\u00d7'.repeat(8)}</Text>,
},
]
: []),
...(integration.connectionConfig?.domain
? [
{
label: t('integrations.manageDialog.domain'),
value: (
<Text variant="code" truncate>
{maskValue(integration.connectionConfig.domain)}
</Text>
),
},
]
: []),
...(integration.connectionConfig?.apiEndpoint
? [
{
label: t('integrations.manageDialog.apiEndpoint'),
value: (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/platform/app/features/settings/integrations/components/integration-manage/integration-active-view.tsx`
around lines 88 - 120, Replace the hardcoded/internal labels ('apiKey',
'accessToken', 'domain', 'apiEndpoint') used when building the displayed items
with user-facing, localized strings via the translation function (t). Update the
label entries in the arrays constructed in integration-active-view.tsx (the
objects created when secretBindings/SENSITIVE_KEYS, oauth2 auth branch using
hasOAuth2Config, and the integration.connectionConfig?.domain and ?.apiEndpoint
branches) to call t(...) with appropriate keys (e.g.
integrations.manageDialog.apiKey, integrations.manageDialog.accessToken,
integrations.manageDialog.domain, integrations.manageDialog.apiEndpoint) so the
UI shows translated labels consistently.

@yannickmonney yannickmonney merged commit 9b72a37 into main Feb 27, 2026
17 checks passed
@yannickmonney yannickmonney deleted the feat/ui-component-updates branch February 27, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant