参考 Airtable Interfaces 的 User Filters 设计,为 ListView 工具栏新增 userFilters 配置,支持三种 Element 呈现模式:
- Dropdown — 每个可过滤字段显示为独立的下拉选择器 badge(如
状态 ∨)
- Tabs — 预设过滤组合显示为选项卡(如
Tab | my customers | All records)
- Toggle — 过滤字段显示为开关切换按钮
Airtable 参考截图
Dropdown 模式 — 工具栏左侧显示字段级过滤 badge:

Tabs 模式 + 设置面板 — 右侧面板中 Elements 和 Tabs 配置:

当前状态
ListView.tsx 已有 Airtable 风格工具栏(Hide fields / Filter / Group / Sort / Color / Density / Search)
quickFilters 仅支持 toggle button 模式,无 dropdown 和 tabs 模式
- 工具栏左侧无字段级过滤 badge,右侧工具按钮无法自动收纳
涉及的包和文件
| 包 |
文件 |
变更类型 |
@object-ui/types |
packages/types/src/objectql.ts |
Schema 扩展 — 新增 userFilters 属性 |
@object-ui/types |
packages/types/src/zod/objectql.zod.ts |
Zod schema 验证 |
@object-ui/plugin-list |
packages/plugin-list/src/UserFilters.tsx |
新文件 — 三模式渲染组件 |
@object-ui/plugin-list |
packages/plugin-list/src/ListView.tsx |
工具栏集成 + 状态管理 |
@object-ui/plugin-list |
packages/plugin-list/src/__tests__/UserFilters.test.tsx |
新文件 — 单元测试 |
Schema 设计
// ListViewSchema extension
userFilters?: {
/** UI element type: 'dropdown' | 'tabs' | 'toggle' */
element: 'dropdown' | 'tabs' | 'toggle';
/** Field-level filters (for dropdown & toggle modes) */
fields?: Array<{
field: string;
label?: string;
type?: 'select' | 'multi-select' | 'boolean' | 'date-range' | 'text';
options?: Array<{ label: string; value: string | number | boolean; color?: string }>;
showCount?: boolean;
defaultValues?: (string | number | boolean)[];
}>;
/** Named filter presets (for tabs mode) */
tabs?: Array<{
id: string;
label: string;
filters: Array<any[] | string>;
icon?: string;
default?: boolean;
}>;
allowAddTab?: boolean;
showAllRecords?: boolean;
};
使用示例
Dropdown 模式:
{
"type": "list-view",
"objectName": "accounts",
"userFilters": {
"element": "dropdown",
"fields": [
{ "field": "status", "label": "状态", "type": "multi-select", "showCount": true },
{ "field": "priority_tag", "label": "重要性标签", "type": "multi-select",
"options": [
{ "label": "Enterprise", "value": "enterprise", "color": "#dc2626" },
{ "label": "SMB", "value": "smb", "color": "#2563eb" }
]
}
]
}
}
Tabs 模式:
{
"type": "list-view",
"objectName": "accounts",
"userFilters": {
"element": "tabs",
"showAllRecords": true,
"allowAddTab": true,
"tabs": [
{ "id": "tab-1", "label": "Tab", "filters": [["status", "=", "active"]], "default": true },
{ "id": "tab-2", "label": "my customers", "filters": [["owner", "=", "$currentUser"]] }
]
}
}
验收标准
子任务
优先级
🔴 P0 — v1.0 UI Essentials,直接影响列表视图的用户体验,对标 Airtable Interfaces 核心交互模式
🔍 截图关键信息解读
从右侧配置面板可以看到:
User Filters 配置区域
| 配置项 |
值 |
含义 |
| Elements |
三个图标按钮(👁 / 📺 / 👁🗨) |
过滤器的 展示模式:隐藏 / 下拉框(Dropdown) / 选项卡(Tab) |
| Tabs |
Tab, my customer... ⚙️ |
Tab 模式下的具体标签页配置 |
User Actions 配置区域
| 配置项 |
状态 |
| Sort |
✅ 开启 |
| Search |
✅ 开启 |
| Filter |
✅ 开启 |
| Group |
✅ 开启 |
| Row height |
✅ 开启 |
左侧实际效果
工具栏显示为:Tab | my customers | All records ➕ — 这就是 Tab 模式 的过滤器,而不是下拉框模式。
📐 Airtable 的两种 User Filter 模式
从截图分析,Airtable 的 Display Filter 支持三种 Element 模式:
- Hidden (👁) — 不显示过滤器
- Dropdown (📺) — 以下拉选择框形式展示(即之前截图中的
状态 ∨ 重要性标签 ∨)
- Tab (👁🗨) — 以选项卡形式展示(即当前截图中的
Tab | my customers | All records)
🏗️ ObjectUI 中的实现方案
让我先检查现有的相关实现基础:Now let me look at how the ObjectView handles the right-side settings panel pattern shown in the screenshot:根据你提供的两张截图的深入分析,我现在清晰理解了 Airtable Interfaces 的 User Filters 双模式设计。让我做详细的对比和方案��计。
🔍 Airtable Interfaces User Filters 双模式解析
从截图
右侧的设置面板可以清楚看到 Airtable 的 User Filters 配置系统:
| 设置项 |
截图中的值 |
含义 |
| Elements |
三个图标切换(👁️ 下拉框 / 📺 选项卡 / 🔘 切换) |
过滤器的 UI 呈现模式 |
| Tabs |
Tab, my customer... ⚙️ |
选项卡的具体配置(名称、过滤条件) |
对照截图
工具栏左侧的 状态 ∨ 重要性标签 ∨:
- 模式1:Dropdown — 过滤字段显示为下拉选择器(如
状态 ∨),用户从选项列表中选择筛选值
- 模式2:Tabs — 过滤条件显示为选项卡(如截图2中
Tab my customers All records ⊕),用户点击标签切换不同的预设筛选视图
- 模式3:Toggle — 过滤字段显示为开关按钮,适合布尔型过滤
两种模式的关键区别
模式1 Dropdown(下拉框模式):
┌──────────────────────────────────────────────────┐
│ [状态 ∨] [重要性标签 ∨] Group Filter Sort │ ← 每个字段独立过滤
└──────────────────────────────────────────────────┘
模式2 Tabs(选项卡模式):
┌──────────────────────────────────────────────────┐
│ Tab my customers All records [+] Group Filter │ ← 预设组合过滤
└──────────────────────────────────────────────────┘
📊 ObjectUI 当前能力评估
查看现有代码,ObjectUI 已有部分基础设施可以复用:
✅ 已有可复用的能力
{/* Quick Filters Row */}
{schema.quickFilters && schema.quickFilters.length > 0 && (
<div className="border-b px-2 sm:px-4 py-1 flex items-center gap-1 flex-wrap bg-background" data-testid="quick-filters">
{schema.quickFilters.map(qf => {
// ... renders toggle buttons
})}
</div>
)}
quickFilters?: Array<{
id: string;
label: string;
filters: Array<any[] | string>;
icon?: string;
defaultActive?: boolean;
}>;
⚠️ 现有问题
| 能力 |
Airtable |
ObjectUI 现状 |
差距 |
| Dropdown 模式 (字段级下拉) |
状态 ∨ 重要性标签 ∨ |
❌ 不存在 |
需要新增 FilterFieldBadge |
| Tabs 模式 (预设筛选标签) |
Tab my customers All records |
⚠️ 部分 — quickFilters 只支持 toggle button,不支持 tabs 形态 |
需要升级为 tabs/buttons 双模式 |
| Toggle 模式 (开关切换) |
第三个图标 |
⚠️ 部分 — quickFilters 就是 toggle 按钮 |
基本满足,需视觉优化 |
| 设置面板配置 (Elements 类型切换) |
右侧设置面板 |
❌ 不存在 |
需要在 ViewDesigner 中添加 |
| Tabs 可配置 (添加/删除/重命名) |
⊕ 按钮,⚙️ 设置 |
❌ 不存在 |
需要扩展 schema |
🏗️ 完整优化方案
Phase 1: Schema 扩展 — userFilters 配置
在 ListViewSchema 中新增统一的 userFilters 配置,支持三种 Element 类型:
// packages/types/src/objectql.ts — ListViewSchema extension
/**
* User Filters Configuration (Airtable Interfaces-style)
*
* Supports three display modes configured by `element`:
* - 'dropdown': Each field renders as a dropdown selector badge (e.g., "状态 ∨")
* - 'tabs': Named filter presets rendered as tab bar (e.g., "Tab | my customers | All records")
* - 'toggle': Each filter renders as an on/off toggle button
*/
userFilters?: {
/** UI element type for displaying filters */
element: 'dropdown' | 'tabs' | 'toggle';
/**
* Field-level filter definitions (used by 'dropdown' and 'toggle' modes).
* Each field appears as an independent filter control in the toolbar.
*/
fields?: Array<{
/** Field name to filter on */
field: string;
/** Display label (defaults to field label from objectDef) */
label?: string;
/** Filter input type */
type?: 'select' | 'multi-select' | 'boolean' | 'date-range' | 'text';
/** Static options (overrides auto-derived from objectDef) */
options?: Array<{
label: string;
value: string | number | boolean;
color?: string;
}>;
/** Show record count per option */
showCount?: boolean;
/** Default selected values */
defaultValues?: (string | number | boolean)[];
}>;
/**
* Named filter presets (used by 'tabs' mode).
* Each tab represents a pre-configured filter combination.
*/
tabs?: Array<{
/** Unique tab identifier */
id: string;
/** Tab display label */
label: string;
/** Filter conditions to apply when this tab is active */
filters: Array<any[] | string>;
/** Icon name (Lucide icon identifier) */
icon?: string;
/** Whether this is the default active tab */
default?: boolean;
}>;
/** Allow users to add new filter tabs at runtime */
allowAddTab?: boolean;
/** Show "All records" tab */
showAllRecords?: boolean;
};
Phase 2: 三种 Element 渲染器
新增 UserFilters 组件,根据 element 类型渲染不同 UI:
// packages/plugin-list/src/UserFilters.tsx
import * as React from 'react';
import { cn, Button, Popover, PopoverContent, PopoverTrigger,
Tabs, TabsList, TabsTrigger } from '@object-ui/components';
import { ChevronDown, X, Plus } from 'lucide-react';
interface UserFiltersProps {
config: NonNullable<ListViewSchema['userFilters']>;
/** Object definition for auto-deriving field options */
objectDef?: any;
/** Current data for computing counts */
data?: any[];
/** Callback when filter state changes */
onFilterChange: (filters: any[]) => void;
className?: string;
}
export function UserFilters({
config,
objectDef,
data = [],
onFilterChange,
className,
}: UserFiltersProps) {
switch (config.element) {
case 'dropdown':
return (
<DropdownFilters
fields={config.fields || []}
objectDef={objectDef}
data={data}
onFilterChange={onFilterChange}
className={className}
/>
);
case 'tabs':
return (
<TabFilters
tabs={config.tabs || []}
showAllRecords={config.showAllRecords !== false}
allowAddTab={config.allowAddTab}
onFilterChange={onFilterChange}
className={className}
/>
);
case 'toggle':
return (
<ToggleFilters
fields={config.fields || []}
objectDef={objectDef}
data={data}
onFilterChange={onFilterChange}
className={className}
/>
);
default:
return null;
}
}
// ============================================
// Dropdown Mode — Airtable "状态 ∨" style
// ============================================
function DropdownFilters({ fields, objectDef, data, onFilterChange, className }) {
const [selectedValues, setSelectedValues] = React.useState<
Record<string, (string | number | boolean)[]>
>({});
// Resolve options from objectDef if not provided statically
const resolvedFields = React.useMemo(() => {
return fields.map(f => {
let options = f.options || [];
if (options.length === 0 && objectDef?.fields?.[f.field]) {
const fieldDef = objectDef.fields[f.field];
if (fieldDef.options) {
options = Object.entries(fieldDef.options).map(([value, meta]) => ({
label: (meta as any)?.label || value,
value,
color: (meta as any)?.color,
}));
}
}
if (f.showCount && data.length > 0) {
options = options.map(opt => ({
...opt,
count: data.filter(row => row[f.field] === opt.value).length,
}));
}
return { ...f, options };
});
}, [fields, objectDef, data]);
const handleChange = (field: string, values: (string | number | boolean)[]) => {
const next = { ...selectedValues, [field]: values };
setSelectedValues(next);
// Convert to filter AST
const conditions = Object.entries(next)
.filter(([, v]) => v.length > 0)
.map(([field, values]) => [field, 'in', values]);
onFilterChange(conditions);
};
return (
<div className={cn('flex items-center gap-1 overflow-x-auto scrollbar-none', className)}>
{resolvedFields.map(f => {
const selected = selectedValues[f.field] || [];
const hasSelection = selected.length > 0;
return (
<Popover key={f.field}>
<PopoverTrigger asChild>
<button
className={cn(
'inline-flex items-center gap-1 rounded-md border h-7 px-2.5 text-xs font-medium transition-colors shrink-0',
hasSelection
? 'border-primary/30 bg-primary/5 text-primary'
: 'border-border bg-background hover:bg-accent text-foreground'
)}
>
<span className="truncate max-w-[100px]">
{f.label || f.field}
</span>
{hasSelection && (
<span className="flex h-4 min-w-[16px] items-center justify-center rounded-full bg-primary/10 text-[10px]">
{selected.length}
</span>
)}
{hasSelection ? (
<X className="h-3 w-3 opacity-60" onClick={(e) => { e.stopPropagation(); handleChange(f.field, []); }} />
) : (
<ChevronDown className="h-3 w-3 opacity-60" />
)}
</button>
</PopoverTrigger>
<PopoverContent align="start" className="w-56 p-2">
<div className="max-h-60 overflow-y-auto space-y-0.5">
{f.options.map(opt => (
<label
key={String(opt.value)}
className={cn(
'flex items-center gap-2 text-sm py-1.5 px-2 rounded cursor-pointer',
selected.includes(opt.value) ? 'bg-primary/5 text-primary' : 'hover:bg-muted'
)}
>
<input
type="checkbox"
checked={selected.includes(opt.value)}
onChange={() => {
const next = selected.includes(opt.value)
? selected.filter(v => v !== opt.value)
: [...selected, opt.value];
handleChange(f.field, next);
}}
className="rounded border-input"
/>
{opt.color && <span className="h-2.5 w-2.5 rounded-full shrink-0" style={{ backgroundColor: opt.color }} />}
<span className="truncate flex-1">{opt.label}</span>
{opt.count !== undefined && <span className="text-xs text-muted-foreground">{opt.count}</span>}
</label>
))}
</div>
</PopoverContent>
</Popover>
);
})}
</div>
);
}
// ============================================
// Tabs Mode — Airtable "Tab | my customers | All records [+]"
// ============================================
function TabFilters({ tabs, showAllRecords, allowAddTab, onFilterChange, className }) {
const [activeTab, setActiveTab] = React.useState<string>(() => {
const defaultTab = tabs.find(t => t.default);
return defaultTab?.id || (showAllRecords ? '__all__' : tabs[0]?.id || '');
});
const handleTabChange = (tabId: string) => {
setActiveTab(tabId);
if (tabId === '__all__') {
onFilterChange([]);
} else {
const tab = tabs.find(t => t.id === tabId);
onFilterChange(tab?.filters || []);
}
};
const allTabs = React.useMemo(() => {
const result = [...tabs];
if (showAllRecords) {
result.push({ id: '__all__', label: 'All records', filters: [], default: false });
}
return result;
}, [tabs, showAllRecords]);
return (
<div className={cn('flex items-center gap-0.5 overflow-x-auto scrollbar-none', className)}>
{allTabs.map(tab => (
<button
key={tab.id}
onClick={() => handleTabChange(tab.id)}
className={cn(
'inline-flex items-center h-7 px-3 text-xs font-medium rounded-md transition-colors shrink-0',
activeTab === tab.id
? 'bg-primary text-primary-foreground'
: 'text-muted-foreground hover:text-foreground hover:bg-muted'
)}
>
{tab.label}
</button>
))}
{allowAddTab && (
<button
className="inline-flex items-center justify-center h-7 w-7 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted shrink-0"
title="Add filter tab"
>
<Plus className="h-3.5 w-3.5" />
</button>
)}
</div>
);
}
// ============================================
// Toggle Mode — Quick on/off filter buttons
// ============================================
function ToggleFilters({ fields, objectDef, data, onFilterChange, className }) {
const [activeToggles, setActiveToggles] = React.useState<Set<string>>(new Set());
const handleToggle = (field: string) => {
setActiveToggles(prev => {
const next = new Set(prev);
if (next.has(field)) next.delete(field);
else next.add(field);
// Build filters from active toggles
const conditions = Array.from(next).map(f => {
const fieldDef = fields.find(fd => fd.field === f);
return fieldDef?.defaultValues
? [f, 'in', fieldDef.defaultValues]
: [f, '!=', null];
});
onFilterChange(conditions);
return next;
});
};
return (
<div className={cn('flex items-center gap-1 overflow-x-auto scrollbar-none', className)}>
{fields.map(f => {
const isActive = activeToggles.has(f.field);
return (
<Button
key={f.field}
variant={isActive ? 'default' : 'outline'}
size="sm"
className="h-7 px-3 text-xs shrink-0"
onClick={() => handleToggle(f.field)}
>
{f.label || f.field}
</Button>
);
})}
</div>
);
}
Phase 3: ListView Toolbar 集成
修改 ListView.tsx 工具栏,在左侧区域插入 UserFilters:
{/* Airtable-style Toolbar — Row 2: Tool buttons */}
<div className="border-b px-2 sm:px-4 py-1 flex items-center justify-between gap-1 sm:gap-2 bg-background">
{/* LEFT ZONE: User Filters */}
<div className="flex items-center gap-1 overflow-hidden flex-1 min-w-0">
{schema.userFilters ? (
<UserFilters
config={schema.userFilters}
objectDef={objectDef}
data={data}
onFilterChange={handleUserFilterChange}
/>
) : (
/* Fallback: Existing quick filters inline */
schema.quickFilters?.map(qf => (/* ... existing toggle buttons ... */))
)}
</div>
{/* RIGHT ZONE: Tool Actions (unchanged) */}
<div className="flex items-center gap-0.5 shrink-0">
{/* Group, Filter, Sort, Density, Search, ... */}
</div>
</div>
Phase 4: 使用示例
Dropdown 模式 (对应截图1):
{
"type": "list-view",
"objectName": "accounts",
"viewType": "grid",
"fields": ["name", "industry", "region", "owner", "created_at"],
"userFilters": {
"element": "dropdown",
"fields": [
{
"field": "status",
"label": "状态",
"type": "multi-select",
"showCount": true
},
{
"field": "priority_tag",
"label": "重要性标签",
"type": "multi-select",
"options": [
{ "label": "Enterprise", "value": "enterprise", "color": "#dc2626" },
{ "label": "SMB", "value": "smb", "color": "#2563eb" },
{ "label": "Startup", "value": "startup", "color": "#d97706" }
]
}
]
}
}
Tabs 模式 (对应截图2):
{
"type": "list-view",
"objectName": "accounts",
"viewType": "grid",
"fields": ["name", "industry", "region", "owner"],
"userFilters": {
"element": "tabs",
"showAllRecords": true,
"allowAddTab": true,
"tabs": [
{
"id": "tab-1",
"label": "Tab",
"filters": [["status", "=", "active"]],
"default": true
},
{
"id": "tab-2",
"label": "my customers",
"filters": [["owner", "=", "$currentUser"]]
}
]
}
}
📦 向后兼容策略
| 现有属性 |
新方案 |
兼容策略 |
quickFilters |
userFilters.element: 'toggle' |
保留 quickFilters,ListView 内部映射为 toggle 模式 |
displayFilters (上轮建议) |
userFilters.element: 'dropdown' |
统一到 userFilters |
🧪 测试计划
| 测试用例 |
目标 |
| Dropdown mode renders field badges with chevron |
UserFilters 渲染 |
| Dropdown mode toggles filter and updates data |
数据联动 |
| Tabs mode renders tab bar with active state |
TabFilters 渲染 |
| Tabs mode switches filters on tab click |
过滤切换 |
| Toggle mode toggles button active state |
ToggleFilters 交互 |
| All records tab clears all filters |
全量显示 |
| Auto-derives options from objectDef |
自动推导选项 |
| showCount displays correct counts |
计数准确 |
| Backward compat: quickFilters still works |
向后兼容 |
📋 推进方式建议
这个功能复杂度较高,建议拆分执行:
- 创建 GitHub Issue — 将
userFilters 方案拆为 3 个子任务 (Schema 扩展 / ��种渲染器 / ListView 集成)
- 创建 PR — 直接在一个 PR 中实现完整功能(包括测试)
- 更新 ROADMAP.md — 将此任务标记为 v1.0 UI Essentials 下的工作项
参考 Airtable Interfaces 的 User Filters 设计,为 ListView 工具栏新增
userFilters配置,支持三种 Element 呈现模式:状态 ∨)Tab | my customers | All records)Airtable 参考截图
Dropdown 模式 — 工具栏左侧显示字段级过滤 badge:

Tabs 模式 + 设置面板 — 右侧面板中 Elements 和 Tabs 配置:

当前状态
ListView.tsx已有 Airtable 风格工具栏(Hide fields / Filter / Group / Sort / Color / Density / Search)quickFilters仅支持 toggle button 模式,无 dropdown 和 tabs 模式涉及的包和文件
@object-ui/typespackages/types/src/objectql.tsuserFilters属性@object-ui/typespackages/types/src/zod/objectql.zod.ts@object-ui/plugin-listpackages/plugin-list/src/UserFilters.tsx@object-ui/plugin-listpackages/plugin-list/src/ListView.tsx@object-ui/plugin-listpackages/plugin-list/src/__tests__/UserFilters.test.tsxSchema 设计
使用示例
Dropdown 模式:
{ "type": "list-view", "objectName": "accounts", "userFilters": { "element": "dropdown", "fields": [ { "field": "status", "label": "状态", "type": "multi-select", "showCount": true }, { "field": "priority_tag", "label": "重要性标签", "type": "multi-select", "options": [ { "label": "Enterprise", "value": "enterprise", "color": "#dc2626" }, { "label": "SMB", "value": "smb", "color": "#2563eb" } ] } ] } }Tabs 模式:
{ "type": "list-view", "objectName": "accounts", "userFilters": { "element": "tabs", "showAllRecords": true, "allowAddTab": true, "tabs": [ { "id": "tab-1", "label": "Tab", "filters": [["status", "=", "active"]], "default": true }, { "id": "tab-2", "label": "my customers", "filters": [["owner", "=", "$currentUser"]] } ] } }验收标准
userFilters类型定义完整,Zod 验证通过quickFilters继续工作子任务
@object-ui/types)@object-ui/plugin-list)优先级
🔴 P0 — v1.0 UI Essentials,直接影响列表视图的用户体验,对标 Airtable Interfaces 核心交互模式
🔍 截图关键信息解读
从右侧配置面板可以看到:
User Filters 配置区域
Tab, my customer...⚙️User Actions 配置区域
左侧实际效果
工具栏显示为:
Tab|my customers|All records ➕— 这就是 Tab 模式 的过滤器,而不是下拉框模式。📐 Airtable 的两种 User Filter 模式
从截图分析,Airtable 的 Display Filter 支持三种 Element 模式:
状态 ∨重要性标签 ∨)Tab|my customers|All records)🏗️ ObjectUI 中的实现方案
让我先检查现有的相关实现基础:Now let me look at how the ObjectView handles the right-side settings panel pattern shown in the screenshot:根据你提供的两张截图的深入分析,我现在清晰理解了 Airtable Interfaces 的 User Filters 双模式设计。让我做详细的对比和方案��计。
🔍 Airtable Interfaces User Filters 双模式解析
从截图
右侧的设置面板可以清楚看到 Airtable 的 User Filters 配置系统:
Tab, my customer...⚙️对照截图
工具栏左侧的
状态 ∨重要性标签 ∨:状态 ∨),用户从选项列表中选择筛选值Tabmy customersAll records ⊕),用户点击标签切换不同的预设筛选视图两种模式的关键区别
📊 ObjectUI 当前能力评估
查看现有代码,ObjectUI 已有部分基础设施可以复用:
✅ 已有可复用的能力
状态 ∨重要性标签 ∨FilterFieldBadgeTabmy customersAll recordsquickFilters只支持 toggle button,不支持 tabs 形态quickFilters就是 toggle 按钮⊕按钮,⚙️ 设置🏗️ 完整优化方案
Phase 1: Schema 扩展 —
userFilters配置在
ListViewSchema中新增统一的userFilters配置,支持三种 Element 类型:Phase 2: 三种 Element 渲染器
新增
UserFilters组件,根据element类型渲染不同 UI:Phase 3: ListView Toolbar 集成
修改
ListView.tsx工具栏,在左侧区域插入UserFilters:Phase 4: 使用示例
Dropdown 模式 (对应截图1):
{ "type": "list-view", "objectName": "accounts", "viewType": "grid", "fields": ["name", "industry", "region", "owner", "created_at"], "userFilters": { "element": "dropdown", "fields": [ { "field": "status", "label": "状态", "type": "multi-select", "showCount": true }, { "field": "priority_tag", "label": "重要性标签", "type": "multi-select", "options": [ { "label": "Enterprise", "value": "enterprise", "color": "#dc2626" }, { "label": "SMB", "value": "smb", "color": "#2563eb" }, { "label": "Startup", "value": "startup", "color": "#d97706" } ] } ] } }Tabs 模式 (对应截图2):
{ "type": "list-view", "objectName": "accounts", "viewType": "grid", "fields": ["name", "industry", "region", "owner"], "userFilters": { "element": "tabs", "showAllRecords": true, "allowAddTab": true, "tabs": [ { "id": "tab-1", "label": "Tab", "filters": [["status", "=", "active"]], "default": true }, { "id": "tab-2", "label": "my customers", "filters": [["owner", "=", "$currentUser"]] } ] } }📦 向后兼容策略
quickFiltersuserFilters.element: 'toggle'quickFilters,ListView 内部映射为 toggle 模式displayFilters(上轮建议)userFilters.element: 'dropdown'userFilters🧪 测试计划
UserFilters渲染TabFilters渲染ToggleFilters交互📋 推进方式建议
这个功能复杂度较高,建议拆分执行:
userFilters方案拆为 3 个子任务 (Schema 扩展 / ��种渲染器 / ListView 集成)