Skip to content

feat: Airtable-style single-row toolbar for list views#447

Merged
hotlong merged 4 commits intomainfrom
copilot/add-toolbar-for-sorting-filtering-search
Feb 11, 2026
Merged

feat: Airtable-style single-row toolbar for list views#447
hotlong merged 4 commits intomainfrom
copilot/add-toolbar-for-sorting-filtering-search

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 11, 2026

Redesigns the ListView toolbar to match Airtable's compact single-row toolbar pattern and removes the duplicate ObjectView toolbar.

Changes

  • ListView toolbar: Single Airtable-style row with tool buttons (Hide fields | Filter | Group | Sort | Color | Row height) left-aligned, expandable Search right-aligned
  • ObjectView toolbar: Removed duplicate filter/sort/search/refresh controls (delegated to ListView). Now only renders named view tabs and create button when needed.
  • Compact h-7 ghost buttons with text-xs labels and 3.5x3.5 icons
  • Search collapses to a button by default; expands inline on click with auto-focus, collapses on blur when empty
  • Hide fields, Group, Color, Row height rendered as disabled placeholders for future implementation
  • Cleaned up unused imports (FilterUI, SortUI, Search, Input, RefreshCw) and unused searchQuery state from ObjectView
  • Updated tests to account for expandable search interaction flow and removed search controls from ObjectView

Affected packages

  • @object-ui/plugin-listListView.tsx
  • @object-ui/plugin-viewObjectView.tsx

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Feb 11, 2026 10:37am
objectui-console Ready Ready Preview, Comment Feb 11, 2026 10:37am
objectui-storybook Error Error Feb 11, 2026 10:37am

Request Review

Copilot AI and others added 2 commits February 11, 2026 10:01
…-row layout

Row 1: View tabs/switcher (optional)
Row 2: Tool buttons (Hide Fields, Filter, Group, Sort, Color, Row Height) + expandable Search

- Compact h-7 toolbar buttons with smaller icons (3.5x3.5)
- Expandable search (collapsed by default, click to expand)
- Placeholder buttons for future features (Hide Fields, Group, Color, Row Height)
- Updated tests to match new expandable search UX

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Add top toolbar for sorting and filtering in list view feat: Airtable-style two-row toolbar for list views Feb 11, 2026
Copilot AI requested a review from hotlong February 11, 2026 10:10
@hotlong
Copy link
Copy Markdown
Contributor

hotlong commented Feb 11, 2026

@copilot 你没搞懂,我需要的就是第二行好看的,第一行,丑的要死的直接把它删掉,哪有什么管理软件有两行工具栏的,你不会动脑筋思考吗?

…tyle ListView toolbar

- Removed filter/sort/search controls from ObjectView toolbar (delegated to ListView)
- Removed unused imports (FilterUI, SortUI, Search, Input, RefreshCw) and searchQuery state
- ObjectView toolbar now only renders named view tabs + create button when needed
- Single clean Airtable toolbar row: Hide fields | Filter | Group | Sort | Color | Row height | Search

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 11, 2026

@copilot 你没搞懂,我需要的就是第二行好看的,第一行,丑的要死的直接把它删掉,哪有什么管理软件有两行工具栏的,你不会动脑筋思考吗?

已修复,commit 50d0aed。删掉了 ObjectView 的工具栏(filter/sort/search/refresh 全部移除),现在只保留 ListView 的单行 Airtable 风格工具栏:Hide fields | Filter | Group | Sort | Color | Row height | Search。

Single toolbar

Copilot AI changed the title feat: Airtable-style two-row toolbar for list views feat: Airtable-style single-row toolbar for list views Feb 11, 2026
@hotlong hotlong marked this pull request as ready for review February 11, 2026 10:41
Copilot AI review requested due to automatic review settings February 11, 2026 10:41
@hotlong hotlong merged commit 9bb0e40 into main Feb 11, 2026
5 of 6 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Redesigns list/object view toolbars to follow a more compact Airtable-style pattern by consolidating ListView controls into a compact toolbar and stripping ObjectView’s duplicate toolbar controls.

Changes:

  • Reworked ListView toolbar UI: compact tool buttons on the left + expandable Search on the right (with optional view tabs row).
  • Simplified ObjectView toolbar to only show named view tabs / view switcher / create button, delegating filter/sort/search to ListView.
  • Updated unit tests to reflect the new Search interaction and the removal of ObjectView search.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
packages/plugin-list/src/ListView.tsx Implements new compact toolbar with tool buttons + expandable search UI.
packages/plugin-view/src/ObjectView.tsx Removes duplicate toolbar controls from ObjectView and trims imports/UI.
packages/plugin-list/src/tests/ListView.test.tsx Updates tests for “search button → expand → input” flow.
packages/plugin-view/src/tests/ObjectView.test.tsx Updates expectations to assert ObjectView no longer renders search.
Comments suppressed due to low confidence (1)

packages/plugin-view/src/tests/ObjectView.test.tsx:128

  • These tests assert that ObjectView never renders a search box (even when showSearch is provided). Since showSearch is still part of the ObjectViewSchema type, this effectively enshrines a breaking behavior change. Please either (1) keep search support in ObjectView when used standalone and add a test covering showSearch: true, or (2) remove/deprecate showSearch from the schema/types and update docs/tests accordingly.
    it('should not render search box (delegated to ListView toolbar)', () => {
      const schema: ObjectViewSchema = {
        type: 'object-view',
        objectName: 'contacts',
      };

      render(<ObjectView schema={schema} dataSource={mockDataSource} />);

      expect(screen.queryByPlaceholderText(/search/i)).toBeNull();
    });

    it('should not render search box when showSearch is false', () => {
      const schema: ObjectViewSchema = {
        type: 'object-view',
        objectName: 'contacts',
        showSearch: false,
      };

      render(<ObjectView schema={schema} dataSource={mockDataSource} />);

      expect(screen.queryByPlaceholderText(/search/i)).toBeNull();
    });

Comment on lines +545 to +555
<Button
variant="ghost"
size="sm"
className="absolute right-0.5 top-1/2 -translate-y-1/2 h-5 w-5 p-0 hover:bg-muted-foreground/20"
onClick={() => {
handleSearchChange('');
setSearchExpanded(false);
}}
>
<X className="h-3 w-3" />
</Button>
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The clear (X) button inside the expanded search input is icon-only and has no accessible name. Add an aria-label (e.g., "Clear search") or an sr-only text node so screen readers can identify the control.

Copilot uses AI. Check for mistakes.
Comment on lines +558 to +566
<Button
variant="ghost"
size="sm"
className="h-7 px-2 text-muted-foreground hover:text-primary text-xs"
onClick={() => setSearchExpanded(true)}
>
<Search className="h-3.5 w-3.5 mr-1.5" />
<span className="hidden sm:inline">Search</span>
</Button>
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The collapsed Search button hides its text label via hidden sm:inline, so on small screens it may end up with no accessible name (icon-only). Provide an aria-label/title or sr-only text so it remains discoverable and so tests can reliably query it by accessible name.

Copilot uses AI. Check for mistakes.
Comment on lines +851 to +860
// Render toolbar — only named view tabs; filter/sort/search is handled by ListView
const renderToolbar = () => {
const showSearchBox = schema.showSearch !== false;
const showCreateButton = schema.showCreate !== false && operations.create !== false;
const showRefreshButton = schema.showRefresh !== false;
const showViewSwitcherToggle = schema.showViewSwitcher === true; // Changed: default to false (hidden)

const namedViewTabs = renderNamedViewTabs();

// Hide toolbar entirely if there is nothing to show
if (!namedViewTabs && !showViewSwitcherToggle && !showCreateButton && !toolbarAddon) return null;

Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

After removing the toolbar controls (FilterUI/SortUI/Search/Refresh), there is still leftover filter/sort/search/refresh-related logic in this component (e.g., schema flags like showSearch/showFilters/showRefresh, and the Filter/Sort schema generation + refresh handler). That code path is now unused and is likely to trigger lint failures for unused variables, and it also makes the ObjectView API misleading. Either reintroduce controls when ObjectView is used standalone, or remove/deprecate the related schema flags and delete the unused logic to match the new toolbar responsibilities.

Copilot uses AI. Check for mistakes.
const searchInput = screen.getByPlaceholderText(/find/i);
expect(searchInput).toBeInTheDocument();
const searchButton = screen.getByRole('button', { name: /search/i });
expect(searchButton).toBeInTheDocument();
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

This test queries the Search control by accessible name, but the implementation currently derives that name from text that is visually hidden via Tailwind's hidden class (CSS not applied in jsdom). Once the button becomes icon-only on small screens, the accessible name may be empty unless an aria-label/sr-only label is added. Consider asserting against an explicit aria-label (and add it in the component) so the test reflects real accessibility behavior.

Suggested change
expect(searchButton).toBeInTheDocument();
expect(searchButton).toBeInTheDocument();
// Ensure the search control exposes a stable accessible name via aria-label
expect(searchButton).toHaveAttribute('aria-label', expect.stringMatching(/search/i));

Copilot uses AI. Check for mistakes.
Comment on lines +412 to +420
<Button
variant="ghost"
size="sm"
className="h-7 px-2 text-muted-foreground hover:text-primary text-xs"
disabled
>
<EyeOff className="h-3.5 w-3.5 mr-1.5" />
<span className="hidden sm:inline">Hide fields</span>
</Button>
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Several toolbar buttons rely on a label wrapped in hidden sm:inline, which is display:none on small screens. That removes the accessible name, leaving icon-only buttons without an aria label (e.g., Hide fields / Filter / Group / Sort / Color / Row height). Add an aria-label (and optionally title) or use an sr-only label so the buttons remain accessible when the visible text is hidden.

Copilot uses AI. Check for mistakes.
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.

3 participants