MM-63285: Add property field methods to plugin API (#31035)
Co-authored-by: Claude <noreply@anthropic.com>
Этот коммит содержится в:
@@ -239,3 +239,77 @@ func (p PropertyOptions[T]) IsValid() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PluginPropertyOption provides a simple implementation of PropertyOption for plugins
|
||||
// using a map[string]string for flexible key-value storage
|
||||
type PluginPropertyOption struct {
|
||||
Data map[string]string `json:"data"`
|
||||
}
|
||||
|
||||
func NewPluginPropertyOption(id, name string) *PluginPropertyOption {
|
||||
return &PluginPropertyOption{
|
||||
Data: map[string]string{
|
||||
"id": id,
|
||||
"name": name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PluginPropertyOption) GetID() string {
|
||||
if p.Data == nil {
|
||||
return ""
|
||||
}
|
||||
return p.Data["id"]
|
||||
}
|
||||
|
||||
func (p *PluginPropertyOption) GetName() string {
|
||||
if p.Data == nil {
|
||||
return ""
|
||||
}
|
||||
return p.Data["name"]
|
||||
}
|
||||
|
||||
func (p *PluginPropertyOption) SetID(id string) {
|
||||
if p.Data == nil {
|
||||
p.Data = make(map[string]string)
|
||||
}
|
||||
p.Data["id"] = id
|
||||
}
|
||||
|
||||
func (p *PluginPropertyOption) IsValid() error {
|
||||
if p.Data == nil {
|
||||
return errors.New("data cannot be nil")
|
||||
}
|
||||
|
||||
id := p.GetID()
|
||||
if id == "" {
|
||||
return errors.New("id cannot be empty")
|
||||
}
|
||||
|
||||
if !IsValidId(id) {
|
||||
return errors.New("id is not a valid ID")
|
||||
}
|
||||
|
||||
name := p.GetName()
|
||||
if name == "" {
|
||||
return errors.New("name cannot be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetValue retrieves a custom value from the option data
|
||||
func (p *PluginPropertyOption) GetValue(key string) string {
|
||||
if p.Data == nil {
|
||||
return ""
|
||||
}
|
||||
return p.Data[key]
|
||||
}
|
||||
|
||||
// SetValue sets a custom value in the option data
|
||||
func (p *PluginPropertyOption) SetValue(key, value string) {
|
||||
if p.Data == nil {
|
||||
p.Data = make(map[string]string)
|
||||
}
|
||||
p.Data[key] = value
|
||||
}
|
||||
|
||||
@@ -243,3 +243,138 @@ func TestPropertyFieldSearchCursor_IsValid(t *testing.T) {
|
||||
assert.Error(t, cursor.IsValid())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPluginPropertyOption(t *testing.T) {
|
||||
t.Run("NewPluginPropertyOption", func(t *testing.T) {
|
||||
id := NewId()
|
||||
option := NewPluginPropertyOption(id, "test-name")
|
||||
|
||||
assert.Equal(t, id, option.GetID())
|
||||
assert.Equal(t, "test-name", option.GetName())
|
||||
assert.NoError(t, option.IsValid())
|
||||
})
|
||||
|
||||
t.Run("SetID", func(t *testing.T) {
|
||||
option := &PluginPropertyOption{}
|
||||
newId := NewId()
|
||||
option.SetID(newId)
|
||||
|
||||
assert.Equal(t, newId, option.GetID())
|
||||
})
|
||||
|
||||
t.Run("GetValue and SetValue", func(t *testing.T) {
|
||||
option := NewPluginPropertyOption(NewId(), "test-name")
|
||||
|
||||
option.SetValue("color", "red")
|
||||
option.SetValue("description", "test description")
|
||||
|
||||
assert.Equal(t, "red", option.GetValue("color"))
|
||||
assert.Equal(t, "test description", option.GetValue("description"))
|
||||
assert.Equal(t, "", option.GetValue("nonexistent"))
|
||||
})
|
||||
|
||||
t.Run("IsValid", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
option *PluginPropertyOption
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid option",
|
||||
option: NewPluginPropertyOption(NewId(), "test-name"),
|
||||
},
|
||||
{
|
||||
name: "nil data",
|
||||
option: &PluginPropertyOption{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty id",
|
||||
option: &PluginPropertyOption{
|
||||
Data: map[string]string{"name": "test"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty name",
|
||||
option: &PluginPropertyOption{
|
||||
Data: map[string]string{"id": NewId()},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid id",
|
||||
option: &PluginPropertyOption{
|
||||
Data: map[string]string{
|
||||
"id": "invalid-id-format",
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.option.IsValid()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("PropertyOptions with PluginPropertyOption", func(t *testing.T) {
|
||||
options := PropertyOptions[*PluginPropertyOption]{
|
||||
NewPluginPropertyOption(NewId(), "Option 1"),
|
||||
NewPluginPropertyOption(NewId(), "Option 2"),
|
||||
}
|
||||
|
||||
// Add custom data
|
||||
options[0].SetValue("color", "blue")
|
||||
options[1].SetValue("description", "Second option")
|
||||
|
||||
assert.NoError(t, options.IsValid())
|
||||
assert.Equal(t, "blue", options[0].GetValue("color"))
|
||||
assert.Equal(t, "Second option", options[1].GetValue("description"))
|
||||
})
|
||||
|
||||
t.Run("PropertyField with PluginPropertyOptions", func(t *testing.T) {
|
||||
fieldID := NewId()
|
||||
groupID := NewId()
|
||||
fieldName := "Test Field"
|
||||
fieldType := PropertyFieldTypeSelect
|
||||
|
||||
field := &PropertyField{
|
||||
ID: fieldID,
|
||||
GroupID: groupID,
|
||||
Name: fieldName,
|
||||
Type: fieldType,
|
||||
Attrs: make(StringInterface),
|
||||
}
|
||||
|
||||
options := PropertyOptions[*PluginPropertyOption]{
|
||||
NewPluginPropertyOption(NewId(), "Option 1"),
|
||||
NewPluginPropertyOption(NewId(), "Option 2"),
|
||||
}
|
||||
|
||||
field.Attrs[PropertyFieldAttributeOptions] = options
|
||||
|
||||
// Verify the field properties are set correctly
|
||||
assert.Equal(t, fieldID, field.ID)
|
||||
assert.Equal(t, groupID, field.GroupID)
|
||||
assert.Equal(t, fieldName, field.Name)
|
||||
assert.Equal(t, fieldType, field.Type)
|
||||
|
||||
// Test that we can retrieve the options
|
||||
if optionsFromField, err := NewPropertyOptionsFromFieldAttrs[*PluginPropertyOption](field.Attrs[PropertyFieldAttributeOptions]); err == nil {
|
||||
require.Len(t, optionsFromField, 2)
|
||||
assert.Equal(t, "Option 1", optionsFromField[0].GetName())
|
||||
assert.Equal(t, "Option 2", optionsFromField[1].GetName())
|
||||
} else {
|
||||
t.Fatalf("Failed to retrieve options from field: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user