Coverage for src/lexigram/admin/layout/layout_manager.py: 0%

67 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-24 23:18 +0800

1"""Layout manager for lexigram-admin. 

2 

3Provides layout types and configuration for resource views. 

4""" 

5 

6from __future__ import annotations 

7 

8from dataclasses import dataclass, field 

9from enum import Enum, auto 

10from typing import TYPE_CHECKING, Any 

11 

12if TYPE_CHECKING: 

13 from collections.abc import Callable 

14 

15 

16class LayoutType(str, Enum): 

17 """Available layout types for resource views.""" 

18 

19 LIST = auto() # Standard list/table view 

20 GRID = auto() # Grid/card view 

21 CALENDAR = auto() # Calendar view for date-based data 

22 KANBAN = auto() # Kanban board view 

23 TIMELINE = auto() # Timeline view 

24 MAP = auto() # Map view for geo-data 

25 TREE = auto() # Tree/hierarchical view 

26 CUSTOM = auto() # User-defined custom layout 

27 

28 

29@dataclass 

30class LayoutConfig: 

31 """Configuration for a layout type.""" 

32 

33 type: LayoutType = LayoutType.LIST 

34 label: str = "" 

35 icon: str = "list" 

36 enabled: bool = True 

37 default: bool = False 

38 

39 # Layout-specific options 

40 options: dict[str, Any] = field(default_factory=dict) 

41 

42 # Grid-specific 

43 columns: int = 3 

44 card_template: Callable[..., Any] | None = None 

45 

46 # Calendar-specific 

47 date_field: str = "date" 

48 title_field: str = "title" 

49 

50 # Kanban-specific 

51 status_field: str = "status" 

52 statuses: list[str] = field(default_factory=list) 

53 

54 def with_option(self, key: str, value: Any) -> LayoutConfig: 

55 """Add an option and return self for chaining.""" 

56 self.options[key] = value 

57 return self 

58 

59 

60@dataclass 

61class LayoutViewConfig: 

62 """Configuration for multiple layout views on a resource.""" 

63 

64 layouts: list[LayoutConfig] = field(default_factory=list) 

65 default: LayoutType = LayoutType.LIST 

66 

67 def add(self, layout: LayoutConfig) -> LayoutViewConfig: 

68 """Add a layout configuration.""" 

69 self.layouts.append(layout) 

70 return self 

71 

72 def set_default(self, layout_type: LayoutType) -> LayoutViewConfig: 

73 """Set the default layout type.""" 

74 self.default = layout_type 

75 return self 

76 

77 

78class LayoutManager: 

79 """Manages layout configurations for a resource. 

80 

81 Handles switching between different view layouts (list, grid, calendar, etc.) 

82 and provides view rendering. 

83 """ 

84 

85 def __init__(self, default_layout: LayoutType = LayoutType.LIST): 

86 """Initialize layout manager. 

87 

88 Args: 

89 default_layout: Default layout type 

90 """ 

91 self._layouts: dict[LayoutType, LayoutConfig] = {} 

92 self._default = default_layout 

93 self._current = default_layout 

94 

95 def register(self, config: LayoutConfig) -> LayoutManager: 

96 """Register a layout configuration. 

97 

98 Args: 

99 config: Layout configuration to register 

100 

101 Returns: 

102 Self for chaining 

103 """ 

104 self._layouts[config.type] = config 

105 if config.default: 

106 self._default = config.type 

107 return self 

108 

109 def set_default(self, layout_type: LayoutType) -> LayoutManager: 

110 """Set the default layout type. 

111 

112 Args: 

113 layout_type: Layout type to set as default 

114 

115 Returns: 

116 Self for chaining 

117 """ 

118 self._default = layout_type 

119 return self 

120 

121 def get_config(self, layout_type: LayoutType) -> LayoutConfig | None: 

122 """Get configuration for a layout type. 

123 

124 Args: 

125 layout_type: Layout type to get config for 

126 

127 Returns: 

128 LayoutConfig or None if not registered 

129 """ 

130 return self._layouts.get(layout_type) 

131 

132 def get_available(self) -> list[LayoutConfig]: 

133 """Get all available layout configurations. 

134 

135 Returns: 

136 List of enabled layout configurations 

137 """ 

138 return list(filter(lambda c: c.enabled, self._layouts.values())) 

139 

140 def get_current(self) -> LayoutType: 

141 """Get the current active layout type. 

142 

143 Returns: 

144 Current layout type 

145 """ 

146 return self._current 

147 

148 def set_current(self, layout_type: LayoutType) -> None: 

149 """Set the current active layout type. 

150 

151 Args: 

152 layout_type: Layout type to set as current 

153 """ 

154 if layout_type in self._layouts: 

155 self._current = layout_type 

156 

157 def get_default(self) -> LayoutType: 

158 """Get the default layout type. 

159 

160 Returns: 

161 Default layout type 

162 """ 

163 return self._default 

164 

165 @property 

166 def has_multiple_layouts(self) -> bool: 

167 """Check if multiple layouts are available. 

168 

169 Returns: 

170 True if more than one layout is enabled 

171 """ 

172 return len(self.get_available()) > 1