Coverage for src/backend/InvenTree/plugin/base/ui/mixins.py: 57%

35 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 17:47 +0000

1"""UserInterfaceMixin class definition. 

2 

3Allows integration of custom UI elements into the React user interface. 

4""" 

5 

6from typing import Literal, TypedDict 

7 

8import structlog 

9from rest_framework.request import Request 

10 

11from plugin import PluginMixinEnum 

12 

13logger = structlog.get_logger('inventree') 

14 

15 

16# List of supported feature types 

17FeatureType = Literal[ 

18 'spotlight_action', # Custom actions for the spotlight search 

19 'dashboard', # Custom dashboard items 

20 'panel', # Custom panels 

21 'template_editor', # Custom template editor 

22 'template_preview', # Custom template preview 

23 'navigation', # Custom navigation items 

24 'primary_action', # Custom primary action buttons 

25] 

26 

27 

28class UIFeature(TypedDict): 

29 """Base type definition for a ui feature. 

30 

31 Attributes: 

32 key: The key of the feature (required, must be a unique identifier) 

33 title: The title of the feature (required, human readable) 

34 description: The long-form description of the feature (optional, human readable) 

35 icon: The icon of the feature (optional, must be a valid icon identifier) 

36 feature_type: The feature type (required, see documentation for all available types) 

37 options: Feature options (required, see documentation for all available options for each type) 

38 context: Additional context data to be passed to the rendering function (optional, dict) 

39 source: The source of the feature (required, path to a JavaScript file, with optional function name). 

40 """ 

41 

42 key: str 

43 title: str 

44 description: str 

45 icon: str 

46 feature_type: FeatureType 

47 options: dict 

48 context: dict 

49 source: str 

50 

51 

52class CustomPanelOptions(TypedDict): 

53 """Options type definition for a custom panel. 

54 

55 Attributes: 

56 icon: The icon of the panel (optional, must be a valid icon identifier). 

57 """ 

58 

59 

60class CustomDashboardItemOptions(TypedDict): 

61 """Options type definition for a custom dashboard item. 

62 

63 Attributes: 

64 width: The minimum width of the dashboard item (integer, defaults to 2) 

65 height: The minimum height of the dashboard item (integer, defaults to 2) 

66 """ 

67 

68 width: int 

69 height: int 

70 

71 

72class UserInterfaceMixin: 

73 """Plugin mixin class which handles injection of custom elements into the front-end interface. 

74 

75 - All content is accessed via the API, as requested by the user interface. 

76 - This means that content can be dynamically generated, based on the current state of the system. 

77 """ 

78 

79 class MixinMeta: 

80 """Metaclass for this plugin mixin.""" 

81 

82 MIXIN_NAME = 'ui' 

83 

84 def __init__(self): 

85 """Register mixin.""" 

86 super().__init__() 

87 self.add_mixin(PluginMixinEnum.USER_INTERFACE, True, __class__) 

88 

89 def get_ui_features( 

90 self, feature_type: FeatureType, context: dict, request: Request, **kwargs 

91 ) -> list[UIFeature]: 

92 """Return a list of custom features to be injected into the UI. 

93 

94 Arguments: 

95 feature_type: The type of feature being requested 

96 context: Additional context data provided by the UI (query parameters) 

97 request: HTTPRequest object (including user information) 

98 

99 Returns: 

100 list: A list of custom UIFeature dicts to be injected into the UI 

101 

102 """ 

103 feature_map = { 

104 'spotlight_action': self.get_ui_spotlight_actions, 

105 'dashboard': self.get_ui_dashboard_items, 

106 'navigation': self.get_ui_navigation_items, 

107 'panel': self.get_ui_panels, 

108 'template_editor': self.get_ui_template_editors, 

109 'template_preview': self.get_ui_template_previews, 

110 'primary_action': self.get_ui_primary_actions, 

111 } 

112 

113 if feature_type in feature_map: 

114 return feature_map[feature_type](request, context, **kwargs) 

115 else: 

116 logger.warning(f'Invalid feature type: {feature_type}') 

117 return [] 

118 

119 def get_ui_spotlight_actions( 

120 self, request: Request, context: dict, **kwargs 

121 ) -> list[UIFeature]: 

122 """Return a list of custom actions to be injected into the UI spotlight. 

123 

124 Args: 

125 request: HTTPRequest object (including user information) 

126 context: Additional context data provided by the UI (query parameters) 

127 

128 Returns: 

129 list: A list of custom actions to be injected into the UI spotlight. 

130 """ 

131 # Default implementation returns an empty list 

132 return [] 

133 

134 def get_ui_panels( 

135 self, request: Request, context: dict, **kwargs 

136 ) -> list[UIFeature]: 

137 """Return a list of custom panels to be injected into the UI. 

138 

139 Args: 

140 request: HTTPRequest object (including user information) 

141 context: Additional context data provided by the UI (query parameters) 

142 

143 Returns: 

144 list: A list of custom panels to be injected into the UI 

145 """ 

146 # Default implementation returns an empty list 

147 return [] 

148 

149 def get_ui_dashboard_items( 

150 self, request: Request, context: dict, **kwargs 

151 ) -> list[UIFeature]: 

152 """Return a list of custom dashboard items to be injected into the UI. 

153 

154 Args: 

155 request: HTTPRequest object (including user information) 

156 context: Additional context data provided by the UI (query parameters) 

157 

158 Returns: 

159 list: A list of custom dashboard items to be injected into the UI 

160 """ 

161 # Default implementation returns an empty list 

162 return [] 

163 

164 def get_ui_template_editors( 

165 self, request: Request, context: dict, **kwargs 

166 ) -> list[UIFeature]: 

167 """Return a list of custom template editors to be injected into the UI. 

168 

169 Args: 

170 request: HTTPRequest object (including user information) 

171 context: Additional context data provided by the UI (query parameters) 

172 

173 Returns: 

174 list: A list of custom template editors to be injected into the UI 

175 """ 

176 # Default implementation returns an empty list 

177 return [] 

178 

179 def get_ui_template_previews( 

180 self, request: Request, context: dict, **kwargs 

181 ) -> list[UIFeature]: 

182 """Return a list of custom template previews to be injected into the UI. 

183 

184 Args: 

185 request: HTTPRequest object (including user information) 

186 context: Additional context data provided by the UI (query parameters) 

187 

188 Returns: 

189 list: A list of custom template previews to be injected into the UI 

190 """ 

191 # Default implementation returns an empty list 

192 return [] 

193 

194 def get_ui_navigation_items( 

195 self, request: Request, context: dict, **kwargs 

196 ) -> list[UIFeature]: 

197 """Return a list of custom navigation items to be injected into the UI. 

198 

199 Args: 

200 request: HTTPRequest object (including user information) 

201 context: Additional context data provided by the UI (query parameters) 

202 

203 Returns: 

204 list: A list of custom navigation items to be injected into the UI 

205 """ 

206 # Default implementation returns an empty list 

207 return [] 

208 

209 def get_ui_primary_actions( 

210 self, request: Request, context: dict, **kwargs 

211 ) -> list[UIFeature]: 

212 """Return a list of custom primary action buttons to be injected into the UI. 

213 

214 Args: 

215 request: HTTPRequest object (including user information) 

216 context: Additional context data provided by the UI (query parameters) 

217 

218 Returns: 

219 list: A list of custom primary action buttons to be injected into the UI 

220 """ 

221 # Sample code to render conditional primary action button based on context 

222 # items = [] 

223 # if self.my_assert_function(context): 

224 # items.append({ 

225 # 'key': 'sample-primary-action', 

226 # 'title': 'Sample Primary Action', 

227 # 'icon': 'ti:plus:outline', 

228 # 'options': {'url': '/core/sample-primary-action/', 'color': 'orange'}, 

229 # }) 

230 # return items 

231 

232 # Default implementation returns an empty list 

233 return []