@@ -94,11 +94,23 @@ class GenerateFileURLResponseModel(BaseModel):
9494 file_url : str = Field (description = "A URL which the file is accessible on." )
9595
9696
97+ class GroupItem (BaseModel ):
98+ name : str
99+ slug : str
100+
101+
97102class GroupedTableNamesResponseModel (BaseModel ):
98103 grouped : t .Dict [str , t .List [str ]] = Field (default_factory = list )
99104 ungrouped : t .List [str ] = Field (default_factory = list )
100105
101106
107+ class GroupedFormsResponseModel (BaseModel ):
108+ grouped : t .Dict [str , t .List [FormConfigResponseModel ]] = Field (
109+ default_factory = list
110+ )
111+ ungrouped : t .List [FormConfigResponseModel ] = Field (default_factory = list )
112+
113+
102114@dataclass
103115class TableConfig :
104116 """
@@ -340,6 +352,10 @@ class FormConfig:
340352 :param description:
341353 An optional description which is shown in the UI to explain to the user
342354 what the form is for.
355+ :param form_group:
356+ If specified, forms can be divided into groups in the form
357+ menu. This is useful when you have many forms that you
358+ can organize into groups for better visibility.
343359
344360 Here's a full example:
345361
@@ -364,7 +380,8 @@ def my_endpoint(request: Request, data: MyModel):
364380 config = FormConfig(
365381 name="My Form",
366382 pydantic_model=MyModel,
367- endpoint=my_endpoint
383+ endpoint=my_endpoint,
384+ form_group="Text forms",
368385 )
369386
370387 """
@@ -378,11 +395,13 @@ def __init__(
378395 t .Union [FormResponse , t .Coroutine [None , None , FormResponse ]],
379396 ],
380397 description : t .Optional [str ] = None ,
398+ form_group : t .Optional [str ] = None ,
381399 ):
382400 self .name = name
383401 self .pydantic_model = pydantic_model
384402 self .endpoint = endpoint
385403 self .description = description
404+ self .form_group = form_group
386405 self .slug = self .name .replace (" " , "-" ).lower ()
387406
388407
@@ -622,6 +641,14 @@ def __init__(
622641 response_model = t .List [FormConfigResponseModel ],
623642 )
624643
644+ private_app .add_api_route (
645+ path = "/forms/grouped/" ,
646+ endpoint = self .get_grouped_forms , # type: ignore
647+ methods = ["GET" ],
648+ response_model = GroupedFormsResponseModel ,
649+ tags = ["Forms" ],
650+ )
651+
625652 private_app .add_api_route (
626653 path = "/forms/{form_slug:str}/" ,
627654 endpoint = self .get_single_form , # type: ignore
@@ -937,6 +964,34 @@ def get_forms(self) -> t.List[FormConfigResponseModel]:
937964 for form in self .forms
938965 ]
939966
967+ def get_grouped_forms (self ) -> GroupedFormsResponseModel :
968+ """
969+ Returns a list of custom forms registered with the admin, grouped using
970+ `form_group`.
971+ """
972+ response = GroupedFormsResponseModel ()
973+ group_names = sorted (
974+ {
975+ v .form_group
976+ for _ , v in self .form_config_map .items ()
977+ if v .form_group
978+ }
979+ )
980+ response .grouped = {i : [] for i in group_names }
981+ for _ , form_config in self .form_config_map .items ():
982+ form_group = form_config .form_group
983+ form_config_response = FormConfigResponseModel (
984+ name = form_config .name ,
985+ slug = form_config .slug ,
986+ description = form_config .description ,
987+ )
988+ if form_group is None :
989+ response .ungrouped .append (form_config_response )
990+ else :
991+ response .grouped [form_group ].append (form_config_response )
992+
993+ return response
994+
940995 def get_single_form (self , form_slug : str ) -> FormConfigResponseModel :
941996 """
942997 Returns the FormConfig for the given form.
0 commit comments