Skip to content

Commit 881f3d4

Browse files
Copilothotlong
andcommitted
Remove breadcrumb, ViewTabBar, Add Filter button; restructure toolbar layout
- Remove ObjectView breadcrumb (Opportunity > All Opportunities) - Remove ViewTabBar from ObjectView (view switching via config panel) - Remove Add Filter button from UserFilters component - Restructure ListView toolbar: UserFilters left, tool buttons right - Update tests to match new UI Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent ae5d020 commit 881f3d4

6 files changed

Lines changed: 18 additions & 98 deletions

File tree

apps/console/src/__tests__/ObjectView.test.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,9 @@ describe('ObjectView Component', () => {
167167

168168
render(<ObjectView dataSource={mockDataSource} objects={mockObjects} onEdit={vi.fn()} />);
169169

170-
// Check Header (appears in breadcrumb and h1)
170+
// Check Header (h1 only, breadcrumb removed)
171171
const headers = screen.getAllByText('Opportunity');
172172
expect(headers.length).toBeGreaterThanOrEqual(1);
173-
174-
// Check Tabs exist (also appears in breadcrumb)
175-
const allOppTexts = screen.getAllByText('All Opportunities');
176-
expect(allOppTexts.length).toBeGreaterThanOrEqual(1);
177-
expect(screen.getByText('Pipeline')).toBeInTheDocument();
178173

179174
// Check Grid is rendered (default)
180175
expect(screen.getByTestId('object-grid')).toBeInTheDocument();
@@ -284,14 +279,14 @@ describe('ObjectView Component', () => {
284279
expect(screen.getByTestId('view-config-panel')).toBeInTheDocument();
285280
});
286281

287-
it('shows breadcrumb with object and view name', () => {
282+
it('does not show breadcrumb in ObjectView (removed to avoid duplication with AppHeader)', () => {
288283
mockUseParams.mockReturnValue({ objectName: 'opportunity' });
289284

290285
render(<ObjectView dataSource={mockDataSource} objects={mockObjects} onEdit={vi.fn()} />);
291286

292-
// Breadcrumb should show object label and active view label (may appear in tabs too)
293-
const allOppTexts = screen.getAllByText('All Opportunities');
294-
expect(allOppTexts.length).toBeGreaterThanOrEqual(2); // breadcrumb + tab
287+
// Breadcrumb removed — "All Opportunities" should not appear in the header area
288+
// The h1 title should still show the object label
289+
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('Opportunity');
295290
});
296291

297292
it('shows object description when present', () => {

apps/console/src/components/ObjectView.tsx

Lines changed: 4 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ import { useParams, useSearchParams, useNavigate } from 'react-router-dom';
1414
import { ObjectChart } from '@object-ui/plugin-charts';
1515
import { ListView } from '@object-ui/plugin-list';
1616
import { DetailView, RecordChatterPanel } from '@object-ui/plugin-detail';
17-
import { ObjectView as PluginObjectView, ViewTabBar } from '@object-ui/plugin-view';
18-
import type { ViewTabItem, AvailableViewType } from '@object-ui/plugin-view';
17+
import { ObjectView as PluginObjectView } from '@object-ui/plugin-view';
18+
import type { AvailableViewType } from '@object-ui/plugin-view';
1919
// Import plugins for side-effects (registration)
2020
import '@object-ui/plugin-grid';
2121
import '@object-ui/plugin-kanban';
2222
import '@object-ui/plugin-calendar';
2323
import { Button, Empty, EmptyTitle, EmptyDescription, NavigationOverlay, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from '@object-ui/components';
24-
import { Plus, Table as TableIcon, Settings2, Wrench, KanbanSquare, Calendar, LayoutGrid, Activity, GanttChart, MapPin, BarChart3, ChevronRight } from 'lucide-react';
24+
import { Plus, Table as TableIcon, Settings2, Wrench, KanbanSquare, Calendar, LayoutGrid, Activity, GanttChart, MapPin, BarChart3 } from 'lucide-react';
2525
import type { ListViewSchema, ViewNavigationConfig, FeedItem } from '@object-ui/types';
2626
import { MetadataToggle, MetadataPanel, useMetadataInspector } from './MetadataInspector';
2727
import { ViewConfigPanel } from './ViewConfigPanel';
@@ -697,12 +697,6 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
697697
<TableIcon className="h-4 w-4 text-primary" />
698698
</div>
699699
<div className="min-w-0">
700-
{/* Breadcrumb: Object > View */}
701-
<div className="flex items-center gap-1 text-xs text-muted-foreground mb-0.5">
702-
<span className="truncate">{objectLabel(objectDef)}</span>
703-
<ChevronRight className="h-3 w-3 shrink-0" />
704-
<span className="truncate font-medium text-foreground">{activeView?.label || t('console.objectView.allRecords')}</span>
705-
</div>
706700
<h1 className="text-base sm:text-lg font-semibold tracking-tight text-foreground truncate">{objectLabel(objectDef)}</h1>
707701
{objectDef.description && (
708702
<p className="text-xs text-muted-foreground truncate hidden sm:block max-w-md">{objectDesc(objectDef)}</p>
@@ -763,56 +757,7 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
763757
</div>
764758
</div>
765759

766-
{/* View Tabs — Airtable-style named-view switcher with management UX */}
767-
{views.length > 1 && (
768-
<div className="border-b px-3 sm:px-4 bg-background overflow-x-auto shrink-0">
769-
<ViewTabBar
770-
views={views.map((view: { id: string; label: string; type: string; filter?: any[]; sort?: any[] }) => ({
771-
id: view.id,
772-
label: view.label,
773-
type: view.type,
774-
hasActiveFilters: Array.isArray((view as any).filter) && (view as any).filter.length > 0,
775-
hasActiveSort: Array.isArray((view as any).sort) && (view as any).sort.length > 0,
776-
} as ViewTabItem))}
777-
activeViewId={activeViewId}
778-
onViewChange={handleViewChange}
779-
viewTypeIcons={VIEW_TYPE_ICONS}
780-
config={{ ...objectDef.viewTabBar, reorderable: isAdmin ? true : objectDef.viewTabBar?.reorderable }}
781-
onAddView={isAdmin ? () => { setViewConfigPanelMode('create'); setShowViewConfigPanel(true); } : undefined}
782-
onRenameView={(id: any, newName: any) => {
783-
// Rename is wired for future backend integration
784-
console.info('[ViewTabBar] Rename view:', id, newName);
785-
}}
786-
onDuplicateView={(id: any) => {
787-
console.info('[ViewTabBar] Duplicate view:', id);
788-
}}
789-
onDeleteView={(id: any) => {
790-
console.info('[ViewTabBar] Delete view:', id);
791-
}}
792-
onSetDefaultView={(id: any) => {
793-
console.info('[ViewTabBar] Set default view:', id);
794-
}}
795-
onShareView={(id: any) => {
796-
console.info('[ViewTabBar] Share view:', id);
797-
}}
798-
onPinView={(id: any, pinned: any) => {
799-
console.info('[ViewTabBar] Pin view:', id, pinned);
800-
}}
801-
onReorderViews={(viewIds: any) => {
802-
console.info('[ViewTabBar] Reorder views:', viewIds);
803-
}}
804-
onChangeViewType={(id: any, newType: any) => {
805-
console.info('[ViewTabBar] Change view type:', id, newType);
806-
}}
807-
onConfigView={isAdmin ? (id: any) => {
808-
handleViewChange(id);
809-
setViewConfigPanelMode('edit');
810-
setShowViewConfigPanel(true);
811-
} : undefined}
812-
availableViewTypes={AVAILABLE_VIEW_TYPES}
813-
/>
814-
</div>
815-
)}
760+
{/* View Tabs removed — view switching is handled via ViewConfigPanel (right sidebar) */}
816761

817762
{/* 2. Content — Plugin ObjectView with ViewSwitcher + Filter + Sort */}
818763
<div className="flex-1 overflow-hidden relative flex flex-row">

packages/plugin-list/src/ListView.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,12 +1071,11 @@ export const ListView: React.FC<ListViewProps> = ({
10711071
</div>
10721072
)}
10731073

1074-
{/* Airtable-style Toolbar — Merged: UserFilter badges (left) + Tool buttons (right) */}
1074+
{/* Airtable-style Toolbar — UserFilter badges (left) + Tool buttons (right) */}
10751075
<div className="border-b px-2 sm:px-4 py-1 flex items-center justify-between gap-1 sm:gap-2 bg-background">
1076-
<div className="flex items-center gap-0.5 overflow-x-auto flex-1 min-w-0">
1076+
<div className="flex items-center gap-0.5 overflow-x-auto min-w-0">
10771077
{/* User Filters — inline in toolbar (Airtable Interfaces-style) */}
10781078
{resolvedUserFilters && (
1079-
<>
10801079
<div className="shrink-0 min-w-0" data-testid="user-filters">
10811080
<UserFilters
10821081
config={resolvedUserFilters}
@@ -1086,10 +1085,10 @@ export const ListView: React.FC<ListViewProps> = ({
10861085
maxVisible={3}
10871086
/>
10881087
</div>
1089-
<div className="h-4 w-px bg-border/60 mx-0.5 shrink-0" />
1090-
</>
10911088
)}
1089+
</div>
10921090

1091+
<div className="flex items-center gap-0.5 shrink-0">
10931092
{/* Hide Fields */}
10941093
{toolbarFlags.showHideFields && (
10951094
<Popover open={showHideFields} onOpenChange={setShowHideFields}>
@@ -1480,10 +1479,7 @@ export const ListView: React.FC<ListViewProps> = ({
14801479
</PopoverContent>
14811480
</Popover>
14821481
)}
1483-
</div>
14841482

1485-
{/* Right: Add Record */}
1486-
<div className="flex items-center gap-1">
14871483
{/* Add Record (top position) */}
14881484
{toolbarFlags.showAddRecord && toolbarFlags.addRecordPosition === 'top' && (
14891485
<Button

packages/plugin-list/src/UserFilters.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,6 @@ function DropdownFilters({ fields, objectDef, data, onFilterChange, maxVisible,
303303
)}
304304
</>
305305
)}
306-
<button
307-
className="inline-flex items-center gap-1 h-7 px-2 text-xs text-muted-foreground hover:text-foreground hover:bg-muted rounded-md transition-colors shrink-0"
308-
data-testid="user-filters-add"
309-
title="Add filter"
310-
>
311-
<Plus className="h-3.5 w-3.5" />
312-
<span className="hidden sm:inline">Add filter</span>
313-
</button>
314306
</div>
315307
);
316308
}

packages/plugin-list/src/__tests__/ListView.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ describe('ListView', () => {
540540
expect(screen.getByTestId('filter-badge-is_active')).toBeInTheDocument();
541541
});
542542

543-
it('should show Add filter button in userFilters', () => {
543+
it('should not show Add filter button in userFilters (removed from UI)', () => {
544544
const schema: ListViewSchema = {
545545
type: 'list-view',
546546
objectName: 'contacts',
@@ -555,7 +555,7 @@ describe('ListView', () => {
555555
};
556556

557557
renderWithProvider(<ListView schema={schema} />);
558-
expect(screen.getByTestId('user-filters-add')).toBeInTheDocument();
558+
expect(screen.queryByTestId('user-filters-add')).not.toBeInTheDocument();
559559
});
560560

561561
it('should not render userFilters when objectDef has no filterable fields', async () => {

packages/plugin-list/src/__tests__/UserFilters.test.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,10 @@ describe('UserFilters', () => {
369369
});
370370

371371
// ============================================
372-
// Add Filter Entry Point
372+
// Add Filter Entry Point (removed)
373373
// ============================================
374374
describe('Add filter entry', () => {
375-
it('renders "Add filter" button in dropdown mode', () => {
375+
it('does not render "Add filter" button (removed from UI)', () => {
376376
const config = {
377377
element: 'dropdown' as const,
378378
fields: [
@@ -387,15 +387,7 @@ describe('UserFilters', () => {
387387
};
388388
const onChange = vi.fn();
389389
render(<UserFilters config={config} onFilterChange={onChange} />);
390-
expect(screen.getByTestId('user-filters-add')).toBeInTheDocument();
391-
expect(screen.getByText('Add filter')).toBeInTheDocument();
392-
});
393-
394-
it('renders "Add filter" button even when no fields are provided', () => {
395-
const config = { element: 'dropdown' as const };
396-
const onChange = vi.fn();
397-
render(<UserFilters config={config} onFilterChange={onChange} />);
398-
expect(screen.getByTestId('user-filters-add')).toBeInTheDocument();
390+
expect(screen.queryByTestId('user-filters-add')).not.toBeInTheDocument();
399391
});
400392
});
401393

0 commit comments

Comments
 (0)