mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-30 22:11:07 +00:00 
			
		
		
		
	Support setting the default attribute of the issue template dropdown field (#31045)
		
	Fix #31044 According to [GitHub issue template documentation](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-for-dropdown), the `default` attribute can be used to specify the preselected option for a dropdown field. (cherry picked from commit 7ab0988af140aa3e0204979765f75961f1dc9c11)
This commit is contained in:
		
					parent
					
						
							
								d6e454c320
							
						
					
				
			
			
				commit
				
					
						df15abd072
					
				
			
		
					 3 changed files with 118 additions and 1 deletions
				
			
		|  | @ -91,6 +91,9 @@ func validateYaml(template *api.IssueTemplate) error { | |||
| 			if err := validateOptions(field, idx); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err := validateDropdownDefault(position, field.Attributes); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		case api.IssueFormFieldTypeCheckboxes: | ||||
| 			if err := validateStringItem(position, field.Attributes, false, "description"); err != nil { | ||||
| 				return err | ||||
|  | @ -249,6 +252,28 @@ func validateBoolItem(position errorPosition, m map[string]any, names ...string) | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func validateDropdownDefault(position errorPosition, attributes map[string]any) error { | ||||
| 	v, ok := attributes["default"] | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	defaultValue, ok := v.(int) | ||||
| 	if !ok { | ||||
| 		return position.Errorf("'default' should be an int") | ||||
| 	} | ||||
| 
 | ||||
| 	options, ok := attributes["options"].([]any) | ||||
| 	if !ok { | ||||
| 		// should not happen | ||||
| 		return position.Errorf("'options' is required and should be a array") | ||||
| 	} | ||||
| 	if defaultValue < 0 || defaultValue >= len(options) { | ||||
| 		return position.Errorf("the value of 'default' is out of range") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type errorPosition string | ||||
| 
 | ||||
| func (p errorPosition) Errorf(format string, a ...any) error { | ||||
|  |  | |||
|  | @ -355,6 +355,96 @@ body: | |||
| `, | ||||
| 			wantErr: "body[0](checkboxes), option[1]: can not require a hidden checkbox", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "dropdown default is not an integer", | ||||
| 			content: ` | ||||
| name: "test" | ||||
| about: "this is about" | ||||
| body: | ||||
|   - type: dropdown | ||||
|     id: "1" | ||||
|     attributes: | ||||
|       label: Label of dropdown | ||||
|       description: Description of dropdown | ||||
|       multiple: true | ||||
|       options: | ||||
|         - Option 1 of dropdown | ||||
|         - Option 2 of dropdown | ||||
|         - Option 3 of dropdown | ||||
|       default: "def" | ||||
|     validations: | ||||
|       required: true | ||||
| `, | ||||
| 			wantErr: "body[0](dropdown): 'default' should be an int", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "dropdown default is out of range", | ||||
| 			content: ` | ||||
| name: "test" | ||||
| about: "this is about" | ||||
| body: | ||||
|   - type: dropdown | ||||
|     id: "1" | ||||
|     attributes: | ||||
|       label: Label of dropdown | ||||
|       description: Description of dropdown | ||||
|       multiple: true | ||||
|       options: | ||||
|         - Option 1 of dropdown | ||||
|         - Option 2 of dropdown | ||||
|         - Option 3 of dropdown | ||||
|       default: 3 | ||||
|     validations: | ||||
|       required: true | ||||
| `, | ||||
| 			wantErr: "body[0](dropdown): the value of 'default' is out of range", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "dropdown without default is valid", | ||||
| 			content: ` | ||||
| name: "test" | ||||
| about: "this is about" | ||||
| body: | ||||
|   - type: dropdown | ||||
|     id: "1" | ||||
|     attributes: | ||||
|       label: Label of dropdown | ||||
|       description: Description of dropdown | ||||
|       multiple: true | ||||
|       options: | ||||
|         - Option 1 of dropdown | ||||
|         - Option 2 of dropdown | ||||
|         - Option 3 of dropdown | ||||
|     validations: | ||||
|       required: true | ||||
| `, | ||||
| 			want: &api.IssueTemplate{ | ||||
| 				Name:  "test", | ||||
| 				About: "this is about", | ||||
| 				Fields: []*api.IssueFormField{ | ||||
| 					{ | ||||
| 						Type: "dropdown", | ||||
| 						ID:   "1", | ||||
| 						Attributes: map[string]any{ | ||||
| 							"label":       "Label of dropdown", | ||||
| 							"description": "Description of dropdown", | ||||
| 							"multiple":    true, | ||||
| 							"options": []any{ | ||||
| 								"Option 1 of dropdown", | ||||
| 								"Option 2 of dropdown", | ||||
| 								"Option 3 of dropdown", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Validations: map[string]any{ | ||||
| 							"required": true, | ||||
| 						}, | ||||
| 						Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				FileName: "test.yaml", | ||||
| 			}, | ||||
| 			wantErr: "", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "valid", | ||||
| 			content: ` | ||||
|  | @ -399,6 +489,7 @@ body: | |||
|         - Option 1 of dropdown | ||||
|         - Option 2 of dropdown | ||||
|         - Option 3 of dropdown | ||||
|       default: 1 | ||||
|     validations: | ||||
|       required: true | ||||
|   - type: checkboxes | ||||
|  | @ -475,6 +566,7 @@ body: | |||
| 								"Option 2 of dropdown", | ||||
| 								"Option 3 of dropdown", | ||||
| 							}, | ||||
| 							"default": 1, | ||||
| 						}, | ||||
| 						Validations: map[string]any{ | ||||
| 							"required": true, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue