MM-63285: Add property field methods to plugin API (#31035)

Co-authored-by: Claude <noreply@anthropic.com>
Этот коммит содержится в:
Julien Tant
2025-06-10 16:10:28 -07:00
коммит произвёл GitHub
родитель 81856f9e7d
Коммит 731bd7c414
13 изменённых файлов: 2675 добавлений и 0 удалений

Просмотреть файл

@@ -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)
}
})
}