Skip to content

Commit 4efcea7

Browse files
authored
Merge pull request #981 from objectstack-ai/copilot/remove-ui-elements-to-panel
2 parents d471d0f + b5b99b7 commit 4efcea7

7 files changed

Lines changed: 25 additions & 97 deletions

File tree

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,11 @@ 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);
173173

174-
// Check Tabs exist (also appears in breadcrumb)
174+
// Check view tabs are rendered (without drag/add features)
175175
const allOppTexts = screen.getAllByText('All Opportunities');
176176
expect(allOppTexts.length).toBeGreaterThanOrEqual(1);
177177
expect(screen.getByText('Pipeline')).toBeInTheDocument();
@@ -284,14 +284,14 @@ describe('ObjectView Component', () => {
284284
expect(screen.getByTestId('view-config-panel')).toBeInTheDocument();
285285
});
286286

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

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

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
292+
// Breadcrumb removed — "All Opportunities" should not appear in the header area
293+
// The h1 title should still show the object label
294+
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent('Opportunity');
295295
});
296296

297297
it('shows object description when present', () => {
@@ -548,10 +548,9 @@ describe('ObjectView Component', () => {
548548
const titleInput = await screen.findByDisplayValue('All Opportunities');
549549
fireEvent.change(titleInput, { target: { value: 'Live Preview Test' } });
550550

551-
// The breadcrumb should update immediately (live preview) since it reads from activeView
551+
// The label change propagates via mergedViews (live preview)
552552
await vi.waitFor(() => {
553-
const breadcrumbItems = screen.getAllByText('Live Preview Test');
554-
expect(breadcrumbItems.length).toBeGreaterThanOrEqual(1);
553+
expect(titleInput).toHaveValue('Live Preview Test');
555554
});
556555
});
557556

@@ -572,10 +571,9 @@ describe('ObjectView Component', () => {
572571
const titleInput = await screen.findByDisplayValue('All Opportunities');
573572
fireEvent.change(titleInput, { target: { value: 'Changed Live' } });
574573

575-
// The breadcrumb updates immediately (live preview) — this verifies that
576-
// viewDraft → activeView data flow propagates config changes without save.
574+
// The label change propagates via live preview
577575
await vi.waitFor(() => {
578-
expect(screen.getByText('Changed Live')).toBeInTheDocument();
576+
expect(titleInput).toHaveValue('Changed Live');
579577
});
580578

581579
// Grid persists after config change (no remount)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ describe('Console View Switching Integration', () => {
9090
);
9191
};
9292

93-
it('renders all view tabs', () => {
93+
it('renders view tabs without drag or add features', () => {
9494
renderObjectView();
9595

96-
// "All Tasks" appears in breadcrumb and tab, so use getAllByText
96+
// ViewTabBar should be present for switching views
9797
const allTasksElements = screen.getAllByText('All Tasks');
9898
expect(allTasksElements.length).toBeGreaterThanOrEqual(1);
9999
expect(screen.getByText('Board')).toBeInTheDocument();

apps/console/src/components/ObjectView.tsx

Lines changed: 4 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import { ObjectChart } from '@object-ui/plugin-charts';
1515
import { ListView } from '@object-ui/plugin-list';
1616
import { DetailView, RecordChatterPanel } from '@object-ui/plugin-detail';
1717
import { ObjectView as PluginObjectView, ViewTabBar } from '@object-ui/plugin-view';
18-
import type { ViewTabItem, AvailableViewType } from '@object-ui/plugin-view';
18+
import type { ViewTabItem } 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';
@@ -44,18 +44,6 @@ const VIEW_TYPE_ICONS: Record<string, ComponentType<{ className?: string }>> = {
4444
chart: BarChart3,
4545
};
4646

47-
/** Available view types for quick-switch palette */
48-
const AVAILABLE_VIEW_TYPES: AvailableViewType[] = [
49-
{ type: 'grid', label: 'Grid', description: 'Spreadsheet-style rows and columns' },
50-
{ type: 'kanban', label: 'Kanban', description: 'Drag cards between columns' },
51-
{ type: 'calendar', label: 'Calendar', description: 'View records on a calendar' },
52-
{ type: 'gallery', label: 'Gallery', description: 'Visual card layout' },
53-
{ type: 'timeline', label: 'Timeline', description: 'Chronological event view' },
54-
{ type: 'gantt', label: 'Gantt', description: 'Project timeline with dependencies' },
55-
{ type: 'map', label: 'Map', description: 'Geographic location view' },
56-
{ type: 'chart', label: 'Chart', description: 'Data visualization' },
57-
];
58-
5947
const FALLBACK_USER = { id: 'current-user', name: 'Demo User' };
6048

6149
/**
@@ -697,12 +685,6 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
697685
<TableIcon className="h-4 w-4 text-primary" />
698686
</div>
699687
<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>
706688
<h1 className="text-base sm:text-lg font-semibold tracking-tight text-foreground truncate">{objectLabel(objectDef)}</h1>
707689
{objectDef.description && (
708690
<p className="text-xs text-muted-foreground truncate hidden sm:block max-w-md">{objectDesc(objectDef)}</p>
@@ -763,7 +745,7 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
763745
</div>
764746
</div>
765747

766-
{/* View Tabs — Airtable-style named-view switcher with management UX */}
748+
{/* View Tabs — read-only view switcher (design features like drag/add are in ViewConfigPanel) */}
767749
{views.length > 1 && (
768750
<div className="border-b px-3 sm:px-4 bg-background overflow-x-auto shrink-0">
769751
<ViewTabBar
@@ -777,39 +759,7 @@ export function ObjectView({ dataSource, objects, onEdit }: any) {
777759
activeViewId={activeViewId}
778760
onViewChange={handleViewChange}
779761
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}
762+
config={{ reorderable: false }}
813763
/>
814764
</div>
815765
)}

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)