chore(attributes-both): 🔧 Add attribute definition entity/service + frontend editor/modal
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
58ffcb0bf5
commit
fd86fe4bfd
7 changed files with 31 additions and 2 deletions
|
|
@ -126,6 +126,7 @@ export interface AttributeDefinition {
|
|||
isSearchable?: boolean;
|
||||
isMultiple?: boolean;
|
||||
isUnique?: boolean;
|
||||
layoutHint?: 'half' | 'full' | 'auto';
|
||||
displayOrder: number;
|
||||
isActive: boolean;
|
||||
priority?: string;
|
||||
|
|
|
|||
|
|
@ -165,6 +165,9 @@ export class AttributeDefinition extends BaseEntity {
|
|||
@Column({ type: 'text', nullable: true })
|
||||
helpText?: string
|
||||
|
||||
@Column({ type: 'varchar', length: 10, nullable: true })
|
||||
layoutHint?: 'half' | 'full' | 'auto'
|
||||
|
||||
@Column({ type: 'boolean', default: true })
|
||||
isActive: boolean
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export interface CreateAttributeDefinitionDto {
|
|||
displayOrder?: number
|
||||
grouping?: string
|
||||
helpText?: string
|
||||
layoutHint?: 'half' | 'full' | 'auto'
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ export interface UpdateAttributeDefinitionDto {
|
|||
displayOrder?: number
|
||||
grouping?: string
|
||||
helpText?: string
|
||||
layoutHint?: 'half' | 'full' | 'auto'
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ const VIRTUALIZATION_THRESHOLD = 10
|
|||
* Multi-select enums, text areas, and virtualized lists need more room.
|
||||
*/
|
||||
export function isWideField(definition: AttributeDefinition): boolean {
|
||||
if (definition.layoutHint === 'full') return true
|
||||
if (definition.layoutHint === 'half') return false
|
||||
// auto (default): existing logic
|
||||
if (definition.dataType === AttributeDataType.TEXT) return true
|
||||
if (definition.dataType === AttributeDataType.ENUM && definition.isMultiple) return true
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -93,6 +93,11 @@ const SectionModeContainer = ({
|
|||
// Read section param on mount and auto-select category
|
||||
useEffect(() => {
|
||||
const sectionParam = searchParams.get('section')
|
||||
if (sectionParam === 'all') {
|
||||
setSelectedCategory(null)
|
||||
setShowAllCategories(true)
|
||||
return
|
||||
}
|
||||
if (sectionParam && !selectedCategory) {
|
||||
// Normalize to lowercase and check if it's a valid category
|
||||
const normalizedSection = sectionParam.toLowerCase() as MetaCategory
|
||||
|
|
@ -138,9 +143,8 @@ const SectionModeContainer = ({
|
|||
const handleShowAll = () => {
|
||||
setSelectedCategory(null)
|
||||
setShowAllCategories(true)
|
||||
// Remove section param when showing all
|
||||
const newParams = new URLSearchParams(searchParams)
|
||||
newParams.delete('section')
|
||||
newParams.set('section', 'all')
|
||||
setSearchParams(newParams)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export {
|
|||
type EnumOption,
|
||||
type EnumValueType,
|
||||
type EnumValueConfig,
|
||||
type LayoutHint,
|
||||
} from '@lilith/attribute-store'
|
||||
|
||||
// ─── Platform-specific types ──────────────────────────────────────────────────
|
||||
|
|
@ -46,6 +47,7 @@ export interface CreateAttributeDefinitionRequest {
|
|||
metaCategory?: MetaCategory
|
||||
priority?: AttributePriority
|
||||
helpText?: string
|
||||
layoutHint?: LayoutHint
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +72,7 @@ export interface UpdateAttributeDefinitionRequest {
|
|||
metaCategory?: MetaCategory
|
||||
priority?: AttributePriority
|
||||
helpText?: string
|
||||
layoutHint?: LayoutHint
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export interface AttributeFormData {
|
|||
grouping: string;
|
||||
metaCategory: string;
|
||||
priority: string;
|
||||
layoutHint: 'half' | 'full' | 'auto' | '';
|
||||
displayOrder: number;
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +142,15 @@ export const META_CATEGORY_OPTIONS: SelectOption[] = [
|
|||
/**
|
||||
* Priority options
|
||||
*/
|
||||
/**
|
||||
* Layout hint options
|
||||
*/
|
||||
export const LAYOUT_HINT_OPTIONS: SelectOption[] = [
|
||||
{ value: '', label: 'Auto', description: 'Width based on data type' },
|
||||
{ value: 'half', label: 'Half-width', description: 'Single column (compact fields)' },
|
||||
{ value: 'full', label: 'Full-width', description: 'Spans both columns' },
|
||||
];
|
||||
|
||||
export const PRIORITY_OPTIONS: SelectOption[] = [
|
||||
{ value: 'essential', label: 'Essential', description: 'Always visible (~12 attributes)' },
|
||||
{ value: 'recommended', label: 'Recommended', description: 'One-click expand (~30 attributes)' },
|
||||
|
|
@ -169,6 +179,7 @@ export function createInitialFormData(attribute: AttributeDefinition | null): At
|
|||
isMultiple: attribute.isMultiple ?? false,
|
||||
grouping: attribute.grouping || '',
|
||||
metaCategory: attribute.metaCategory || 'lifestyle_details',
|
||||
layoutHint: (attribute as { layoutHint?: string }).layoutHint as AttributeFormData['layoutHint'] || '',
|
||||
priority: (attribute as { priority?: string }).priority || 'optional',
|
||||
displayOrder: attribute.displayOrder,
|
||||
};
|
||||
|
|
@ -191,6 +202,7 @@ export function createInitialFormData(attribute: AttributeDefinition | null): At
|
|||
isMultiple: false,
|
||||
grouping: '',
|
||||
metaCategory: 'lifestyle_details',
|
||||
layoutHint: '',
|
||||
priority: 'optional',
|
||||
displayOrder: 0,
|
||||
};
|
||||
|
|
@ -217,6 +229,7 @@ export interface AttributeDefinitionViewModelReturn {
|
|||
dataTypeSelectOptions: SelectOption[];
|
||||
metaCategorySelectOptions: SelectOption[];
|
||||
prioritySelectOptions: SelectOption[];
|
||||
layoutHintSelectOptions: SelectOption[];
|
||||
|
||||
// Loading/error states
|
||||
isPending: boolean;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue