Skip to content

feat(platform): UI polish and workflow validation fixes#458

Merged
Israeltheminer merged 1 commit into
mainfrom
feat/custom-agents-ux-polish
Feb 13, 2026
Merged

feat(platform): UI polish and workflow validation fixes#458
Israeltheminer merged 1 commit into
mainfrom
feat/custom-agents-ux-polish

Conversation

@Israeltheminer
Copy link
Copy Markdown
Collaborator

@Israeltheminer Israeltheminer commented Feb 13, 2026

Summary

  • Fix assistant thinking indicator to show during empty streaming responses, and extract TeamFilterMenu into its own component
  • Replace Form/Description wrappers with native HTML in import forms, fix vendors table cell spacing
  • Fix workflow step validation to only run when both stepType and config are present, preventing infinite retry loops on partial updates
  • Strip misplaced nextSteps from action config with a warning instead of hard failing
  • Improve AI assistant communication rules to be more concise and actionable
  • Add tests for action step validation, action parameter validation, and step config validation covering common AI agent mistake patterns

Test plan

  • Verify assistant thinking animation shows while waiting for AI response
  • Test team filter menu in user dropdown works correctly
  • Verify customer/product/vendor import forms render and submit correctly
  • Test workflow step updates with partial payloads (config-only, no stepType)
  • Verify action steps with misplaced nextSteps emit warning but don't fail
  • Run new validation tests: npm run test --workspace=@tale/platform

Summary by CodeRabbit

  • Bug Fixes

    • Improved AI assistant to display thinking animation while processing requests
    • Refined workflow step validation logic for partial updates
    • Added warning for incorrectly placed configuration fields
  • Tests

    • Added comprehensive test coverage for action step validation
    • Added tests for workflow parameter validation
    • Added tests for step configuration validation
  • Refactor

    • Simplified internal component structure
    • Streamlined markup in import forms
  • Style

    • Adjusted table cell spacing for better visual alignment
  • Documentation

    • Enhanced AI assistant communication guidelines with clearer directives

Fix assistant thinking indicator to show during empty streaming responses.
Extract TeamFilterMenu into its own component. Replace Form/Description
wrappers with native HTML in import forms. Fix vendors table cell spacing.

Fix workflow step validation to only run when both stepType and config are
present, preventing infinite retry loops on partial updates. Strip misplaced
nextSteps from action config with a warning instead of failing. Improve
AI assistant communication rules to be more concise and actionable.

Add tests for action step validation, action parameter validation, and
step config validation covering common AI agent mistake patterns.
@Israeltheminer Israeltheminer force-pushed the feat/custom-agents-ux-polish branch from bb51563 to aecf3ba Compare February 13, 2026 17:43
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

This PR encompasses multiple distinct changes across the platform services: refactoring form components to use plain HTML instead of semantic UI components (Form, Description), extracting a new TeamFilterMenu component for better modularity, adding thinking animation detection in the automation assistant based on response waiting state, adjusting workflow step validation logic to require both stepType and config parameters before validation, and adding comprehensive test suites for workflow validation functions with specific focus on nextSteps field handling and parameter extraction. Additionally, the AI communication instructions are expanded with more explicit guidance on avoiding restated workflow steps and providing actionable feedback.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: UI polish (component extraction, HTML replacement, spacing fixes) and workflow validation fixes (partial update handling, nextSteps warning, validation improvements).
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/custom-agents-ux-polish

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: 5

🤖 Fix all issues with AI agents
In
`@services/platform/app/features/customers/components/customer-import-form.tsx`:
- Around line 136-139: The two unordered lists in the CustomerImportForm
component need an explicit role attribute for VoiceOver accessibility: update
both <ul> elements inside customer-import-form.tsx (the one rendering the
localeHint/churnedNote list and the other list around lines ~167-170) to include
role="list" so Safari/VoiceOver will announce list semantics when Tailwind v4
Preflight resets list-style; locate the <ul className="list-outside list-disc
..."> instances and add role="list" to each.

In `@services/platform/app/features/products/components/product-import-form.tsx`:
- Around line 77-80: The UL that renders expected columns in the
ProductImportForm component should include an explicit role for VoiceOver
accessibility; update the <ul className="list-outside list-disc space-y-2 pl-4">
element in product-import-form.tsx to add role="list" so Safari/VoiceOver will
announce the list semantics (keep the existing Tailwind classes and list items
unchanged).

In `@services/platform/app/features/vendors/components/vendor-import-form.tsx`:
- Around line 100-102: The two unordered lists in the VendorImportForm component
need explicit list semantics for VoiceOver: add role="list" to both <ul>
elements in the vendor-import-form.tsx JSX (the <ul className="list-outside
list-disc ..."> instances) so Safari/VoiceOver correctly announces them even
when Tailwind v4 Preflight removes list-style; update both occurrences (the one
showing t('importForm.localeHint') and the other list around line ~130) to
include role="list".

In
`@services/platform/convex/workflow_engine/helpers/validation/validate_action_parameters.test.ts`:
- Around line 156-170: The test suite contains a duplicate case checking
nextSteps contamination: the test "should reject nextSteps as unknown field in
raw parameters" duplicates the earlier "should fail with unknown fields
alongside variables"; remove the redundant test or alter it to cover a different
scenario. Locate the tests referencing validateActionParameters and the two
descriptions ("should reject nextSteps as unknown field in raw parameters" and
"should fail with unknown fields alongside variables") and either delete the
former duplicate or change its input/expectation to exercise a distinct
validation path (e.g., different action name, nested unknown field, or different
malformed parameter) so each test covers unique behavior.

In
`@services/platform/convex/workflow_engine/helpers/validation/validate_step_config.test.ts`:
- Around line 153-177: Update the test comment in validate_step_config.test.ts
to clearly state that this test documents the current validator behavior
(validateStepConfig) which requires stepType even on partial updates, and that
the actual fix is implemented upstream in update_workflow_step_tool.ts where
validation is gated to run only when both stepType and config are present;
explicitly note that the expectation (failure with "Step type is required") is
intentional and should not be changed until the upstream gating is applied so
future readers don't mistakenly flip the test.

Comment on lines +136 to +139
<ul className="list-outside list-disc space-y-2 pl-4">
<li>{t('importForm.localeHint')}</li>
<li className="text-yellow-600">{t('importForm.churnedNote')}</li>
</Stack>
</Description>
</ul>
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

Add role="list" on both <ul> elements for VoiceOver accessibility.

Both list elements (Lines 136 and 167) need role="list" for Safari/VoiceOver to properly announce list semantics when Tailwind CSS v4 Preflight resets list-style.

Proposed fix
@@ -136,7 +136,7 @@
-            <ul className="list-outside list-disc space-y-2 pl-4">
+            <ul role="list" className="list-outside list-disc space-y-2 pl-4">
@@ -167,7 +167,7 @@
-            <ul className="list-outside list-disc space-y-2 pl-4">
+            <ul role="list" className="list-outside list-disc space-y-2 pl-4">

Based on learnings: "Tailwind CSS v4 with Preflight resets list-style to none, and Safari/VoiceOver requires an explicit role='list' for proper semantics."

Also applies to: 167-170

🤖 Prompt for AI Agents
In `@services/platform/app/features/customers/components/customer-import-form.tsx`
around lines 136 - 139, The two unordered lists in the CustomerImportForm
component need an explicit role attribute for VoiceOver accessibility: update
both <ul> elements inside customer-import-form.tsx (the one rendering the
localeHint/churnedNote list and the other list around lines ~167-170) to include
role="list" so Safari/VoiceOver will announce list semantics when Tailwind v4
Preflight resets list-style; locate the <ul className="list-outside list-disc
..."> instances and add role="list" to each.

Comment on lines 77 to 80
<ul className="list-outside list-disc space-y-2 pl-4">
<li>{t('import.expectedColumns')}</li>
<li className="text-blue-600">{t('import.draftStatusNote')}</li>
</ul>
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

Add role="list" for VoiceOver accessibility.

Tailwind CSS v4 with Preflight resets list-style to none, which causes Safari/VoiceOver to not announce the list semantics. Add role="list" to maintain accessibility.

Proposed fix
-            <ul className="list-outside list-disc space-y-2 pl-4">
+            <ul role="list" className="list-outside list-disc space-y-2 pl-4">

Based on learnings: "In the tale-project/tale repository, when reviewing React components written in TypeScript (.tsx files), do not remove the role='list' attribute from ul elements. Tailwind CSS v4 with Preflight resets list-style to none, and Safari/VoiceOver requires an explicit role='list' for proper semantics."

📝 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
<ul className="list-outside list-disc space-y-2 pl-4">
<li>{t('import.expectedColumns')}</li>
<li className="text-blue-600">{t('import.draftStatusNote')}</li>
</ul>
<ul role="list" className="list-outside list-disc space-y-2 pl-4">
<li>{t('import.expectedColumns')}</li>
<li className="text-blue-600">{t('import.draftStatusNote')}</li>
</ul>
🤖 Prompt for AI Agents
In `@services/platform/app/features/products/components/product-import-form.tsx`
around lines 77 - 80, The UL that renders expected columns in the
ProductImportForm component should include an explicit role for VoiceOver
accessibility; update the <ul className="list-outside list-disc space-y-2 pl-4">
element in product-import-form.tsx to add role="list" so Safari/VoiceOver will
announce the list semantics (keep the existing Tailwind classes and list items
unchanged).

Comment on lines 100 to 102
<ul className="list-outside list-disc space-y-2 pl-4">
<li>{t('importForm.localeHint')}</li>
</ul>
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

Add role="list" on both <ul> elements for VoiceOver accessibility.

Both list elements (Lines 100 and 130) need role="list" for Safari/VoiceOver to properly announce list semantics when Tailwind CSS v4 Preflight resets list-style.

Proposed fix
@@ -100,7 +100,7 @@
-            <ul className="list-outside list-disc space-y-2 pl-4">
+            <ul role="list" className="list-outside list-disc space-y-2 pl-4">
@@ -130,7 +130,7 @@
-            <ul className="list-outside list-disc space-y-2 pl-4">
+            <ul role="list" className="list-outside list-disc space-y-2 pl-4">

Based on learnings: "Tailwind CSS v4 with Preflight resets list-style to none, and Safari/VoiceOver requires an explicit role='list' for proper semantics."

Also applies to: 130-132

🤖 Prompt for AI Agents
In `@services/platform/app/features/vendors/components/vendor-import-form.tsx`
around lines 100 - 102, The two unordered lists in the VendorImportForm
component need explicit list semantics for VoiceOver: add role="list" to both
<ul> elements in the vendor-import-form.tsx JSX (the <ul className="list-outside
list-disc ..."> instances) so Safari/VoiceOver correctly announces them even
when Tailwind v4 Preflight removes list-style; update both occurrences (the one
showing t('importForm.localeHint') and the other list around line ~130) to
include role="list".

Comment on lines +156 to +170
describe('nextSteps contamination at parameter level', () => {
it('should reject nextSteps as unknown field in raw parameters', () => {
// validateActionParameters correctly rejects unknown fields
const result = validateActionParameters('set_variables', {
variables: [{ name: 'counter', value: 0 }],
nextSteps: { success: 'next_step' },
});

expect(result.valid).toBe(false);
expect(
result.errors.some(
(e) => e.includes('Unknown field') && e.includes('nextSteps'),
),
).toBe(true);
});
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

Minor: Duplicate test case for nextSteps contamination.

This test (lines 157-170) tests the exact same scenario as the test at lines 40-53 ("should fail with unknown fields alongside variables"). Both validate that nextSteps alongside valid variables produces an "Unknown field" error.

Consider removing one to reduce redundancy, or differentiate them if there's a subtle distinction intended.

🤖 Prompt for AI Agents
In
`@services/platform/convex/workflow_engine/helpers/validation/validate_action_parameters.test.ts`
around lines 156 - 170, The test suite contains a duplicate case checking
nextSteps contamination: the test "should reject nextSteps as unknown field in
raw parameters" duplicates the earlier "should fail with unknown fields
alongside variables"; remove the redundant test or alter it to cover a different
scenario. Locate the tests referencing validateActionParameters and the two
descriptions ("should reject nextSteps as unknown field in raw parameters" and
"should fail with unknown fields alongside variables") and either delete the
former duplicate or change its input/expectation to exercise a distinct
validation path (e.g., different action name, nested unknown field, or different
malformed parameter) so each test covers unique behavior.

Comment on lines +153 to +177
describe('partial updates (update_workflow_step scenarios)', () => {
it('should fail when stepType is undefined but config is provided', () => {
// This is the critical bug: update_workflow_step passes stepType: undefined
// when only config is being updated, causing "Step type is required" error.
// The AI agent then retries 30 times with the same payload.
const result = validateStepConfig({
stepSlug: 'update',
name: 'Step',
stepType: undefined,
config: {
type: 'set_variables',
parameters: {
variables: [{ name: 'foo', value: 'bar' }],
},
},
});

// Current behavior: fails with "Step type is required"
// This documents the bug - a partial update with valid config shouldn't fail
// just because stepType wasn't re-sent in the update payload
expect(result.valid).toBe(false);
expect(
result.errors.some((e) => e.includes('Step type is required')),
).toBe(true);
});
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

Clarify test intent: This documents current behavior, not desired behavior.

The comment says "This documents the bug" and expects failure. Per the PR description, the fix for this is in update_workflow_step_tool.ts which gates validation to run only when both stepType and config are present.

Consider adding a note that this test documents the validator's current behavior (requiring stepType), and the actual fix is upstream gating. This prevents future confusion about whether the test expectation should change.

📝 Suggested comment enhancement
   describe('partial updates (update_workflow_step scenarios)', () => {
     it('should fail when stepType is undefined but config is provided', () => {
       // This is the critical bug: update_workflow_step passes stepType: undefined
       // when only config is being updated, causing "Step type is required" error.
       // The AI agent then retries 30 times with the same payload.
+      //
+      // NOTE: This test documents the validator's behavior. The fix is in
+      // update_workflow_step_tool.ts which gates validation to only run when
+      // both stepType AND config are provided.
       const result = validateStepConfig({
📝 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
describe('partial updates (update_workflow_step scenarios)', () => {
it('should fail when stepType is undefined but config is provided', () => {
// This is the critical bug: update_workflow_step passes stepType: undefined
// when only config is being updated, causing "Step type is required" error.
// The AI agent then retries 30 times with the same payload.
const result = validateStepConfig({
stepSlug: 'update',
name: 'Step',
stepType: undefined,
config: {
type: 'set_variables',
parameters: {
variables: [{ name: 'foo', value: 'bar' }],
},
},
});
// Current behavior: fails with "Step type is required"
// This documents the bug - a partial update with valid config shouldn't fail
// just because stepType wasn't re-sent in the update payload
expect(result.valid).toBe(false);
expect(
result.errors.some((e) => e.includes('Step type is required')),
).toBe(true);
});
describe('partial updates (update_workflow_step scenarios)', () => {
it('should fail when stepType is undefined but config is provided', () => {
// This is the critical bug: update_workflow_step passes stepType: undefined
// when only config is being updated, causing "Step type is required" error.
// The AI agent then retries 30 times with the same payload.
//
// NOTE: This test documents the validator's behavior. The fix is in
// update_workflow_step_tool.ts which gates validation to only run when
// both stepType AND config are provided.
const result = validateStepConfig({
stepSlug: 'update',
name: 'Step',
stepType: undefined,
config: {
type: 'set_variables',
parameters: {
variables: [{ name: 'foo', value: 'bar' }],
},
},
});
// Current behavior: fails with "Step type is required"
// This documents the bug - a partial update with valid config shouldn't fail
// just because stepType wasn't re-sent in the update payload
expect(result.valid).toBe(false);
expect(
result.errors.some((e) => e.includes('Step type is required')),
).toBe(true);
});
🤖 Prompt for AI Agents
In
`@services/platform/convex/workflow_engine/helpers/validation/validate_step_config.test.ts`
around lines 153 - 177, Update the test comment in validate_step_config.test.ts
to clearly state that this test documents the current validator behavior
(validateStepConfig) which requires stepType even on partial updates, and that
the actual fix is implemented upstream in update_workflow_step_tool.ts where
validation is gated to run only when both stepType and config are present;
explicitly note that the expectation (failure with "Step type is required") is
intentional and should not be changed until the upstream gating is applied so
future readers don't mistakenly flip the test.

@Israeltheminer Israeltheminer merged commit aef9b5b into main Feb 13, 2026
15 checks passed
@Israeltheminer Israeltheminer deleted the feat/custom-agents-ux-polish branch February 13, 2026 17:50
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