IAM: Add search for teams in app platform (#113503)
* add legacy search (wip) * fix search field name * implement team search endpoint * generate openapi spec * generate endpoints for frontend * minor fixes * fix issues found while testing * add more fields to search result * add basic unit tests * add more unit tests * improve getColumns() func in legacy search * configure search endpoint in team.cue * add team search handler * add the searchTeams endpoint to manifest.cue * make gofmt * update openapi spec * generate frontend endpoints * remove unused field * move fields defiitions to separate builder * fix legacy search * fix unit tests * fix unit test * address feedback * fix unit test * update openapi specs * yarn generate-apis * add missing unit tests
This commit is contained in:
@@ -67,5 +67,10 @@ func All(sql db.DB, sprinkles DashboardStats) ([]resource.DocumentBuilderInfo, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []resource.DocumentBuilderInfo{dashboards, users, extGroupMappings}, nil
|
||||
teams, err := GetTeamSearchBuilder()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []resource.DocumentBuilderInfo{dashboards, users, extGroupMappings, teams}, nil
|
||||
}
|
||||
|
||||
@@ -70,6 +70,18 @@ func TestExternalGroupMappingDocumentBuilder(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTeamSearchBuilder(t *testing.T) {
|
||||
info, err := GetTeamSearchBuilder()
|
||||
require.NoError(t, err)
|
||||
doSnapshotTests(t, info.Builder, "team", &resourcepb.ResourceKey{
|
||||
Namespace: "default",
|
||||
Group: "iam.grafana.app",
|
||||
Resource: "searchTeams",
|
||||
}, []string{
|
||||
"with-email-and-external-uid",
|
||||
})
|
||||
}
|
||||
|
||||
func TestDashboardDocumentBuilder(t *testing.T) {
|
||||
key := &resourcepb.ResourceKey{
|
||||
Namespace: "default",
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
)
|
||||
|
||||
const (
|
||||
TEAM_SEARCH_EMAIL = "email"
|
||||
TEAM_SEARCH_PROVISIONED = "provisioned"
|
||||
TEAM_SEARCH_EXTERNAL_UID = "externalUID"
|
||||
)
|
||||
|
||||
var TeamSearchTableColumnDefinitions = map[string]*resourcepb.ResourceTableColumnDefinition{
|
||||
TEAM_SEARCH_EMAIL: {
|
||||
Name: TEAM_SEARCH_EMAIL,
|
||||
Type: resourcepb.ResourceTableColumnDefinition_STRING,
|
||||
Description: "Email of the team",
|
||||
},
|
||||
TEAM_SEARCH_PROVISIONED: {
|
||||
Name: TEAM_SEARCH_PROVISIONED,
|
||||
Type: resourcepb.ResourceTableColumnDefinition_BOOLEAN,
|
||||
Description: "Whether the team is provisioned",
|
||||
},
|
||||
TEAM_SEARCH_EXTERNAL_UID: {
|
||||
Name: TEAM_SEARCH_EXTERNAL_UID,
|
||||
Type: resourcepb.ResourceTableColumnDefinition_STRING,
|
||||
Description: "External UID of the team",
|
||||
},
|
||||
}
|
||||
|
||||
func GetTeamSearchBuilder() (resource.DocumentBuilderInfo, error) {
|
||||
values := make([]*resourcepb.ResourceTableColumnDefinition, 0, len(TeamSearchTableColumnDefinitions))
|
||||
for _, v := range TeamSearchTableColumnDefinitions {
|
||||
values = append(values, v)
|
||||
}
|
||||
fields, err := resource.NewSearchableDocumentFields(values)
|
||||
|
||||
return resource.DocumentBuilderInfo{
|
||||
GroupResource: schema.GroupResource{
|
||||
Group: "iam.grafana.app",
|
||||
Resource: "searchTeams",
|
||||
},
|
||||
Fields: fields,
|
||||
Builder: new(teamSearchBuilder),
|
||||
}, err
|
||||
}
|
||||
|
||||
var _ resource.DocumentBuilder = new(teamSearchBuilder)
|
||||
|
||||
type teamSearchBuilder struct{}
|
||||
|
||||
func (t *teamSearchBuilder) BuildDocument(ctx context.Context, key *resourcepb.ResourceKey, rv int64, value []byte) (*resource.IndexableDocument, error) {
|
||||
team := &v0alpha1.Team{}
|
||||
err := json.NewDecoder(bytes.NewReader(value)).Decode(team)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj, err := utils.MetaAccessor(team)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
doc := resource.NewIndexableDocument(key, rv, obj)
|
||||
|
||||
doc.Fields = make(map[string]any)
|
||||
if team.Spec.Email != "" {
|
||||
doc.Fields[TEAM_SEARCH_EMAIL] = team.Spec.Email
|
||||
}
|
||||
if team.Spec.Provisioned {
|
||||
doc.Fields[TEAM_SEARCH_PROVISIONED] = team.Spec.Provisioned
|
||||
}
|
||||
if team.Spec.ExternalUID != "" {
|
||||
doc.Fields[TEAM_SEARCH_EXTERNAL_UID] = team.Spec.ExternalUID
|
||||
}
|
||||
|
||||
return doc, nil
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"key": {
|
||||
"namespace": "default",
|
||||
"group": "iam.grafana.app",
|
||||
"resource": "searchTeams",
|
||||
"name": "with-email-and-external-uid"
|
||||
},
|
||||
"name": "with-email-and-external-uid",
|
||||
"rv": 1234,
|
||||
"title": "Team With Email And External UID",
|
||||
"title_ngram": "Team With Email And External UID",
|
||||
"title_phrase": "team with email and external uid",
|
||||
"fields": {
|
||||
"email": "test@example.com",
|
||||
"externalUID": "external-uid",
|
||||
"provisioned": true
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"apiVersion": "iam.grafana.app/v0alpha1",
|
||||
"kind": "Team",
|
||||
"metadata": {
|
||||
"name": "team-with-email-and-external-uid"
|
||||
},
|
||||
"spec": {
|
||||
"title": "Team With Email And External UID",
|
||||
"email": "test@example.com",
|
||||
"provisioned": true,
|
||||
"externalUID": "external-uid"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user