diff --git a/graphql2/generated.go b/graphql2/generated.go index db25f0d63c..6aec523cae 100644 --- a/graphql2/generated.go +++ b/graphql2/generated.go @@ -68,6 +68,7 @@ type ResolverRoot interface { AlertMetric() AlertMetricResolver EscalationPolicy() EscalationPolicyResolver EscalationPolicyStep() EscalationPolicyStepResolver + FieldValuePair() FieldValuePairResolver GQLAPIKey() GQLAPIKeyResolver HeartbeatMonitor() HeartbeatMonitorResolver IntegrationKey() IntegrationKeyResolver @@ -279,9 +280,16 @@ type ComplexityRoot struct { Targets func(childComplexity int) int } + FieldValueConnection struct { + Nodes func(childComplexity int) int + PageInfo func(childComplexity int) int + } + FieldValuePair struct { - FieldID func(childComplexity int) int - Value func(childComplexity int) int + FieldID func(childComplexity int) int + IsFavorite func(childComplexity int) int + Label func(childComplexity int) int + Value func(childComplexity int) int } GQLAPIKey struct { @@ -457,51 +465,53 @@ type ComplexityRoot struct { } Query struct { - Alert func(childComplexity int, id int) int - Alerts func(childComplexity int, input *AlertSearchOptions) int - AuthSubjectsForProvider func(childComplexity int, first *int, after *string, providerID string) int - CalcRotationHandoffTimes func(childComplexity int, input *CalcRotationHandoffTimesInput) int - Config func(childComplexity int, all *bool) int - ConfigHints func(childComplexity int) int - DebugMessageStatus func(childComplexity int, input DebugMessageStatusInput) int - DebugMessages func(childComplexity int, input *DebugMessagesInput) int - DestinationDisplayInfo func(childComplexity int, input DestinationInput) int - DestinationFieldValidate func(childComplexity int, input DestinationFieldValidateInput) int - DestinationTypes func(childComplexity int) int - EscalationPolicies func(childComplexity int, input *EscalationPolicySearchOptions) int - EscalationPolicy func(childComplexity int, id string) int - ExperimentalFlags func(childComplexity int) int - GenerateSlackAppManifest func(childComplexity int) int - GqlAPIKeys func(childComplexity int) int - HeartbeatMonitor func(childComplexity int, id string) int - IntegrationKey func(childComplexity int, id string) int - IntegrationKeyTypes func(childComplexity int) int - IntegrationKeys func(childComplexity int, input *IntegrationKeySearchOptions) int - LabelKeys func(childComplexity int, input *LabelKeySearchOptions) int - LabelValues func(childComplexity int, input *LabelValueSearchOptions) int - Labels func(childComplexity int, input *LabelSearchOptions) int - LinkAccountInfo func(childComplexity int, token string) int - MessageLogs func(childComplexity int, input *MessageLogSearchOptions) int - PhoneNumberInfo func(childComplexity int, number string) int - Rotation func(childComplexity int, id string) int - Rotations func(childComplexity int, input *RotationSearchOptions) int - Schedule func(childComplexity int, id string) int - Schedules func(childComplexity int, input *ScheduleSearchOptions) int - Service func(childComplexity int, id string) int - Services func(childComplexity int, input *ServiceSearchOptions) int - SlackChannel func(childComplexity int, id string) int - SlackChannels func(childComplexity int, input *SlackChannelSearchOptions) int - SlackUserGroup func(childComplexity int, id string) int - SlackUserGroups func(childComplexity int, input *SlackUserGroupSearchOptions) int - SwoStatus func(childComplexity int) int - SystemLimits func(childComplexity int) int - TimeZones func(childComplexity int, input *TimeZoneSearchOptions) int - User func(childComplexity int, id *string) int - UserCalendarSubscription func(childComplexity int, id string) int - UserContactMethod func(childComplexity int, id string) int - UserOverride func(childComplexity int, id string) int - UserOverrides func(childComplexity int, input *UserOverrideSearchOptions) int - Users func(childComplexity int, input *UserSearchOptions, first *int, after *string, search *string) int + Alert func(childComplexity int, id int) int + Alerts func(childComplexity int, input *AlertSearchOptions) int + AuthSubjectsForProvider func(childComplexity int, first *int, after *string, providerID string) int + CalcRotationHandoffTimes func(childComplexity int, input *CalcRotationHandoffTimesInput) int + Config func(childComplexity int, all *bool) int + ConfigHints func(childComplexity int) int + DebugMessageStatus func(childComplexity int, input DebugMessageStatusInput) int + DebugMessages func(childComplexity int, input *DebugMessagesInput) int + DestinationDisplayInfo func(childComplexity int, input DestinationInput) int + DestinationFieldSearch func(childComplexity int, input DestinationFieldSearchInput) int + DestinationFieldValidate func(childComplexity int, input DestinationFieldValidateInput) int + DestinationFieldValueName func(childComplexity int, input DestinationFieldValidateInput) int + DestinationTypes func(childComplexity int) int + EscalationPolicies func(childComplexity int, input *EscalationPolicySearchOptions) int + EscalationPolicy func(childComplexity int, id string) int + ExperimentalFlags func(childComplexity int) int + GenerateSlackAppManifest func(childComplexity int) int + GqlAPIKeys func(childComplexity int) int + HeartbeatMonitor func(childComplexity int, id string) int + IntegrationKey func(childComplexity int, id string) int + IntegrationKeyTypes func(childComplexity int) int + IntegrationKeys func(childComplexity int, input *IntegrationKeySearchOptions) int + LabelKeys func(childComplexity int, input *LabelKeySearchOptions) int + LabelValues func(childComplexity int, input *LabelValueSearchOptions) int + Labels func(childComplexity int, input *LabelSearchOptions) int + LinkAccountInfo func(childComplexity int, token string) int + MessageLogs func(childComplexity int, input *MessageLogSearchOptions) int + PhoneNumberInfo func(childComplexity int, number string) int + Rotation func(childComplexity int, id string) int + Rotations func(childComplexity int, input *RotationSearchOptions) int + Schedule func(childComplexity int, id string) int + Schedules func(childComplexity int, input *ScheduleSearchOptions) int + Service func(childComplexity int, id string) int + Services func(childComplexity int, input *ServiceSearchOptions) int + SlackChannel func(childComplexity int, id string) int + SlackChannels func(childComplexity int, input *SlackChannelSearchOptions) int + SlackUserGroup func(childComplexity int, id string) int + SlackUserGroups func(childComplexity int, input *SlackUserGroupSearchOptions) int + SwoStatus func(childComplexity int) int + SystemLimits func(childComplexity int) int + TimeZones func(childComplexity int, input *TimeZoneSearchOptions) int + User func(childComplexity int, id *string) int + UserCalendarSubscription func(childComplexity int, id string) int + UserContactMethod func(childComplexity int, id string) int + UserOverride func(childComplexity int, id string) int + UserOverrides func(childComplexity int, input *UserOverrideSearchOptions) int + Users func(childComplexity int, input *UserSearchOptions, first *int, after *string, search *string) int } Rotation struct { @@ -779,6 +789,9 @@ type EscalationPolicyStepResolver interface { Targets(ctx context.Context, obj *escalation.Step) ([]assignment.RawTarget, error) EscalationPolicy(ctx context.Context, obj *escalation.Step) (*escalation.Policy, error) } +type FieldValuePairResolver interface { + Label(ctx context.Context, obj *FieldValuePair) (string, error) +} type GQLAPIKeyResolver interface { CreatedBy(ctx context.Context, obj *GQLAPIKey) (*user.User, error) @@ -901,6 +914,8 @@ type QueryResolver interface { SwoStatus(ctx context.Context) (*SWOStatus, error) DestinationTypes(ctx context.Context) ([]DestinationTypeInfo, error) DestinationFieldValidate(ctx context.Context, input DestinationFieldValidateInput) (bool, error) + DestinationFieldSearch(ctx context.Context, input DestinationFieldSearchInput) (*FieldValueConnection, error) + DestinationFieldValueName(ctx context.Context, input DestinationFieldValidateInput) (string, error) DestinationDisplayInfo(ctx context.Context, input DestinationInput) (*DestinationDisplayInfo, error) GqlAPIKeys(ctx context.Context) ([]GQLAPIKey, error) } @@ -1796,6 +1811,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.EscalationPolicyStep.Targets(childComplexity), true + case "FieldValueConnection.nodes": + if e.complexity.FieldValueConnection.Nodes == nil { + break + } + + return e.complexity.FieldValueConnection.Nodes(childComplexity), true + + case "FieldValueConnection.pageInfo": + if e.complexity.FieldValueConnection.PageInfo == nil { + break + } + + return e.complexity.FieldValueConnection.PageInfo(childComplexity), true + case "FieldValuePair.fieldID": if e.complexity.FieldValuePair.FieldID == nil { break @@ -1803,6 +1832,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.FieldValuePair.FieldID(childComplexity), true + case "FieldValuePair.isFavorite": + if e.complexity.FieldValuePair.IsFavorite == nil { + break + } + + return e.complexity.FieldValuePair.IsFavorite(childComplexity), true + + case "FieldValuePair.label": + if e.complexity.FieldValuePair.Label == nil { + break + } + + return e.complexity.FieldValuePair.Label(childComplexity), true + case "FieldValuePair.value": if e.complexity.FieldValuePair.Value == nil { break @@ -2999,6 +3042,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.DestinationDisplayInfo(childComplexity, args["input"].(DestinationInput)), true + case "Query.destinationFieldSearch": + if e.complexity.Query.DestinationFieldSearch == nil { + break + } + + args, err := ec.field_Query_destinationFieldSearch_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.DestinationFieldSearch(childComplexity, args["input"].(DestinationFieldSearchInput)), true + case "Query.destinationFieldValidate": if e.complexity.Query.DestinationFieldValidate == nil { break @@ -3011,6 +3066,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.DestinationFieldValidate(childComplexity, args["input"].(DestinationFieldValidateInput)), true + case "Query.destinationFieldValueName": + if e.complexity.Query.DestinationFieldValueName == nil { + break + } + + args, err := ec.field_Query_destinationFieldValueName_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.DestinationFieldValueName(childComplexity, args["input"].(DestinationFieldValidateInput)), true + case "Query.destinationTypes": if e.complexity.Query.DestinationTypes == nil { break @@ -4503,6 +4570,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputDebugMessageStatusInput, ec.unmarshalInputDebugMessagesInput, ec.unmarshalInputDebugSendSMSInput, + ec.unmarshalInputDestinationFieldSearchInput, ec.unmarshalInputDestinationFieldValidateInput, ec.unmarshalInputDestinationInput, ec.unmarshalInputEscalationPolicySearchOptions, @@ -5632,6 +5700,21 @@ func (ec *executionContext) field_Query_destinationDisplayInfo_args(ctx context. return args, nil } +func (ec *executionContext) field_Query_destinationFieldSearch_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 DestinationFieldSearchInput + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg0, err = ec.unmarshalNDestinationFieldSearchInput2githubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐDestinationFieldSearchInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_destinationFieldValidate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -5647,6 +5730,21 @@ func (ec *executionContext) field_Query_destinationFieldValidate_args(ctx contex return args, nil } +func (ec *executionContext) field_Query_destinationFieldValueName_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 DestinationFieldValidateInput + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg0, err = ec.unmarshalNDestinationFieldValidateInput2githubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐDestinationFieldValidateInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_escalationPolicies_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -9424,6 +9522,10 @@ func (ec *executionContext) fieldContext_Destination_values(ctx context.Context, return ec.fieldContext_FieldValuePair_fieldID(ctx, field) case "value": return ec.fieldContext_FieldValuePair_value(ctx, field) + case "label": + return ec.fieldContext_FieldValuePair_label(ctx, field) + case "isFavorite": + return ec.fieldContext_FieldValuePair_isFavorite(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type FieldValuePair", field.Name) }, @@ -11410,6 +11512,110 @@ func (ec *executionContext) fieldContext_EscalationPolicyStep_escalationPolicy(c return fc, nil } +func (ec *executionContext) _FieldValueConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *FieldValueConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FieldValueConnection_nodes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Nodes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]FieldValuePair) + fc.Result = res + return ec.marshalNFieldValuePair2ᚕgithubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐFieldValuePairᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FieldValueConnection_nodes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FieldValueConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "fieldID": + return ec.fieldContext_FieldValuePair_fieldID(ctx, field) + case "value": + return ec.fieldContext_FieldValuePair_value(ctx, field) + case "label": + return ec.fieldContext_FieldValuePair_label(ctx, field) + case "isFavorite": + return ec.fieldContext_FieldValuePair_isFavorite(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FieldValuePair", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _FieldValueConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *FieldValueConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FieldValueConnection_pageInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*PageInfo) + fc.Result = res + return ec.marshalNPageInfo2ᚖgithubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FieldValueConnection_pageInfo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FieldValueConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _FieldValuePair_fieldID(ctx context.Context, field graphql.CollectedField, obj *FieldValuePair) (ret graphql.Marshaler) { fc, err := ec.fieldContext_FieldValuePair_fieldID(ctx, field) if err != nil { @@ -11498,8 +11704,8 @@ func (ec *executionContext) fieldContext_FieldValuePair_value(ctx context.Contex return fc, nil } -func (ec *executionContext) _GQLAPIKey_id(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_id(ctx, field) +func (ec *executionContext) _FieldValuePair_label(ctx context.Context, field graphql.CollectedField, obj *FieldValuePair) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FieldValuePair_label(ctx, field) if err != nil { return graphql.Null } @@ -11512,7 +11718,7 @@ func (ec *executionContext) _GQLAPIKey_id(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.ID, nil + return ec.resolvers.FieldValuePair().Label(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -11526,24 +11732,24 @@ func (ec *executionContext) _GQLAPIKey_id(ctx context.Context, field graphql.Col } res := resTmp.(string) fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_FieldValuePair_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "GQLAPIKey", + Object: "FieldValuePair", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _GQLAPIKey_name(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_name(ctx, field) +func (ec *executionContext) _FieldValuePair_isFavorite(ctx context.Context, field graphql.CollectedField, obj *FieldValuePair) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FieldValuePair_isFavorite(ctx, field) if err != nil { return graphql.Null } @@ -11556,7 +11762,7 @@ func (ec *executionContext) _GQLAPIKey_name(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Name, nil + return obj.IsFavorite, nil }) if err != nil { ec.Error(ctx, err) @@ -11568,26 +11774,26 @@ func (ec *executionContext) _GQLAPIKey_name(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.(string) + res := resTmp.(bool) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_FieldValuePair_isFavorite(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "GQLAPIKey", + Object: "FieldValuePair", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } -func (ec *executionContext) _GQLAPIKey_description(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_description(ctx, field) +func (ec *executionContext) _GQLAPIKey_id(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_id(ctx, field) if err != nil { return graphql.Null } @@ -11600,7 +11806,7 @@ func (ec *executionContext) _GQLAPIKey_description(ctx context.Context, field gr }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Description, nil + return obj.ID, nil }) if err != nil { ec.Error(ctx, err) @@ -11614,24 +11820,24 @@ func (ec *executionContext) _GQLAPIKey_description(ctx context.Context, field gr } res := resTmp.(string) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GQLAPIKey_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GQLAPIKey", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } -func (ec *executionContext) _GQLAPIKey_createdAt(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_createdAt(ctx, field) +func (ec *executionContext) _GQLAPIKey_name(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_name(ctx, field) if err != nil { return graphql.Null } @@ -11644,7 +11850,7 @@ func (ec *executionContext) _GQLAPIKey_createdAt(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.CreatedAt, nil + return obj.Name, nil }) if err != nil { ec.Error(ctx, err) @@ -11656,26 +11862,26 @@ func (ec *executionContext) _GQLAPIKey_createdAt(ctx context.Context, field grap } return graphql.Null } - res := resTmp.(time.Time) + res := resTmp.(string) fc.Result = res - return ec.marshalNISOTimestamp2timeᚐTime(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GQLAPIKey_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GQLAPIKey", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ISOTimestamp does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _GQLAPIKey_createdBy(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_createdBy(ctx, field) +func (ec *executionContext) _GQLAPIKey_description(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_description(ctx, field) if err != nil { return graphql.Null } @@ -11688,63 +11894,38 @@ func (ec *executionContext) _GQLAPIKey_createdBy(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.GQLAPIKey().CreatedBy(rctx, obj) + return obj.Description, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*user.User) + res := resTmp.(string) fc.Result = res - return ec.marshalOUser2ᚖgithubᚗcomᚋtargetᚋgoalertᚋuserᚐUser(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_createdBy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GQLAPIKey_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GQLAPIKey", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "role": - return ec.fieldContext_User_role(ctx, field) - case "name": - return ec.fieldContext_User_name(ctx, field) - case "email": - return ec.fieldContext_User_email(ctx, field) - case "contactMethods": - return ec.fieldContext_User_contactMethods(ctx, field) - case "notificationRules": - return ec.fieldContext_User_notificationRules(ctx, field) - case "calendarSubscriptions": - return ec.fieldContext_User_calendarSubscriptions(ctx, field) - case "statusUpdateContactMethodID": - return ec.fieldContext_User_statusUpdateContactMethodID(ctx, field) - case "authSubjects": - return ec.fieldContext_User_authSubjects(ctx, field) - case "sessions": - return ec.fieldContext_User_sessions(ctx, field) - case "onCallSteps": - return ec.fieldContext_User_onCallSteps(ctx, field) - case "isFavorite": - return ec.fieldContext_User_isFavorite(ctx, field) - case "assignedSchedules": - return ec.fieldContext_User_assignedSchedules(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _GQLAPIKey_updatedAt(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_updatedAt(ctx, field) +func (ec *executionContext) _GQLAPIKey_createdAt(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_createdAt(ctx, field) if err != nil { return graphql.Null } @@ -11757,7 +11938,7 @@ func (ec *executionContext) _GQLAPIKey_updatedAt(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.UpdatedAt, nil + return obj.CreatedAt, nil }) if err != nil { ec.Error(ctx, err) @@ -11774,7 +11955,7 @@ func (ec *executionContext) _GQLAPIKey_updatedAt(ctx context.Context, field grap return ec.marshalNISOTimestamp2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_updatedAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GQLAPIKey_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GQLAPIKey", Field: field, @@ -11787,8 +11968,8 @@ func (ec *executionContext) fieldContext_GQLAPIKey_updatedAt(ctx context.Context return fc, nil } -func (ec *executionContext) _GQLAPIKey_updatedBy(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_GQLAPIKey_updatedBy(ctx, field) +func (ec *executionContext) _GQLAPIKey_createdBy(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_createdBy(ctx, field) if err != nil { return graphql.Null } @@ -11801,7 +11982,7 @@ func (ec *executionContext) _GQLAPIKey_updatedBy(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.GQLAPIKey().UpdatedBy(rctx, obj) + return ec.resolvers.GQLAPIKey().CreatedBy(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -11815,7 +11996,120 @@ func (ec *executionContext) _GQLAPIKey_updatedBy(ctx context.Context, field grap return ec.marshalOUser2ᚖgithubᚗcomᚋtargetᚋgoalertᚋuserᚐUser(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GQLAPIKey_updatedBy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GQLAPIKey_createdBy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "GQLAPIKey", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "role": + return ec.fieldContext_User_role(ctx, field) + case "name": + return ec.fieldContext_User_name(ctx, field) + case "email": + return ec.fieldContext_User_email(ctx, field) + case "contactMethods": + return ec.fieldContext_User_contactMethods(ctx, field) + case "notificationRules": + return ec.fieldContext_User_notificationRules(ctx, field) + case "calendarSubscriptions": + return ec.fieldContext_User_calendarSubscriptions(ctx, field) + case "statusUpdateContactMethodID": + return ec.fieldContext_User_statusUpdateContactMethodID(ctx, field) + case "authSubjects": + return ec.fieldContext_User_authSubjects(ctx, field) + case "sessions": + return ec.fieldContext_User_sessions(ctx, field) + case "onCallSteps": + return ec.fieldContext_User_onCallSteps(ctx, field) + case "isFavorite": + return ec.fieldContext_User_isFavorite(ctx, field) + case "assignedSchedules": + return ec.fieldContext_User_assignedSchedules(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _GQLAPIKey_updatedAt(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_updatedAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.UpdatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNISOTimestamp2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_GQLAPIKey_updatedAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "GQLAPIKey", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ISOTimestamp does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _GQLAPIKey_updatedBy(ctx context.Context, field graphql.CollectedField, obj *GQLAPIKey) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_GQLAPIKey_updatedBy(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.GQLAPIKey().UpdatedBy(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*user.User) + fc.Result = res + return ec.marshalOUser2ᚖgithubᚗcomᚋtargetᚋgoalertᚋuserᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_GQLAPIKey_updatedBy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GQLAPIKey", Field: field, @@ -20485,6 +20779,122 @@ func (ec *executionContext) fieldContext_Query_destinationFieldValidate(ctx cont return fc, nil } +func (ec *executionContext) _Query_destinationFieldSearch(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_destinationFieldSearch(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().DestinationFieldSearch(rctx, fc.Args["input"].(DestinationFieldSearchInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*FieldValueConnection) + fc.Result = res + return ec.marshalNFieldValueConnection2ᚖgithubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐFieldValueConnection(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_destinationFieldSearch(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "nodes": + return ec.fieldContext_FieldValueConnection_nodes(ctx, field) + case "pageInfo": + return ec.fieldContext_FieldValueConnection_pageInfo(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FieldValueConnection", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_destinationFieldSearch_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_destinationFieldValueName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_destinationFieldValueName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().DestinationFieldValueName(rctx, fc.Args["input"].(DestinationFieldValidateInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_destinationFieldValueName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_destinationFieldValueName_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Query_destinationDisplayInfo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_destinationDisplayInfo(ctx, field) if err != nil { @@ -31242,6 +31652,72 @@ func (ec *executionContext) unmarshalInputDebugSendSMSInput(ctx context.Context, return it, nil } +func (ec *executionContext) unmarshalInputDestinationFieldSearchInput(ctx context.Context, obj interface{}) (DestinationFieldSearchInput, error) { + var it DestinationFieldSearchInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + if _, present := asMap["first"]; !present { + asMap["first"] = 15 + } + + fieldsInOrder := [...]string{"destType", "fieldID", "search", "omit", "after", "first"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "destType": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("destType")) + data, err := ec.unmarshalNDestinationType2string(ctx, v) + if err != nil { + return it, err + } + it.DestType = data + case "fieldID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fieldID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.FieldID = data + case "search": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("search")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Search = data + case "omit": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("omit")) + data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + it.Omit = data + case "after": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.After = data + case "first": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.First = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDestinationFieldValidateInput(ctx context.Context, obj interface{}) (DestinationFieldValidateInput, error) { var it DestinationFieldValidateInput asMap := map[string]interface{}{} @@ -35340,212 +35816,297 @@ func (ec *executionContext) _EscalationPolicy(ctx context.Context, sel ast.Selec } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - -var escalationPolicyConnectionImplementors = []string{"EscalationPolicyConnection"} - -func (ec *executionContext) _EscalationPolicyConnection(ctx context.Context, sel ast.SelectionSet, obj *EscalationPolicyConnection) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, escalationPolicyConnectionImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("EscalationPolicyConnection") - case "nodes": - out.Values[i] = ec._EscalationPolicyConnection_nodes(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "pageInfo": - out.Values[i] = ec._EscalationPolicyConnection_pageInfo(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - -var escalationPolicyStepImplementors = []string{"EscalationPolicyStep"} - -func (ec *executionContext) _EscalationPolicyStep(ctx context.Context, sel ast.SelectionSet, obj *escalation.Step) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, escalationPolicyStepImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("EscalationPolicyStep") - case "id": - out.Values[i] = ec._EscalationPolicyStep_id(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } - case "stepNumber": - out.Values[i] = ec._EscalationPolicyStep_stepNumber(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } - case "delayMinutes": - out.Values[i] = ec._EscalationPolicyStep_delayMinutes(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var escalationPolicyConnectionImplementors = []string{"EscalationPolicyConnection"} + +func (ec *executionContext) _EscalationPolicyConnection(ctx context.Context, sel ast.SelectionSet, obj *EscalationPolicyConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, escalationPolicyConnectionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("EscalationPolicyConnection") + case "nodes": + out.Values[i] = ec._EscalationPolicyConnection_nodes(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "pageInfo": + out.Values[i] = ec._EscalationPolicyConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var escalationPolicyStepImplementors = []string{"EscalationPolicyStep"} + +func (ec *executionContext) _EscalationPolicyStep(ctx context.Context, sel ast.SelectionSet, obj *escalation.Step) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, escalationPolicyStepImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("EscalationPolicyStep") + case "id": + out.Values[i] = ec._EscalationPolicyStep_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "stepNumber": + out.Values[i] = ec._EscalationPolicyStep_stepNumber(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "delayMinutes": + out.Values[i] = ec._EscalationPolicyStep_delayMinutes(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "targets": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._EscalationPolicyStep_targets(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "escalationPolicy": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._EscalationPolicyStep_escalationPolicy(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var fieldValueConnectionImplementors = []string{"FieldValueConnection"} + +func (ec *executionContext) _FieldValueConnection(ctx context.Context, sel ast.SelectionSet, obj *FieldValueConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, fieldValueConnectionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("FieldValueConnection") + case "nodes": + out.Values[i] = ec._FieldValueConnection_nodes(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "pageInfo": + out.Values[i] = ec._FieldValueConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var fieldValuePairImplementors = []string{"FieldValuePair"} + +func (ec *executionContext) _FieldValuePair(ctx context.Context, sel ast.SelectionSet, obj *FieldValuePair) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, fieldValuePairImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("FieldValuePair") + case "fieldID": + out.Values[i] = ec._FieldValuePair_fieldID(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "value": + out.Values[i] = ec._FieldValuePair_value(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "label": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._FieldValuePair_label(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "isFavorite": + out.Values[i] = ec._FieldValuePair_isFavorite(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } - case "targets": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._EscalationPolicyStep_targets(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - case "escalationPolicy": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._EscalationPolicyStep_escalationPolicy(ctx, field, obj) - return res - } - - if field.Deferrable != nil { - dfs, ok := deferred[field.Deferrable.Label] - di := 0 - if ok { - dfs.AddField(field) - di = len(dfs.Values) - 1 - } else { - dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) - deferred[field.Deferrable.Label] = dfs - } - dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { - return innerFunc(ctx, dfs) - }) - - // don't run the out.Concurrently() call below - out.Values[i] = graphql.Null - continue - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - -var fieldValuePairImplementors = []string{"FieldValuePair"} - -func (ec *executionContext) _FieldValuePair(ctx context.Context, sel ast.SelectionSet, obj *FieldValuePair) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, fieldValuePairImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("FieldValuePair") - case "fieldID": - out.Values[i] = ec._FieldValuePair_fieldID(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "value": - out.Values[i] = ec._FieldValuePair_value(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -38003,6 +38564,50 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "destinationFieldSearch": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_destinationFieldSearch(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "destinationFieldValueName": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_destinationFieldValueName(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "destinationDisplayInfo": field := field @@ -42253,6 +42858,11 @@ func (ec *executionContext) marshalNDestinationFieldConfig2ᚕgithubᚗcomᚋtar return ret } +func (ec *executionContext) unmarshalNDestinationFieldSearchInput2githubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐDestinationFieldSearchInput(ctx context.Context, v interface{}) (DestinationFieldSearchInput, error) { + res, err := ec.unmarshalInputDestinationFieldSearchInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNDestinationFieldValidateInput2githubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐDestinationFieldValidateInput(ctx context.Context, v interface{}) (DestinationFieldValidateInput, error) { res, err := ec.unmarshalInputDestinationFieldValidateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -42446,6 +43056,20 @@ func (ec *executionContext) marshalNEscalationPolicyStep2ᚕgithubᚗcomᚋtarge return ret } +func (ec *executionContext) marshalNFieldValueConnection2githubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐFieldValueConnection(ctx context.Context, sel ast.SelectionSet, v FieldValueConnection) graphql.Marshaler { + return ec._FieldValueConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNFieldValueConnection2ᚖgithubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐFieldValueConnection(ctx context.Context, sel ast.SelectionSet, v *FieldValueConnection) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._FieldValueConnection(ctx, sel, v) +} + func (ec *executionContext) unmarshalNFieldValueInput2githubᚗcomᚋtargetᚋgoalertᚋgraphql2ᚐFieldValueInput(ctx context.Context, v interface{}) (FieldValueInput, error) { res, err := ec.unmarshalInputFieldValueInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) diff --git a/graphql2/graph/destinations.graphqls b/graphql2/graph/destinations.graphqls index 5e845b28eb..782c5a291b 100644 --- a/graphql2/graph/destinations.graphqls +++ b/graphql2/graph/destinations.graphqls @@ -1,20 +1,25 @@ extend type Query { - # destinationTypes returns a list of destination types that can be used for # notifications. destinationTypes: [DestinationTypeInfo!]! @experimental(flagName: "dest-types") - # destinationFieldValidate validates a destination field value as valid or invalid. # # It does not guarantee that the value is valid for the destination type, only # that it is valid for the field (i.e., syntax/formatting). destinationFieldValidate(input: DestinationFieldValidateInput!): Boolean! @experimental(flagName: "dest-types") - + destinationFieldSearch(input: DestinationFieldSearchInput!): FieldValueConnection! + destinationFieldValueName(input: DestinationFieldValidateInput!): String! # destinationDisplayInfo returns the display information for a destination. destinationDisplayInfo(input: DestinationInput!): DestinationDisplayInfo! @experimental(flagName: "dest-types") } +# FieldValueConnection is a connection to a list of FieldValuePairs. +type FieldValueConnection { + nodes: [FieldValuePair!]! + pageInfo: PageInfo! +} + input DestinationFieldValidateInput { destType: DestinationType! # the type of destination to validate fieldID: ID! # the ID of the input field to validate @@ -25,6 +30,15 @@ input DestinationFieldValidateInput { # notifications. scalar DestinationType +input DestinationFieldSearchInput { + destType: DestinationType! # the type of destination to search for + fieldID: ID! # the ID of the input field to search for + search: String # search string to match against + omit: [String!] # values/ids to omit from results + after: String # cursor to start search from + first: Int = 15 # number of results to return +} + # Destination represents a destination that can be used for notifications. type Destination { type: DestinationType! @@ -45,6 +59,9 @@ type FieldValuePair { fieldID: ID! # The ID of the input field that this value is for. value: String! # The value of the input field. + label: String! @goField(forceResolver: true) # The user-friendly text for this value of the input field (e.g., if the value is a user ID, label would be the user's name). + + isFavorite: Boolean! # if true, this value is a favorite for the user, only set for search results } input DestinationInput { diff --git a/graphql2/graphqlapp/destinationtypes.go b/graphql2/graphqlapp/destinationtypes.go index d06d30b0df..89c52f581c 100644 --- a/graphql2/graphqlapp/destinationtypes.go +++ b/graphql2/graphqlapp/destinationtypes.go @@ -35,6 +35,130 @@ const ( fieldScheduleID = "schedule-id" ) +type FieldValuePair App +type DestinationDisplayInfo App + +func (a *App) FieldValuePair() graphql2.FieldValuePairResolver { return (*FieldValuePair)(a) } + +func (a *FieldValuePair) Label(ctx context.Context, fvp *graphql2.FieldValuePair) (string, error) { + if fvp.Label != "" { + return fvp.Label, nil + } + + app := (*App)(a) + switch fvp.FieldID { + case fieldSlackChanID: + ch, err := app.SlackStore.Channel(ctx, fvp.Value) + if err != nil { + return "", err + } + return ch.Name, nil + case fieldSlackUGID: + ug, err := app.SlackStore.UserGroup(ctx, fvp.Value) + if err != nil { + return "", err + } + + return ug.Handle, nil + case fieldUserID: + u, err := app.FindOneUser(ctx, fvp.Value) + if err != nil { + return "", err + } + return u.Name, nil + case fieldRotationID: + r, err := app.FindOneRotation(ctx, fvp.Value) + if err != nil { + return "", err + } + return r.Name, nil + case fieldScheduleID: + s, err := app.FindOneSchedule(ctx, fvp.Value) + if err != nil { + return "", err + } + return s.Name, nil + } + + return "", validation.NewGenericError("unsupported fieldID") +} + +func (q *Query) DestinationFieldValueName(ctx context.Context, input graphql2.DestinationFieldValidateInput) (string, error) { + switch input.FieldID { + case fieldSlackChanID: + ch, err := q.SlackChannel(ctx, input.Value) + if err != nil { + return "", err + } + + return ch.Name, nil + case fieldSlackUGID: + ug, err := q.SlackUserGroup(ctx, input.Value) + if err != nil { + return "", err + } + + return ug.Handle, nil + } + + return "", validation.NewGenericError("unsupported fieldID") +} + +func (q *Query) DestinationFieldSearch(ctx context.Context, input graphql2.DestinationFieldSearchInput) (*graphql2.FieldValueConnection, error) { + switch input.FieldID { + case fieldSlackChanID: + res, err := q.SlackChannels(ctx, &graphql2.SlackChannelSearchOptions{ + Omit: input.Omit, + First: input.First, + Search: input.Search, + After: input.After, + }) + if err != nil { + return nil, err + } + + var nodes []graphql2.FieldValuePair + for _, c := range res.Nodes { + nodes = append(nodes, graphql2.FieldValuePair{ + FieldID: input.FieldID, + Value: c.ID, + Label: c.Name, + }) + } + + return &graphql2.FieldValueConnection{ + Nodes: nodes, + PageInfo: res.PageInfo, + }, nil + case fieldSlackUGID: + res, err := q.SlackUserGroups(ctx, &graphql2.SlackUserGroupSearchOptions{ + Omit: input.Omit, + First: input.First, + Search: input.Search, + After: input.After, + }) + if err != nil { + return nil, err + } + + var nodes []graphql2.FieldValuePair + for _, ug := range res.Nodes { + nodes = append(nodes, graphql2.FieldValuePair{ + FieldID: input.FieldID, + Value: ug.ID, + Label: ug.Handle, + }) + } + + return &graphql2.FieldValueConnection{ + Nodes: nodes, + PageInfo: res.PageInfo, + }, nil + } + + return nil, validation.NewGenericError("unsupported fieldID") +} + func (q *Query) DestinationFieldValidate(ctx context.Context, input graphql2.DestinationFieldValidateInput) (bool, error) { switch input.DestType { case destTwilioSMS, destTwilioVoice: diff --git a/graphql2/models_gen.go b/graphql2/models_gen.go index 383d7ee47f..d2c798ae7a 100644 --- a/graphql2/models_gen.go +++ b/graphql2/models_gen.go @@ -318,6 +318,15 @@ type DestinationFieldConfig struct { SupportsValidation bool `json:"supportsValidation"` } +type DestinationFieldSearchInput struct { + DestType string `json:"destType"` + FieldID string `json:"fieldID"` + Search *string `json:"search,omitempty"` + Omit []string `json:"omit,omitempty"` + After *string `json:"after,omitempty"` + First *int `json:"first,omitempty"` +} + type DestinationFieldValidateInput struct { DestType string `json:"destType"` FieldID string `json:"fieldID"` @@ -357,14 +366,21 @@ type EscalationPolicySearchOptions struct { FavoritesFirst *bool `json:"favoritesFirst,omitempty"` } +type FieldValueConnection struct { + Nodes []FieldValuePair `json:"nodes"` + PageInfo *PageInfo `json:"pageInfo"` +} + type FieldValueInput struct { FieldID string `json:"fieldID"` Value string `json:"value"` } type FieldValuePair struct { - FieldID string `json:"fieldID"` - Value string `json:"value"` + FieldID string `json:"fieldID"` + Value string `json:"value"` + Label string `json:"label"` + IsFavorite bool `json:"isFavorite"` } type GQLAPIKey struct { diff --git a/web/src/app/selection/DestinationSearchSelect.stories.tsx b/web/src/app/selection/DestinationSearchSelect.stories.tsx new file mode 100644 index 0000000000..43f4b81254 --- /dev/null +++ b/web/src/app/selection/DestinationSearchSelect.stories.tsx @@ -0,0 +1,234 @@ +import React from 'react' +import type { Meta, StoryObj } from '@storybook/react' +import DestinationSearchSelect from './DestinationSearchSelect' +import { expect } from '@storybook/jest' +import { userEvent, within } from '@storybook/testing-library' +import { handleDefaultConfig } from '../storybook/graphql' +import { HttpResponse, graphql } from 'msw' +import { useArgs } from '@storybook/preview-api' +import { FieldValueConnection } from '../../schema' + +const meta = { + title: 'util/DestinationSearchSelect', + component: DestinationSearchSelect, + argTypes: { + inputType: { table: { disable: true } }, + placeholderText: { table: { disable: true } }, + isSearchSelectable: { table: { disable: true } }, + supportsValidation: { table: { disable: true } }, + prefix: { table: { disable: true } }, + }, + render: function Component(args) { + const [, setArgs] = useArgs() + const onChange = (value: string): void => { + if (args.onChange) args.onChange(value) + setArgs({ value }) + } + return + }, + tags: ['autodocs'], + parameters: { + msw: { + handlers: [ + handleDefaultConfig, + graphql.query('DestinationFieldSearch', ({ variables: vars }) => { + if (vars.input.search === 'query-error') { + return HttpResponse.json({ + errors: [{ message: 'some_backend_error_message' }], + }) + } + if (vars.input.search === 'empty') { + return HttpResponse.json({ + data: { + destinationFieldSearch: { + nodes: [], + __typename: 'FieldValueConnection', + }, + }, + }) + } + + return HttpResponse.json({ + data: { + destinationFieldSearch: { + nodes: [ + { + fieldID: 'field-id', + value: 'value-id-1', + label: '#value-one', + isFavorite: false, + }, + { + fieldID: 'field-id', + value: 'value-id-2', + label: '#value-two', + isFavorite: false, + }, + ], + }, + }, + } satisfies { + data: { destinationFieldSearch: Partial } + }) + }), + graphql.query('DestinationFieldValueName', ({ variables: vars }) => { + if (vars.input.value === 'invalid-value') { + return HttpResponse.json({ + errors: [{ message: 'some_backend_error_message' }], + }) + } + + const names: Record = { + 'value-id-1': '#value-one', + 'value-id-2': '#value-two', + } + return HttpResponse.json({ + data: { + destinationFieldValueName: names[vars.input.value] || '', + }, + }) + }), + ], + }, + }, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + value: '', + + fieldID: 'field-id', + hint: '', + hintURL: '', + inputType: 'text', + isSearchSelectable: true, + labelPlural: 'Select Values', + labelSingular: 'Select Value', + placeholderText: 'asdf', + prefix: '', + supportsValidation: false, + + destType: 'test-type', + }, +} + +export const OptionSelected: Story = { + args: { + value: 'value-id-1', + + fieldID: 'field-id', + hint: '', + hintURL: '', + inputType: 'text', + isSearchSelectable: true, + labelPlural: 'Select Values', + labelSingular: 'Select Value', + placeholderText: '', + prefix: '', + supportsValidation: false, + + destType: 'test-type', + }, +} + +export const Disabled: Story = { + args: { + value: 'value-id-1', + + fieldID: 'field-id', + hint: '', + hintURL: '', + inputType: 'text', + isSearchSelectable: true, + labelPlural: 'Select Values', + labelSingular: 'Select Value', + placeholderText: '', + prefix: '', + supportsValidation: false, + + destType: 'test-type', + disabled: true, + }, +} + +export const InvalidOptionSelected: Story = { + args: { + value: 'invalid-value', + + fieldID: 'field-id', + hint: '', + hintURL: '', + inputType: 'text', + isSearchSelectable: true, + labelPlural: 'Select Values', + labelSingular: 'Select Value', + placeholderText: '', + prefix: '', + supportsValidation: false, + + destType: 'test-type', + }, +} + +export const NoOptions: Story = { + args: { + value: '', + + fieldID: 'field-id', + hint: '', + hintURL: '', + inputType: 'text', + isSearchSelectable: true, + labelPlural: 'Select Values', + labelSingular: 'Select Value', + placeholderText: '', + prefix: '', + supportsValidation: false, + + destType: 'test-type', + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement) + + const box = await canvas.findByRole('combobox') + await userEvent.click(box) + await userEvent.type(box, 'empty', { delay: null }) + + expect(await within(document.body).findByText('No options')).toBeVisible() + }, +} + +export const QueryError: Story = { + args: { + value: '', + + fieldID: 'field-id', + hint: '', + hintURL: '', + inputType: 'text', + isSearchSelectable: true, + labelPlural: 'Select Values', + labelSingular: 'Select Value', + placeholderText: '', + prefix: '', + supportsValidation: false, + + destType: 'test-type', + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement) + + const box = await canvas.findByRole('combobox') + await userEvent.click(box) + await userEvent.type(box, 'query-error', { delay: null }) + + expect( + await within(document.body).findByText( + '[GraphQL] some_backend_error_message', + ), + ).toBeVisible() + }, +} diff --git a/web/src/app/selection/DestinationSearchSelect.tsx b/web/src/app/selection/DestinationSearchSelect.tsx new file mode 100644 index 0000000000..5eec03bbe0 --- /dev/null +++ b/web/src/app/selection/DestinationSearchSelect.tsx @@ -0,0 +1,152 @@ +import React, { useState } from 'react' +import { useQuery, gql } from 'urql' +import { + DestinationFieldConfig, + DestinationType, + FieldValueConnection, +} from '../../schema' +import MaterialSelect from './MaterialSelect' +import { FavoriteIcon } from '../util/SetFavoriteButton' +import AppLink from '../util/AppLink' + +const searchOptionsQuery = gql` + query DestinationFieldSearch($input: DestinationFieldSearchInput!) { + destinationFieldSearch(input: $input) { + nodes { + value + label + isFavorite + } + } + } +` + +const selectedLabelQuery = gql` + query DestinationFieldValueName($input: DestinationFieldValidateInput!) { + destinationFieldValueName(input: $input) + } +` + +const noSuspense = { suspense: false } + +export type DestinationSearchSelectProps = DestinationFieldConfig & { + value: string + onChange?: (newValue: string) => void + destType: DestinationType + + disabled?: boolean + error?: boolean +} + +const cacheByJSON: Record = {} + +function cachify(val: T): T { + const json = JSON.stringify(val) + if (cacheByJSON[json]) return cacheByJSON[json] as T + cacheByJSON[json] = val + + return val +} + +/** + * DestinationSearchSelect is a select field that allows the user to select a + * destination from a list of options. + * + * You should almost never use this component directly. Instead, use + * DestinationField, which will select the correct component based on the + * destination type. + */ +export default function DestinationSearchSelect( + props: DestinationSearchSelectProps, +): JSX.Element { + const [inputValue, setInputValue] = useState('') + + // check validation of the input phoneNumber through graphql + const [{ data, fetching, error }] = useQuery<{ + destinationFieldSearch: FieldValueConnection + }>({ + query: searchOptionsQuery, + variables: { + input: { + destType: props.destType, + search: inputValue, + fieldID: props.fieldID, + }, + }, + requestPolicy: 'cache-first', + pause: props.disabled, + context: noSuspense, + }) + const options = data?.destinationFieldSearch.nodes || [] + + const [{ data: selectedLabelData, error: selectedErr }] = useQuery<{ + destinationFieldValueName: string + }>({ + query: selectedLabelQuery, + variables: { + input: { + destType: props.destType, + value: props.value, + fieldID: props.fieldID, + }, + }, + requestPolicy: 'cache-first', + pause: !props.value, + context: noSuspense, + }) + + let selectedLabel = selectedLabelData?.destinationFieldValueName || '' + if (selectedErr) { + selectedLabel = `ERROR: ${selectedErr.message}` + } + + interface SelectOption { + value: string + label: string + } + + function handleChange(val: SelectOption | null): void { + if (!props.onChange) return + + // should not be possible since multiple is false + if (Array.isArray(val)) throw new Error('Multiple values not supported') + + props.onChange(val?.value || '') + } + + const value = props.value + ? { label: selectedLabel, value: props.value } + : null + + return ( + setInputValue(val)} + value={value as unknown as SelectOption} + label={props.labelSingular} + helperText={ + props.hintURL ? ( + + {props.hint} + + ) : ( + props.hint + ) + } + options={options + .map((opt) => ({ + label: opt.label, + value: opt.value, + icon: opt.isFavorite ? : undefined, + })) + .map(cachify)} + placeholder='Start typing...' + onChange={handleChange} + /> + ) +} diff --git a/web/src/app/selection/MaterialSelect.tsx b/web/src/app/selection/MaterialSelect.tsx index 738b8f4e77..1355442fdf 100644 --- a/web/src/app/selection/MaterialSelect.tsx +++ b/web/src/app/selection/MaterialSelect.tsx @@ -78,11 +78,12 @@ interface CommonSelectProps { clientSideFilter?: boolean disableCloseOnSelect?: boolean optionsLimit?: number + helperText?: ReactNode } interface SingleSelectProps { multiple: false - value: SelectOption + value: SelectOption | null onChange: (value: SelectOption | null) => void } @@ -251,6 +252,7 @@ export default function MaterialSelect( const newInputVal: string = target.value setInputValue(newInputVal) }} + helperText={props.helperText} error={error} /> ) diff --git a/web/src/schema.d.ts b/web/src/schema.d.ts index 3519098771..4269ff2e40 100644 --- a/web/src/schema.d.ts +++ b/web/src/schema.d.ts @@ -366,6 +366,15 @@ export interface DestinationFieldConfig { supportsValidation: boolean } +export interface DestinationFieldSearchInput { + after?: null | string + destType: DestinationType + fieldID: string + first?: null | number + omit?: null | string[] + search?: null | string +} + export interface DestinationFieldValidateInput { destType: DestinationType fieldID: string @@ -426,6 +435,11 @@ export interface EscalationPolicyStep { targets: Target[] } +export interface FieldValueConnection { + nodes: FieldValuePair[] + pageInfo: PageInfo +} + export interface FieldValueInput { fieldID: string value: string @@ -433,6 +447,8 @@ export interface FieldValueInput { export interface FieldValuePair { fieldID: string + isFavorite: boolean + label: string value: string } @@ -691,7 +707,9 @@ export interface Query { debugMessageStatus: DebugMessageStatusInfo debugMessages: DebugMessage[] destinationDisplayInfo: DestinationDisplayInfo + destinationFieldSearch: FieldValueConnection destinationFieldValidate: boolean + destinationFieldValueName: string destinationTypes: DestinationTypeInfo[] escalationPolicies: EscalationPolicyConnection escalationPolicy?: null | EscalationPolicy