[MM-57418] Implement support for defining plugin settings sections (#27654)
* Implement support for defining plugin settings sections * Implement custom plugin configuration sections * Tests * Update test * Improvements
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c0a7a19294
Коммит
be94c47607
@@ -91,6 +91,29 @@ type PluginSetting struct {
|
||||
Hosting string `json:"hosting"`
|
||||
}
|
||||
|
||||
type PluginSettingsSection struct {
|
||||
// A unique identifier for this section.
|
||||
Key string `json:"key" yaml:"key"`
|
||||
|
||||
// Optional text to display as section title.
|
||||
Title string `json:"title" yaml:"title"`
|
||||
|
||||
// Optional text to display as section subtitle.
|
||||
Subtitle string `json:"subtitle" yaml:"subtitle"`
|
||||
|
||||
// A list of setting definitions to display inside the section.
|
||||
Settings []*PluginSetting `json:"settings" yaml:"settings"`
|
||||
|
||||
// Optional text to display above the settings. Supports Markdown formatting.
|
||||
Header string `json:"header" yaml:"header"`
|
||||
|
||||
// Optional text to display below the settings. Supports Markdown formatting.
|
||||
Footer string `json:"footer" yaml:"footer"`
|
||||
|
||||
// If true, the section will load the custom component registered using `registry.registerAdminConsoleCustomSection`
|
||||
Custom bool `json:"custom" yaml:"custom"`
|
||||
}
|
||||
|
||||
type PluginSettingsSchema struct {
|
||||
// Optional text to display above the settings. Supports Markdown formatting.
|
||||
Header string `json:"header" yaml:"header"`
|
||||
@@ -100,6 +123,9 @@ type PluginSettingsSchema struct {
|
||||
|
||||
// A list of setting definitions.
|
||||
Settings []*PluginSetting `json:"settings" yaml:"settings"`
|
||||
|
||||
// A list of settings section definitions.
|
||||
Sections []*PluginSettingsSection `json:"sections" yaml:"sections"`
|
||||
}
|
||||
|
||||
// The plugin manifest defines the metadata required to load and present your plugin. The manifest
|
||||
@@ -330,6 +356,27 @@ func (s *PluginSettingsSchema) isValid() error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, section := range s.Sections {
|
||||
if err := section.IsValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PluginSettingsSection) IsValid() error {
|
||||
if s.Key == "" {
|
||||
return errors.New("invalid empty Key")
|
||||
}
|
||||
|
||||
for _, setting := range s.Settings {
|
||||
err := setting.isValid()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,37 @@ func TestIsValid(t *testing.T) {
|
||||
Default: "thedefault",
|
||||
},
|
||||
},
|
||||
Sections: []*PluginSettingsSection{
|
||||
{
|
||||
Key: "section1",
|
||||
Title: "section title",
|
||||
Subtitle: "section subtitle",
|
||||
Settings: []*PluginSetting{
|
||||
{
|
||||
Key: "section1setting1",
|
||||
DisplayName: "thedisplayname",
|
||||
Type: "custom",
|
||||
},
|
||||
{
|
||||
Key: "section1setting2",
|
||||
DisplayName: "thedisplayname",
|
||||
Type: "custom",
|
||||
},
|
||||
},
|
||||
Header: "section header",
|
||||
Footer: "section footer",
|
||||
},
|
||||
{
|
||||
Key: "section2",
|
||||
Settings: []*PluginSetting{
|
||||
{
|
||||
Key: "section2setting1",
|
||||
DisplayName: "thedisplayname",
|
||||
Type: "custom",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, false},
|
||||
}
|
||||
@@ -103,6 +134,62 @@ func TestIsValidSettingsSchema(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginSettingsSectionIsValid(t *testing.T) {
|
||||
for name, test := range map[string]struct {
|
||||
Section PluginSettingsSection
|
||||
ExpectedError string
|
||||
}{
|
||||
"missing key": {
|
||||
Section: PluginSettingsSection{
|
||||
Settings: []*PluginSetting{
|
||||
{
|
||||
Type: "custom",
|
||||
Placeholder: "some Text",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedError: "invalid empty Key",
|
||||
},
|
||||
"invalid setting": {
|
||||
Section: PluginSettingsSection{
|
||||
Key: "sectionKey",
|
||||
Settings: []*PluginSetting{
|
||||
{
|
||||
Type: "invalid",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedError: "invalid setting type: invalid",
|
||||
},
|
||||
"valid empty": {
|
||||
Section: PluginSettingsSection{
|
||||
Key: "sectionKey",
|
||||
Settings: []*PluginSetting{},
|
||||
},
|
||||
},
|
||||
"valid": {
|
||||
Section: PluginSettingsSection{
|
||||
Key: "sectionKey",
|
||||
Settings: []*PluginSetting{
|
||||
{
|
||||
Type: "custom",
|
||||
Placeholder: "some Text",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err := test.Section.IsValid()
|
||||
if test.ExpectedError != "" {
|
||||
assert.EqualError(t, err, test.ExpectedError)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingIsValid(t *testing.T) {
|
||||
for name, test := range map[string]struct {
|
||||
Setting PluginSetting
|
||||
|
||||
Ссылка в новой задаче
Block a user