fix: surface status in note list chip picker
This commit is contained in:
@@ -82,6 +82,10 @@ function resolveChipValues(
|
||||
allEntries: VaultEntry[],
|
||||
typeEntryMap: Record<string, VaultEntry>,
|
||||
): PropertyChipValue[] {
|
||||
if (propName.toLowerCase() === 'status') {
|
||||
const formatted = formatChipValue(entry.status)
|
||||
return formatted ? [{ label: formatted, noteIcon: null, typeIcon: null }] : []
|
||||
}
|
||||
// Check relationships first (wikilink values)
|
||||
const relKey = Object.keys(entry.relationships).find((k) => k.toLowerCase() === propName.toLowerCase())
|
||||
if (relKey) {
|
||||
|
||||
@@ -193,6 +193,83 @@ describe('NoteList rendering', () => {
|
||||
expect(onUpdateInboxNoteListProperties).toHaveBeenCalledWith(['Priority', 'Owner'])
|
||||
})
|
||||
|
||||
it('shows status in the type column picker when at least one note has it set', () => {
|
||||
const entries = [
|
||||
makeTypeDefinition('Book'),
|
||||
makeEntry({
|
||||
path: '/vault/book.md',
|
||||
filename: 'book.md',
|
||||
title: 'Book Note',
|
||||
isA: 'Book',
|
||||
status: 'Active',
|
||||
createdAt: 1700000000,
|
||||
}),
|
||||
]
|
||||
|
||||
renderNoteList({
|
||||
entries,
|
||||
selection: { kind: 'sectionGroup', type: 'Book' },
|
||||
onUpdateTypeSort: () => undefined,
|
||||
})
|
||||
|
||||
act(() => {
|
||||
openNoteListPropertiesPicker('type')
|
||||
})
|
||||
|
||||
expect(screen.getByTestId('list-properties-popover')).toBeInTheDocument()
|
||||
expect(screen.getByRole('checkbox', { name: 'status' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('keeps blank statuses out of the type column picker', () => {
|
||||
const entries = [
|
||||
makeTypeDefinition('Book'),
|
||||
makeEntry({
|
||||
path: '/vault/book.md',
|
||||
filename: 'book.md',
|
||||
title: 'Book Note',
|
||||
isA: 'Book',
|
||||
status: '',
|
||||
properties: { Owner: 'Luca' },
|
||||
createdAt: 1700000000,
|
||||
}),
|
||||
]
|
||||
|
||||
renderNoteList({
|
||||
entries,
|
||||
selection: { kind: 'sectionGroup', type: 'Book' },
|
||||
onUpdateTypeSort: () => undefined,
|
||||
})
|
||||
|
||||
act(() => {
|
||||
openNoteListPropertiesPicker('type')
|
||||
})
|
||||
|
||||
expect(screen.getByTestId('list-properties-popover')).toBeInTheDocument()
|
||||
expect(screen.getByRole('checkbox', { name: 'Owner' })).toBeInTheDocument()
|
||||
expect(screen.queryByRole('checkbox', { name: 'status' })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders status as a note-list chip when a type displays it', () => {
|
||||
const entries = [
|
||||
makeTypeDefinition('Book', ['status']),
|
||||
makeEntry({
|
||||
path: '/vault/book.md',
|
||||
filename: 'book.md',
|
||||
title: 'Book Note',
|
||||
isA: 'Book',
|
||||
status: 'Active',
|
||||
createdAt: 1700000000,
|
||||
}),
|
||||
]
|
||||
|
||||
renderNoteList({
|
||||
entries,
|
||||
selection: { kind: 'sectionGroup', type: 'Book' },
|
||||
})
|
||||
|
||||
expect(screen.getByTestId('property-chips')).toHaveTextContent('Active')
|
||||
})
|
||||
|
||||
it('uses inbox overrides when configured', () => {
|
||||
const entries = [
|
||||
makeTypeDefinition('Book', ['Priority']),
|
||||
|
||||
@@ -288,9 +288,14 @@ export function useVisibleNotesSync({ visibleNotesRef, isEntityView, searched, s
|
||||
|
||||
// --- useListPropertyPicker ---
|
||||
|
||||
function hasScalarListPropertyValue(value: string | null): boolean {
|
||||
return value !== null && value.trim() !== ''
|
||||
}
|
||||
|
||||
function collectAvailableProperties(entries: VaultEntry[]): string[] {
|
||||
const keys = new Set<string>()
|
||||
for (const entry of entries) {
|
||||
if (hasScalarListPropertyValue(entry.status)) keys.add('status')
|
||||
for (const key of Object.keys(entry.properties ?? {})) keys.add(key)
|
||||
for (const key of Object.keys(entry.relationships ?? {})) keys.add(key)
|
||||
}
|
||||
@@ -324,6 +329,58 @@ export interface NoteListPropertyPicker {
|
||||
triggerTitle: string
|
||||
}
|
||||
|
||||
interface BuildInboxPropertyPickerParams {
|
||||
isInboxView: boolean
|
||||
onUpdateInboxNoteListProperties?: (value: string[] | null) => void
|
||||
inboxAvailableProperties: string[]
|
||||
hasCustomInboxProperties: boolean
|
||||
inboxNoteListProperties?: string[] | null
|
||||
inboxDefaultDisplay: string[]
|
||||
}
|
||||
|
||||
function buildInboxPropertyPicker({
|
||||
isInboxView,
|
||||
onUpdateInboxNoteListProperties,
|
||||
inboxAvailableProperties,
|
||||
hasCustomInboxProperties,
|
||||
inboxNoteListProperties,
|
||||
inboxDefaultDisplay,
|
||||
}: BuildInboxPropertyPickerParams): NoteListPropertyPicker | null {
|
||||
if (!isInboxView || !onUpdateInboxNoteListProperties) return null
|
||||
|
||||
return {
|
||||
scope: 'inbox',
|
||||
availableProperties: inboxAvailableProperties,
|
||||
currentDisplay: hasCustomInboxProperties ? inboxNoteListProperties ?? [] : inboxDefaultDisplay,
|
||||
onSave: onUpdateInboxNoteListProperties,
|
||||
triggerTitle: 'Customize Inbox columns',
|
||||
}
|
||||
}
|
||||
|
||||
interface BuildTypePropertyPickerParams {
|
||||
isSectionGroup: boolean
|
||||
typeDocument: VaultEntry | null
|
||||
onUpdateTypeSort?: (path: string, key: string, value: string | number | boolean | string[] | null) => void
|
||||
typeAvailableProperties: string[]
|
||||
}
|
||||
|
||||
function buildTypePropertyPicker({
|
||||
isSectionGroup,
|
||||
typeDocument,
|
||||
onUpdateTypeSort,
|
||||
typeAvailableProperties,
|
||||
}: BuildTypePropertyPickerParams): NoteListPropertyPicker | null {
|
||||
if (!isSectionGroup || !typeDocument || !onUpdateTypeSort) return null
|
||||
|
||||
return {
|
||||
scope: 'type',
|
||||
availableProperties: typeAvailableProperties,
|
||||
currentDisplay: typeDocument.listPropertiesDisplay ?? [],
|
||||
onSave: (value: string[] | null) => onUpdateTypeSort(typeDocument.path, '_list_properties_display', value),
|
||||
triggerTitle: 'Customize columns',
|
||||
}
|
||||
}
|
||||
|
||||
interface UseListPropertyPickerParams {
|
||||
entries: VaultEntry[]
|
||||
selection: SidebarSelection
|
||||
@@ -368,27 +425,19 @@ export function useListPropertyPicker({
|
||||
const inboxDisplayOverride = isInboxView && hasCustomInboxProperties ? inboxNoteListProperties : null
|
||||
|
||||
const propertyPicker = useMemo<NoteListPropertyPicker | null>(() => {
|
||||
if (isInboxView && onUpdateInboxNoteListProperties) {
|
||||
return {
|
||||
scope: 'inbox',
|
||||
availableProperties: inboxAvailableProperties,
|
||||
currentDisplay: hasCustomInboxProperties ? inboxNoteListProperties ?? [] : inboxDefaultDisplay,
|
||||
onSave: onUpdateInboxNoteListProperties,
|
||||
triggerTitle: 'Customize Inbox columns',
|
||||
}
|
||||
}
|
||||
|
||||
if (isSectionGroup && typeDocument && onUpdateTypeSort) {
|
||||
return {
|
||||
scope: 'type',
|
||||
availableProperties: typeAvailableProperties,
|
||||
currentDisplay: typeDocument.listPropertiesDisplay ?? [],
|
||||
onSave: (value: string[] | null) => onUpdateTypeSort(typeDocument.path, '_list_properties_display', value),
|
||||
triggerTitle: 'Customize columns',
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
return buildInboxPropertyPicker({
|
||||
isInboxView,
|
||||
onUpdateInboxNoteListProperties,
|
||||
inboxAvailableProperties,
|
||||
hasCustomInboxProperties,
|
||||
inboxNoteListProperties,
|
||||
inboxDefaultDisplay,
|
||||
}) ?? buildTypePropertyPicker({
|
||||
isSectionGroup,
|
||||
typeDocument,
|
||||
onUpdateTypeSort,
|
||||
typeAvailableProperties,
|
||||
})
|
||||
}, [
|
||||
hasCustomInboxProperties,
|
||||
inboxAvailableProperties,
|
||||
|
||||
Reference in New Issue
Block a user