diff --git a/apps/console/src/__tests__/ObjectView.test.tsx b/apps/console/src/__tests__/ObjectView.test.tsx index f74cb3664..25f178bbb 100644 --- a/apps/console/src/__tests__/ObjectView.test.tsx +++ b/apps/console/src/__tests__/ObjectView.test.tsx @@ -167,11 +167,11 @@ describe('ObjectView Component', () => { render(); - // Check Header (appears in breadcrumb and h1) + // Check Header (h1 only, breadcrumb removed) const headers = screen.getAllByText('Opportunity'); expect(headers.length).toBeGreaterThanOrEqual(1); - // Check Tabs exist (also appears in breadcrumb) + // Check view tabs are rendered (without drag/add features) const allOppTexts = screen.getAllByText('All Opportunities'); expect(allOppTexts.length).toBeGreaterThanOrEqual(1); expect(screen.getByText('Pipeline')).toBeInTheDocument(); @@ -284,14 +284,14 @@ describe('ObjectView Component', () => { expect(screen.getByTestId('view-config-panel')).toBeInTheDocument(); }); - it('shows breadcrumb with object and view name', () => { + it('does not show breadcrumb in ObjectView (removed to avoid duplication with AppHeader)', () => { mockUseParams.mockReturnValue({ objectName: 'opportunity' }); render(); - // Breadcrumb should show object label and active view label (may appear in tabs too) - const allOppTexts = screen.getAllByText('All Opportunities'); - expect(allOppTexts.length).toBeGreaterThanOrEqual(2); // breadcrumb + tab + // Breadcrumb removed — "All Opportunities" should not appear in the header area + // The h1 title should still show the object label + expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('Opportunity'); }); it('shows object description when present', () => { @@ -548,10 +548,9 @@ describe('ObjectView Component', () => { const titleInput = await screen.findByDisplayValue('All Opportunities'); fireEvent.change(titleInput, { target: { value: 'Live Preview Test' } }); - // The breadcrumb should update immediately (live preview) since it reads from activeView + // The label change propagates via mergedViews (live preview) await vi.waitFor(() => { - const breadcrumbItems = screen.getAllByText('Live Preview Test'); - expect(breadcrumbItems.length).toBeGreaterThanOrEqual(1); + expect(titleInput).toHaveValue('Live Preview Test'); }); }); @@ -572,10 +571,9 @@ describe('ObjectView Component', () => { const titleInput = await screen.findByDisplayValue('All Opportunities'); fireEvent.change(titleInput, { target: { value: 'Changed Live' } }); - // The breadcrumb updates immediately (live preview) — this verifies that - // viewDraft → activeView data flow propagates config changes without save. + // The label change propagates via live preview await vi.waitFor(() => { - expect(screen.getByText('Changed Live')).toBeInTheDocument(); + expect(titleInput).toHaveValue('Changed Live'); }); // Grid persists after config change (no remount) diff --git a/apps/console/src/__tests__/ViewSwitching.test.tsx b/apps/console/src/__tests__/ViewSwitching.test.tsx index f38e7aef1..e9d61d6c9 100644 --- a/apps/console/src/__tests__/ViewSwitching.test.tsx +++ b/apps/console/src/__tests__/ViewSwitching.test.tsx @@ -90,10 +90,10 @@ describe('Console View Switching Integration', () => { ); }; - it('renders all view tabs', () => { + it('renders view tabs without drag or add features', () => { renderObjectView(); - // "All Tasks" appears in breadcrumb and tab, so use getAllByText + // ViewTabBar should be present for switching views const allTasksElements = screen.getAllByText('All Tasks'); expect(allTasksElements.length).toBeGreaterThanOrEqual(1); expect(screen.getByText('Board')).toBeInTheDocument(); diff --git a/apps/console/src/components/ObjectView.tsx b/apps/console/src/components/ObjectView.tsx index 79696500c..8296e69b5 100644 --- a/apps/console/src/components/ObjectView.tsx +++ b/apps/console/src/components/ObjectView.tsx @@ -15,13 +15,13 @@ import { ObjectChart } from '@object-ui/plugin-charts'; import { ListView } from '@object-ui/plugin-list'; import { DetailView, RecordChatterPanel } from '@object-ui/plugin-detail'; import { ObjectView as PluginObjectView, ViewTabBar } from '@object-ui/plugin-view'; -import type { ViewTabItem, AvailableViewType } from '@object-ui/plugin-view'; +import type { ViewTabItem } from '@object-ui/plugin-view'; // Import plugins for side-effects (registration) import '@object-ui/plugin-grid'; import '@object-ui/plugin-kanban'; import '@object-ui/plugin-calendar'; import { Button, Empty, EmptyTitle, EmptyDescription, NavigationOverlay, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from '@object-ui/components'; -import { Plus, Table as TableIcon, Settings2, Wrench, KanbanSquare, Calendar, LayoutGrid, Activity, GanttChart, MapPin, BarChart3, ChevronRight } from 'lucide-react'; +import { Plus, Table as TableIcon, Settings2, Wrench, KanbanSquare, Calendar, LayoutGrid, Activity, GanttChart, MapPin, BarChart3 } from 'lucide-react'; import type { ListViewSchema, ViewNavigationConfig, FeedItem } from '@object-ui/types'; import { MetadataToggle, MetadataPanel, useMetadataInspector } from './MetadataInspector'; import { ViewConfigPanel } from './ViewConfigPanel'; @@ -44,18 +44,6 @@ const VIEW_TYPE_ICONS: Record> = { chart: BarChart3, }; -/** Available view types for quick-switch palette */ -const AVAILABLE_VIEW_TYPES: AvailableViewType[] = [ - { type: 'grid', label: 'Grid', description: 'Spreadsheet-style rows and columns' }, - { type: 'kanban', label: 'Kanban', description: 'Drag cards between columns' }, - { type: 'calendar', label: 'Calendar', description: 'View records on a calendar' }, - { type: 'gallery', label: 'Gallery', description: 'Visual card layout' }, - { type: 'timeline', label: 'Timeline', description: 'Chronological event view' }, - { type: 'gantt', label: 'Gantt', description: 'Project timeline with dependencies' }, - { type: 'map', label: 'Map', description: 'Geographic location view' }, - { type: 'chart', label: 'Chart', description: 'Data visualization' }, -]; - const FALLBACK_USER = { id: 'current-user', name: 'Demo User' }; /** @@ -697,12 +685,6 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
- {/* Breadcrumb: Object > View */} -
- {objectLabel(objectDef)} - - {activeView?.label || t('console.objectView.allRecords')} -

{objectLabel(objectDef)}

{objectDef.description && (

{objectDesc(objectDef)}

@@ -763,7 +745,7 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
- {/* View Tabs — Airtable-style named-view switcher with management UX */} + {/* View Tabs — read-only view switcher (design features like drag/add are in ViewConfigPanel) */} {views.length > 1 && (
{ setViewConfigPanelMode('create'); setShowViewConfigPanel(true); } : undefined} - onRenameView={(id: any, newName: any) => { - // Rename is wired for future backend integration - console.info('[ViewTabBar] Rename view:', id, newName); - }} - onDuplicateView={(id: any) => { - console.info('[ViewTabBar] Duplicate view:', id); - }} - onDeleteView={(id: any) => { - console.info('[ViewTabBar] Delete view:', id); - }} - onSetDefaultView={(id: any) => { - console.info('[ViewTabBar] Set default view:', id); - }} - onShareView={(id: any) => { - console.info('[ViewTabBar] Share view:', id); - }} - onPinView={(id: any, pinned: any) => { - console.info('[ViewTabBar] Pin view:', id, pinned); - }} - onReorderViews={(viewIds: any) => { - console.info('[ViewTabBar] Reorder views:', viewIds); - }} - onChangeViewType={(id: any, newType: any) => { - console.info('[ViewTabBar] Change view type:', id, newType); - }} - onConfigView={isAdmin ? (id: any) => { - handleViewChange(id); - setViewConfigPanelMode('edit'); - setShowViewConfigPanel(true); - } : undefined} - availableViewTypes={AVAILABLE_VIEW_TYPES} + config={{ reorderable: false }} />
)} diff --git a/packages/plugin-list/src/ListView.tsx b/packages/plugin-list/src/ListView.tsx index 9e866d15d..9ab9231fd 100644 --- a/packages/plugin-list/src/ListView.tsx +++ b/packages/plugin-list/src/ListView.tsx @@ -1071,12 +1071,11 @@ export const ListView: React.FC = ({ )} - {/* Airtable-style Toolbar — Merged: UserFilter badges (left) + Tool buttons (right) */} + {/* Airtable-style Toolbar — UserFilter badges (left) + Tool buttons (right) */}
-
+
{/* User Filters — inline in toolbar (Airtable Interfaces-style) */} {resolvedUserFilters && ( - <>
= ({ maxVisible={3} />
-
- )} +
+
{/* Hide Fields */} {toolbarFlags.showHideFields && ( @@ -1480,10 +1479,7 @@ export const ListView: React.FC = ({ )} -
- {/* Right: Add Record */} -
{/* Add Record (top position) */} {toolbarFlags.showAddRecord && toolbarFlags.addRecordPosition === 'top' && (
); } diff --git a/packages/plugin-list/src/__tests__/ListView.test.tsx b/packages/plugin-list/src/__tests__/ListView.test.tsx index f2c6afa1c..3a7e92c30 100644 --- a/packages/plugin-list/src/__tests__/ListView.test.tsx +++ b/packages/plugin-list/src/__tests__/ListView.test.tsx @@ -540,7 +540,7 @@ describe('ListView', () => { expect(screen.getByTestId('filter-badge-is_active')).toBeInTheDocument(); }); - it('should show Add filter button in userFilters', () => { + it('should not show Add filter button in userFilters (removed from UI)', () => { const schema: ListViewSchema = { type: 'list-view', objectName: 'contacts', @@ -555,7 +555,7 @@ describe('ListView', () => { }; renderWithProvider(); - expect(screen.getByTestId('user-filters-add')).toBeInTheDocument(); + expect(screen.queryByTestId('user-filters-add')).not.toBeInTheDocument(); }); it('should not render userFilters when objectDef has no filterable fields', async () => { diff --git a/packages/plugin-list/src/__tests__/UserFilters.test.tsx b/packages/plugin-list/src/__tests__/UserFilters.test.tsx index 5ee97536d..01436d0f8 100644 --- a/packages/plugin-list/src/__tests__/UserFilters.test.tsx +++ b/packages/plugin-list/src/__tests__/UserFilters.test.tsx @@ -369,10 +369,10 @@ describe('UserFilters', () => { }); // ============================================ - // Add Filter Entry Point + // Add Filter Entry Point (removed) // ============================================ describe('Add filter entry', () => { - it('renders "Add filter" button in dropdown mode', () => { + it('does not render "Add filter" button (removed from UI)', () => { const config = { element: 'dropdown' as const, fields: [ @@ -387,15 +387,7 @@ describe('UserFilters', () => { }; const onChange = vi.fn(); render(); - expect(screen.getByTestId('user-filters-add')).toBeInTheDocument(); - expect(screen.getByText('Add filter')).toBeInTheDocument(); - }); - - it('renders "Add filter" button even when no fields are provided', () => { - const config = { element: 'dropdown' as const }; - const onChange = vi.fn(); - render(); - expect(screen.getByTestId('user-filters-add')).toBeInTheDocument(); + expect(screen.queryByTestId('user-filters-add')).not.toBeInTheDocument(); }); });