From 089dcb36b482ecf77c7fa46e4336955352e21e32 Mon Sep 17 00:00:00 2001 From: Dmitry Ng <19asdek91@gmail.com> Date: Wed, 8 Apr 2026 03:34:32 +0300 Subject: [PATCH] feat: implement flow templates management --- .../sql/20260325_120000_flow_templates.sql | 49 + backend/pkg/database/converter/converter.go | 19 + backend/pkg/database/flow_templates.sql.go | 153 ++ backend/pkg/database/models.go | 9 + backend/pkg/database/querier.go | 5 + backend/pkg/graph/generated.go | 1372 +++++++++++++++++ backend/pkg/graph/model/models_gen.go | 19 + backend/pkg/graph/schema.graphqls | 35 + backend/pkg/graph/schema.resolvers.go | 241 +++ backend/pkg/graph/subscriptions/controller.go | 12 + backend/pkg/graph/subscriptions/publisher.go | 12 + backend/pkg/graph/subscriptions/subscriber.go | 12 + backend/pkg/server/router.go | 2 + backend/sqlc/models/flow_templates.sql | 32 + frontend/graphql-schema.graphql | 59 + frontend/package-lock.json | 5 +- frontend/src/graphql/types.ts | 790 +++++++++- frontend/src/lib/apollo.ts | 4 + frontend/src/pages/templates/template.tsx | 259 +++- frontend/src/pages/templates/templates.tsx | 4 +- frontend/src/providers/templates-provider.tsx | 238 ++- 21 files changed, 3129 insertions(+), 202 deletions(-) create mode 100644 backend/migrations/sql/20260325_120000_flow_templates.sql create mode 100644 backend/pkg/database/flow_templates.sql.go create mode 100644 backend/sqlc/models/flow_templates.sql diff --git a/backend/migrations/sql/20260325_120000_flow_templates.sql b/backend/migrations/sql/20260325_120000_flow_templates.sql new file mode 100644 index 00000000..4766ff08 --- /dev/null +++ b/backend/migrations/sql/20260325_120000_flow_templates.sql @@ -0,0 +1,49 @@ +-- +goose Up +-- +goose StatementBegin +INSERT INTO privileges (role_id, name) VALUES + (1, 'templates.admin'), + (1, 'templates.create'), + (1, 'templates.view'), + (1, 'templates.edit'), + (1, 'templates.delete'), + (1, 'templates.subscribe'), + (2, 'templates.create'), + (2, 'templates.view'), + (2, 'templates.edit'), + (2, 'templates.delete'), + (2, 'templates.subscribe') + ON CONFLICT DO NOTHING; + +CREATE TABLE flow_templates ( + id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + title TEXT NOT NULL, + text TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT flow_templates_title_not_empty CHECK (length(trim(title)) > 0), + CONSTRAINT flow_templates_text_not_empty CHECK (length(trim(text)) > 0) +); + +CREATE INDEX flow_templates_user_id_idx ON flow_templates(user_id); +CREATE INDEX flow_templates_created_at_idx ON flow_templates(created_at DESC); + +CREATE OR REPLACE TRIGGER update_flow_templates_modified + BEFORE UPDATE ON flow_templates + FOR EACH ROW EXECUTE PROCEDURE update_modified_column(); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS flow_templates; + +DELETE FROM privileges WHERE name IN ( + 'templates.admin', + 'templates.create', + 'templates.view', + 'templates.edit', + 'templates.delete', + 'templates.subscribe' +); +-- +goose StatementEnd diff --git a/backend/pkg/database/converter/converter.go b/backend/pkg/database/converter/converter.go index 60715ce2..256c0cbe 100644 --- a/backend/pkg/database/converter/converter.go +++ b/backend/pkg/database/converter/converter.go @@ -492,6 +492,25 @@ func ConvertAPITokens(tokens []database.ApiToken) []*model.APIToken { return result } +func ConvertFlowTemplate(template database.FlowTemplate) *model.FlowTemplate { + return &model.FlowTemplate{ + ID: template.ID, + UserID: template.UserID, + Title: template.Title, + Text: template.Text, + CreatedAt: template.CreatedAt.Time, + UpdatedAt: template.UpdatedAt.Time, + } +} + +func ConvertFlowTemplates(templates []database.FlowTemplate) []*model.FlowTemplate { + result := make([]*model.FlowTemplate, 0, len(templates)) + for _, template := range templates { + result = append(result, ConvertFlowTemplate(template)) + } + return result +} + func ConvertModels(models pconfig.ModelsConfig) []*model.ModelConfig { gmodels := make([]*model.ModelConfig, 0, len(models)) for _, m := range models { diff --git a/backend/pkg/database/flow_templates.sql.go b/backend/pkg/database/flow_templates.sql.go new file mode 100644 index 00000000..9a71fa29 --- /dev/null +++ b/backend/pkg/database/flow_templates.sql.go @@ -0,0 +1,153 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 +// source: flow_templates.sql + +package database + +import ( + "context" +) + +const createFlowTemplate = `-- name: CreateFlowTemplate :one +INSERT INTO flow_templates ( + user_id, + title, + text +) VALUES ( + $1, + $2, + $3 +) +RETURNING id, user_id, title, text, created_at, updated_at +` + +type CreateFlowTemplateParams struct { + UserID int64 `json:"user_id"` + Title string `json:"title"` + Text string `json:"text"` +} + +func (q *Queries) CreateFlowTemplate(ctx context.Context, arg CreateFlowTemplateParams) (FlowTemplate, error) { + row := q.db.QueryRowContext(ctx, createFlowTemplate, arg.UserID, arg.Title, arg.Text) + var i FlowTemplate + err := row.Scan( + &i.ID, + &i.UserID, + &i.Title, + &i.Text, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteFlowTemplate = `-- name: DeleteFlowTemplate :exec +DELETE FROM flow_templates +WHERE id = $1 AND user_id = $2 +` + +type DeleteFlowTemplateParams struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` +} + +func (q *Queries) DeleteFlowTemplate(ctx context.Context, arg DeleteFlowTemplateParams) error { + _, err := q.db.ExecContext(ctx, deleteFlowTemplate, arg.ID, arg.UserID) + return err +} + +const getFlowTemplate = `-- name: GetFlowTemplate :one +SELECT id, user_id, title, text, created_at, updated_at FROM flow_templates +WHERE id = $1 AND user_id = $2 LIMIT 1 +` + +type GetFlowTemplateParams struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` +} + +func (q *Queries) GetFlowTemplate(ctx context.Context, arg GetFlowTemplateParams) (FlowTemplate, error) { + row := q.db.QueryRowContext(ctx, getFlowTemplate, arg.ID, arg.UserID) + var i FlowTemplate + err := row.Scan( + &i.ID, + &i.UserID, + &i.Title, + &i.Text, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getFlowTemplatesByUserID = `-- name: GetFlowTemplatesByUserID :many +SELECT id, user_id, title, text, created_at, updated_at FROM flow_templates +WHERE user_id = $1 +ORDER BY created_at DESC +` + +func (q *Queries) GetFlowTemplatesByUserID(ctx context.Context, userID int64) ([]FlowTemplate, error) { + rows, err := q.db.QueryContext(ctx, getFlowTemplatesByUserID, userID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FlowTemplate + for rows.Next() { + var i FlowTemplate + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.Title, + &i.Text, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateFlowTemplate = `-- name: UpdateFlowTemplate :one +UPDATE flow_templates +SET + title = $3, + text = $4 +WHERE id = $1 AND user_id = $2 +RETURNING id, user_id, title, text, created_at, updated_at +` + +type UpdateFlowTemplateParams struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` + Title string `json:"title"` + Text string `json:"text"` +} + +func (q *Queries) UpdateFlowTemplate(ctx context.Context, arg UpdateFlowTemplateParams) (FlowTemplate, error) { + row := q.db.QueryRowContext(ctx, updateFlowTemplate, + arg.ID, + arg.UserID, + arg.Title, + arg.Text, + ) + var i FlowTemplate + err := row.Scan( + &i.ID, + &i.UserID, + &i.Title, + &i.Text, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/backend/pkg/database/models.go b/backend/pkg/database/models.go index 72bebc9c..e53678d6 100644 --- a/backend/pkg/database/models.go +++ b/backend/pkg/database/models.go @@ -946,6 +946,15 @@ type Flow struct { ToolCallIDTemplate string `json:"tool_call_id_template"` } +type FlowTemplate struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` + Title string `json:"title"` + Text string `json:"text"` + CreatedAt sql.NullTime `json:"created_at"` + UpdatedAt sql.NullTime `json:"updated_at"` +} + type Msgchain struct { ID int64 `json:"id"` Type MsgchainType `json:"type"` diff --git a/backend/pkg/database/querier.go b/backend/pkg/database/querier.go index 3f9af3c0..8f52b2c8 100644 --- a/backend/pkg/database/querier.go +++ b/backend/pkg/database/querier.go @@ -17,6 +17,7 @@ type Querier interface { CreateAssistantLog(ctx context.Context, arg CreateAssistantLogParams) (Assistantlog, error) CreateContainer(ctx context.Context, arg CreateContainerParams) (Container, error) CreateFlow(ctx context.Context, arg CreateFlowParams) (Flow, error) + CreateFlowTemplate(ctx context.Context, arg CreateFlowTemplateParams) (FlowTemplate, error) CreateMsgChain(ctx context.Context, arg CreateMsgChainParams) (Msgchain, error) CreateMsgLog(ctx context.Context, arg CreateMsgLogParams) (Msglog, error) CreateProvider(ctx context.Context, arg CreateProviderParams) (Provider, error) @@ -37,6 +38,7 @@ type Querier interface { DeleteFavoriteFlow(ctx context.Context, arg DeleteFavoriteFlowParams) (UserPreference, error) DeleteFlow(ctx context.Context, id int64) (Flow, error) DeleteFlowAssistantLog(ctx context.Context, id int64) error + DeleteFlowTemplate(ctx context.Context, arg DeleteFlowTemplateParams) error DeletePrompt(ctx context.Context, id int64) error DeleteProvider(ctx context.Context, id int64) (Provider, error) DeleteSubtask(ctx context.Context, id int64) error @@ -83,6 +85,8 @@ type Querier interface { GetFlowTaskSubtasks(ctx context.Context, arg GetFlowTaskSubtasksParams) ([]Subtask, error) GetFlowTaskTypeLastMsgChain(ctx context.Context, arg GetFlowTaskTypeLastMsgChainParams) (Msgchain, error) GetFlowTasks(ctx context.Context, flowID int64) ([]Task, error) + GetFlowTemplate(ctx context.Context, arg GetFlowTemplateParams) (FlowTemplate, error) + GetFlowTemplatesByUserID(ctx context.Context, userID int64) ([]FlowTemplate, error) GetFlowTermLogs(ctx context.Context, flowID int64) ([]Termlog, error) // ==================== Toolcalls Analytics Queries ==================== // Get total execution time and count of toolcalls for a specific flow @@ -224,6 +228,7 @@ type Querier interface { UpdateFlow(ctx context.Context, arg UpdateFlowParams) (Flow, error) UpdateFlowLanguage(ctx context.Context, arg UpdateFlowLanguageParams) (Flow, error) UpdateFlowStatus(ctx context.Context, arg UpdateFlowStatusParams) (Flow, error) + UpdateFlowTemplate(ctx context.Context, arg UpdateFlowTemplateParams) (FlowTemplate, error) UpdateFlowTitle(ctx context.Context, arg UpdateFlowTitleParams) (Flow, error) UpdateFlowToolCallIDTemplate(ctx context.Context, arg UpdateFlowToolCallIDTemplateParams) (Flow, error) UpdateMsgChain(ctx context.Context, arg UpdateMsgChainParams) (Msgchain, error) diff --git a/backend/pkg/graph/generated.go b/backend/pkg/graph/generated.go index 419232f3..da6d67a5 100644 --- a/backend/pkg/graph/generated.go +++ b/backend/pkg/graph/generated.go @@ -247,6 +247,15 @@ type ComplexityRoot struct { TotalTasksCount func(childComplexity int) int } + FlowTemplate struct { + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + Text func(childComplexity int) int + Title func(childComplexity int) int + UpdatedAt func(childComplexity int) int + UserID func(childComplexity int) int + } + FlowsStats struct { TotalAssistantsCount func(childComplexity int) int TotalFlowsCount func(childComplexity int) int @@ -302,12 +311,14 @@ type ComplexityRoot struct { CreateAPIToken func(childComplexity int, input model.CreateAPITokenInput) int CreateAssistant func(childComplexity int, flowID int64, modelProvider string, input string, useAgents bool) int CreateFlow func(childComplexity int, modelProvider string, input string) int + CreateFlowTemplate func(childComplexity int, input model.CreateFlowTemplateInput) int CreatePrompt func(childComplexity int, typeArg model.PromptType, template string) int CreateProvider func(childComplexity int, name string, typeArg model.ProviderType, agents model.AgentsConfig) int DeleteAPIToken func(childComplexity int, tokenID string) int DeleteAssistant func(childComplexity int, flowID int64, assistantID int64) int DeleteFavoriteFlow func(childComplexity int, flowID int64) int DeleteFlow func(childComplexity int, flowID int64) int + DeleteFlowTemplate func(childComplexity int, templateID int64) int DeletePrompt func(childComplexity int, promptID int64) int DeleteProvider func(childComplexity int, providerID int64) int FinishFlow func(childComplexity int, flowID int64) int @@ -318,6 +329,7 @@ type ComplexityRoot struct { TestAgent func(childComplexity int, typeArg model.ProviderType, agentType model.AgentConfigType, agent model.AgentConfig) int TestProvider func(childComplexity int, typeArg model.ProviderType, agents model.AgentsConfig) int UpdateAPIToken func(childComplexity int, tokenID string, input model.UpdateAPITokenInput) int + UpdateFlowTemplate func(childComplexity int, templateID int64, input model.UpdateFlowTemplateInput) int UpdatePrompt func(childComplexity int, promptID int64, template string) int UpdateProvider func(childComplexity int, providerID int64, name string, agents model.AgentsConfig) int ValidatePrompt func(childComplexity int, typeArg model.PromptType, template string) int @@ -412,6 +424,8 @@ type ComplexityRoot struct { Assistants func(childComplexity int, flowID int64) int Flow func(childComplexity int, flowID int64) int FlowStatsByFlow func(childComplexity int, flowID int64) int + FlowTemplate func(childComplexity int, templateID int64) int + FlowTemplates func(childComplexity int) int Flows func(childComplexity int) int FlowsExecutionStatsByPeriod func(childComplexity int, period model.UsageStatsPeriod) int FlowsStatsByPeriod func(childComplexity int, period model.UsageStatsPeriod) int @@ -488,6 +502,9 @@ type ComplexityRoot struct { AssistantUpdated func(childComplexity int, flowID int64) int FlowCreated func(childComplexity int) int FlowDeleted func(childComplexity int) int + FlowTemplateCreated func(childComplexity int) int + FlowTemplateDeleted func(childComplexity int) int + FlowTemplateUpdated func(childComplexity int) int FlowUpdated func(childComplexity int) int MessageLogAdded func(childComplexity int, flowID int64) int MessageLogUpdated func(childComplexity int, flowID int64) int @@ -653,6 +670,9 @@ type MutationResolver interface { DeleteAPIToken(ctx context.Context, tokenID string) (bool, error) AddFavoriteFlow(ctx context.Context, flowID int64) (model.ResultType, error) DeleteFavoriteFlow(ctx context.Context, flowID int64) (model.ResultType, error) + CreateFlowTemplate(ctx context.Context, input model.CreateFlowTemplateInput) (*model.FlowTemplate, error) + UpdateFlowTemplate(ctx context.Context, templateID int64, input model.UpdateFlowTemplateInput) (*model.FlowTemplate, error) + DeleteFlowTemplate(ctx context.Context, templateID int64) (model.ResultType, error) } type QueryResolver interface { Providers(ctx context.Context) ([]*model.Provider, error) @@ -689,6 +709,8 @@ type QueryResolver interface { SettingsUser(ctx context.Context) (*model.UserPreferences, error) APIToken(ctx context.Context, tokenID string) (*model.APIToken, error) APITokens(ctx context.Context) ([]*model.APIToken, error) + FlowTemplate(ctx context.Context, templateID int64) (*model.FlowTemplate, error) + FlowTemplates(ctx context.Context) ([]*model.FlowTemplate, error) } type SubscriptionResolver interface { FlowCreated(ctx context.Context) (<-chan *model.Flow, error) @@ -715,6 +737,9 @@ type SubscriptionResolver interface { APITokenUpdated(ctx context.Context) (<-chan *model.APIToken, error) APITokenDeleted(ctx context.Context) (<-chan *model.APIToken, error) SettingsUserUpdated(ctx context.Context) (<-chan *model.UserPreferences, error) + FlowTemplateCreated(ctx context.Context) (<-chan *model.FlowTemplate, error) + FlowTemplateUpdated(ctx context.Context) (<-chan *model.FlowTemplate, error) + FlowTemplateDeleted(ctx context.Context) (<-chan *model.FlowTemplate, error) } type executableSchema struct { @@ -1653,6 +1678,48 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.FlowStats.TotalTasksCount(childComplexity), true + case "FlowTemplate.createdAt": + if e.complexity.FlowTemplate.CreatedAt == nil { + break + } + + return e.complexity.FlowTemplate.CreatedAt(childComplexity), true + + case "FlowTemplate.id": + if e.complexity.FlowTemplate.ID == nil { + break + } + + return e.complexity.FlowTemplate.ID(childComplexity), true + + case "FlowTemplate.text": + if e.complexity.FlowTemplate.Text == nil { + break + } + + return e.complexity.FlowTemplate.Text(childComplexity), true + + case "FlowTemplate.title": + if e.complexity.FlowTemplate.Title == nil { + break + } + + return e.complexity.FlowTemplate.Title(childComplexity), true + + case "FlowTemplate.updatedAt": + if e.complexity.FlowTemplate.UpdatedAt == nil { + break + } + + return e.complexity.FlowTemplate.UpdatedAt(childComplexity), true + + case "FlowTemplate.userId": + if e.complexity.FlowTemplate.UserID == nil { + break + } + + return e.complexity.FlowTemplate.UserID(childComplexity), true + case "FlowsStats.totalAssistantsCount": if e.complexity.FlowsStats.TotalAssistantsCount == nil { break @@ -1930,6 +1997,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.CreateFlow(childComplexity, args["modelProvider"].(string), args["input"].(string)), true + case "Mutation.createFlowTemplate": + if e.complexity.Mutation.CreateFlowTemplate == nil { + break + } + + args, err := ec.field_Mutation_createFlowTemplate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.CreateFlowTemplate(childComplexity, args["input"].(model.CreateFlowTemplateInput)), true + case "Mutation.createPrompt": if e.complexity.Mutation.CreatePrompt == nil { break @@ -2002,6 +2081,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.DeleteFlow(childComplexity, args["flowId"].(int64)), true + case "Mutation.deleteFlowTemplate": + if e.complexity.Mutation.DeleteFlowTemplate == nil { + break + } + + args, err := ec.field_Mutation_deleteFlowTemplate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.DeleteFlowTemplate(childComplexity, args["templateId"].(int64)), true + case "Mutation.deletePrompt": if e.complexity.Mutation.DeletePrompt == nil { break @@ -2122,6 +2213,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.UpdateAPIToken(childComplexity, args["tokenId"].(string), args["input"].(model.UpdateAPITokenInput)), true + case "Mutation.updateFlowTemplate": + if e.complexity.Mutation.UpdateFlowTemplate == nil { + break + } + + args, err := ec.field_Mutation_updateFlowTemplate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateFlowTemplate(childComplexity, args["templateId"].(int64), args["input"].(model.UpdateFlowTemplateInput)), true + case "Mutation.updatePrompt": if e.complexity.Mutation.UpdatePrompt == nil { break @@ -2615,6 +2718,25 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.FlowStatsByFlow(childComplexity, args["flowId"].(int64)), true + case "Query.flowTemplate": + if e.complexity.Query.FlowTemplate == nil { + break + } + + args, err := ec.field_Query_flowTemplate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.FlowTemplate(childComplexity, args["templateId"].(int64)), true + + case "Query.flowTemplates": + if e.complexity.Query.FlowTemplates == nil { + break + } + + return e.complexity.Query.FlowTemplates(childComplexity), true + case "Query.flows": if e.complexity.Query.Flows == nil { break @@ -3142,6 +3264,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Subscription.FlowDeleted(childComplexity), true + case "Subscription.flowTemplateCreated": + if e.complexity.Subscription.FlowTemplateCreated == nil { + break + } + + return e.complexity.Subscription.FlowTemplateCreated(childComplexity), true + + case "Subscription.flowTemplateDeleted": + if e.complexity.Subscription.FlowTemplateDeleted == nil { + break + } + + return e.complexity.Subscription.FlowTemplateDeleted(childComplexity), true + + case "Subscription.flowTemplateUpdated": + if e.complexity.Subscription.FlowTemplateUpdated == nil { + break + } + + return e.complexity.Subscription.FlowTemplateUpdated(childComplexity), true + case "Subscription.flowUpdated": if e.complexity.Subscription.FlowUpdated == nil { break @@ -3879,9 +4022,11 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputAgentConfigInput, ec.unmarshalInputAgentsConfigInput, ec.unmarshalInputCreateAPITokenInput, + ec.unmarshalInputCreateFlowTemplateInput, ec.unmarshalInputModelPriceInput, ec.unmarshalInputReasoningConfigInput, ec.unmarshalInputUpdateAPITokenInput, + ec.unmarshalInputUpdateFlowTemplateInput, ) first := true @@ -4305,6 +4450,38 @@ func (ec *executionContext) field_Mutation_createAssistant_argsUseAgents( return zeroVal, nil } +func (ec *executionContext) field_Mutation_createFlowTemplate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Mutation_createFlowTemplate_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_createFlowTemplate_argsInput( + ctx context.Context, + rawArgs map[string]interface{}, +) (model.CreateFlowTemplateInput, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["input"] + if !ok { + var zeroVal model.CreateFlowTemplateInput + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNCreateFlowTemplateInput2pentagiᚋpkgᚋgraphᚋmodelᚐCreateFlowTemplateInput(ctx, tmp) + } + + var zeroVal model.CreateFlowTemplateInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_createFlow_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4632,6 +4809,38 @@ func (ec *executionContext) field_Mutation_deleteFavoriteFlow_argsFlowID( return zeroVal, nil } +func (ec *executionContext) field_Mutation_deleteFlowTemplate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Mutation_deleteFlowTemplate_argsTemplateID(ctx, rawArgs) + if err != nil { + return nil, err + } + args["templateId"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_deleteFlowTemplate_argsTemplateID( + ctx context.Context, + rawArgs map[string]interface{}, +) (int64, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["templateId"] + if !ok { + var zeroVal int64 + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("templateId")) + if tmp, ok := rawArgs["templateId"]; ok { + return ec.unmarshalNID2int64(ctx, tmp) + } + + var zeroVal int64 + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_deleteFlow_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -5173,6 +5382,65 @@ func (ec *executionContext) field_Mutation_updateAPIToken_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_updateFlowTemplate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Mutation_updateFlowTemplate_argsTemplateID(ctx, rawArgs) + if err != nil { + return nil, err + } + args["templateId"] = arg0 + arg1, err := ec.field_Mutation_updateFlowTemplate_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg1 + return args, nil +} +func (ec *executionContext) field_Mutation_updateFlowTemplate_argsTemplateID( + ctx context.Context, + rawArgs map[string]interface{}, +) (int64, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["templateId"] + if !ok { + var zeroVal int64 + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("templateId")) + if tmp, ok := rawArgs["templateId"]; ok { + return ec.unmarshalNID2int64(ctx, tmp) + } + + var zeroVal int64 + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_updateFlowTemplate_argsInput( + ctx context.Context, + rawArgs map[string]interface{}, +) (model.UpdateFlowTemplateInput, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["input"] + if !ok { + var zeroVal model.UpdateFlowTemplateInput + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNUpdateFlowTemplateInput2pentagiᚋpkgᚋgraphᚋmodelᚐUpdateFlowTemplateInput(ctx, tmp) + } + + var zeroVal model.UpdateFlowTemplateInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_updatePrompt_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -5596,6 +5864,38 @@ func (ec *executionContext) field_Query_flowStatsByFlow_argsFlowID( return zeroVal, nil } +func (ec *executionContext) field_Query_flowTemplate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Query_flowTemplate_argsTemplateID(ctx, rawArgs) + if err != nil { + return nil, err + } + args["templateId"] = arg0 + return args, nil +} +func (ec *executionContext) field_Query_flowTemplate_argsTemplateID( + ctx context.Context, + rawArgs map[string]interface{}, +) (int64, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["templateId"] + if !ok { + var zeroVal int64 + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("templateId")) + if tmp, ok := rawArgs["templateId"]; ok { + return ec.unmarshalNID2int64(ctx, tmp) + } + + var zeroVal int64 + return zeroVal, nil +} + func (ec *executionContext) field_Query_flow_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -13077,6 +13377,270 @@ func (ec *executionContext) fieldContext_FlowStats_totalAssistantsCount(_ contex return fc, nil } +func (ec *executionContext) _FlowTemplate_id(ctx context.Context, field graphql.CollectedField, obj *model.FlowTemplate) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FlowTemplate_id(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.ID, 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.(int64) + fc.Result = res + return ec.marshalNID2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FlowTemplate_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FlowTemplate", + Field: field, + IsMethod: false, + IsResolver: false, + 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 fc, nil +} + +func (ec *executionContext) _FlowTemplate_userId(ctx context.Context, field graphql.CollectedField, obj *model.FlowTemplate) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FlowTemplate_userId(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.UserID, 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.(int64) + fc.Result = res + return ec.marshalNID2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FlowTemplate_userId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FlowTemplate", + Field: field, + IsMethod: false, + IsResolver: false, + 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 fc, nil +} + +func (ec *executionContext) _FlowTemplate_title(ctx context.Context, field graphql.CollectedField, obj *model.FlowTemplate) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FlowTemplate_title(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.Title, 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.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FlowTemplate_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FlowTemplate", + 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 fc, nil +} + +func (ec *executionContext) _FlowTemplate_text(ctx context.Context, field graphql.CollectedField, obj *model.FlowTemplate) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FlowTemplate_text(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.Text, 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.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FlowTemplate_text(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FlowTemplate", + 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 fc, nil +} + +func (ec *executionContext) _FlowTemplate_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.FlowTemplate) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FlowTemplate_createdAt(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.CreatedAt, 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.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FlowTemplate_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FlowTemplate", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _FlowTemplate_updatedAt(ctx context.Context, field graphql.CollectedField, obj *model.FlowTemplate) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_FlowTemplate_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.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_FlowTemplate_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FlowTemplate", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _FlowsStats_totalFlowsCount(ctx context.Context, field graphql.CollectedField, obj *model.FlowsStats) (ret graphql.Marshaler) { fc, err := ec.fieldContext_FlowsStats_totalFlowsCount(ctx, field) if err != nil { @@ -15942,6 +16506,199 @@ func (ec *executionContext) fieldContext_Mutation_deleteFavoriteFlow(ctx context return fc, nil } +func (ec *executionContext) _Mutation_createFlowTemplate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createFlowTemplate(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.Mutation().CreateFlowTemplate(rctx, fc.Args["input"].(model.CreateFlowTemplateInput)) + }) + 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.(*model.FlowTemplate) + fc.Result = res + return ec.marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_createFlowTemplate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + 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_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", 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_Mutation_createFlowTemplate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_updateFlowTemplate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_updateFlowTemplate(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.Mutation().UpdateFlowTemplate(rctx, fc.Args["templateId"].(int64), fc.Args["input"].(model.UpdateFlowTemplateInput)) + }) + 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.(*model.FlowTemplate) + fc.Result = res + return ec.marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_updateFlowTemplate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + 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_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", 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_Mutation_updateFlowTemplate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_deleteFlowTemplate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteFlowTemplate(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.Mutation().DeleteFlowTemplate(rctx, fc.Args["templateId"].(int64)) + }) + 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.(model.ResultType) + fc.Result = res + return ec.marshalNResultType2pentagiᚋpkgᚋgraphᚋmodelᚐResultType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_deleteFlowTemplate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ResultType 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_Mutation_deleteFlowTemplate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _PromptValidationResult_result(ctx context.Context, field graphql.CollectedField, obj *model.PromptValidationResult) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PromptValidationResult_result(ctx, field) if err != nil { @@ -20706,6 +21463,130 @@ func (ec *executionContext) fieldContext_Query_apiTokens(_ context.Context, fiel return fc, nil } +func (ec *executionContext) _Query_flowTemplate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_flowTemplate(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().FlowTemplate(rctx, fc.Args["templateId"].(int64)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.FlowTemplate) + fc.Result = res + return ec.marshalOFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_flowTemplate(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 "id": + return ec.fieldContext_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", 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_flowTemplate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_flowTemplates(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_flowTemplates(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().FlowTemplates(rctx) + }) + 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.([]*model.FlowTemplate) + fc.Result = res + return ec.marshalNFlowTemplate2ᚕᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplateᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_flowTemplates(_ 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 "id": + return ec.fieldContext_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query___type(ctx, field) if err != nil { @@ -23813,6 +24694,222 @@ func (ec *executionContext) fieldContext_Subscription_settingsUserUpdated(_ cont return fc, nil } +func (ec *executionContext) _Subscription_flowTemplateCreated(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_flowTemplateCreated(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().FlowTemplateCreated(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.FlowTemplate): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_flowTemplateCreated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + 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_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Subscription_flowTemplateUpdated(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_flowTemplateUpdated(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().FlowTemplateUpdated(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.FlowTemplate): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_flowTemplateUpdated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + 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_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Subscription_flowTemplateDeleted(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_flowTemplateDeleted(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().FlowTemplateDeleted(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.FlowTemplate): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_flowTemplateDeleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + 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_FlowTemplate_id(ctx, field) + case "userId": + return ec.fieldContext_FlowTemplate_userId(ctx, field) + case "title": + return ec.fieldContext_FlowTemplate_title(ctx, field) + case "text": + return ec.fieldContext_FlowTemplate_text(ctx, field) + case "createdAt": + return ec.fieldContext_FlowTemplate_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_FlowTemplate_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type FlowTemplate", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Subtask_id(ctx context.Context, field graphql.CollectedField, obj *model.Subtask) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Subtask_id(ctx, field) if err != nil { @@ -29678,6 +30775,40 @@ func (ec *executionContext) unmarshalInputCreateAPITokenInput(ctx context.Contex return it, nil } +func (ec *executionContext) unmarshalInputCreateFlowTemplateInput(ctx context.Context, obj interface{}) (model.CreateFlowTemplateInput, error) { + var it model.CreateFlowTemplateInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"title", "text"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "title": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Title = data + case "text": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("text")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Text = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputModelPriceInput(ctx context.Context, obj interface{}) (model.ModelPrice, error) { var it model.ModelPrice asMap := map[string]interface{}{} @@ -29794,6 +30925,40 @@ func (ec *executionContext) unmarshalInputUpdateAPITokenInput(ctx context.Contex return it, nil } +func (ec *executionContext) unmarshalInputUpdateFlowTemplateInput(ctx context.Context, obj interface{}) (model.UpdateFlowTemplateInput, error) { + var it model.UpdateFlowTemplateInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"title", "text"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "title": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Title = data + case "text": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("text")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Text = data + } + } + + return it, nil +} + // endregion **************************** input.gotpl ***************************** // region ************************** interface.gotpl *************************** @@ -31130,6 +32295,70 @@ func (ec *executionContext) _FlowStats(ctx context.Context, sel ast.SelectionSet return out } +var flowTemplateImplementors = []string{"FlowTemplate"} + +func (ec *executionContext) _FlowTemplate(ctx context.Context, sel ast.SelectionSet, obj *model.FlowTemplate) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, flowTemplateImplementors) + + 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("FlowTemplate") + case "id": + out.Values[i] = ec._FlowTemplate_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "userId": + out.Values[i] = ec._FlowTemplate_userId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "title": + out.Values[i] = ec._FlowTemplate_title(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "text": + out.Values[i] = ec._FlowTemplate_text(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdAt": + out.Values[i] = ec._FlowTemplate_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updatedAt": + out.Values[i] = ec._FlowTemplate_updatedAt(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 flowsStatsImplementors = []string{"FlowsStats"} func (ec *executionContext) _FlowsStats(ctx context.Context, sel ast.SelectionSet, obj *model.FlowsStats) graphql.Marshaler { @@ -31655,6 +32884,27 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "createFlowTemplate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_createFlowTemplate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updateFlowTemplate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateFlowTemplate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deleteFlowTemplate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteFlowTemplate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -32948,6 +34198,47 @@ 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 "flowTemplate": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_flowTemplate(ctx, field) + 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 "flowTemplates": + 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_flowTemplates(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 "__type": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { @@ -33274,6 +34565,12 @@ func (ec *executionContext) _Subscription(ctx context.Context, sel ast.Selection return ec._Subscription_apiTokenDeleted(ctx, fields[0]) case "settingsUserUpdated": return ec._Subscription_settingsUserUpdated(ctx, fields[0]) + case "flowTemplateCreated": + return ec._Subscription_flowTemplateCreated(ctx, fields[0]) + case "flowTemplateUpdated": + return ec._Subscription_flowTemplateUpdated(ctx, fields[0]) + case "flowTemplateDeleted": + return ec._Subscription_flowTemplateDeleted(ctx, fields[0]) default: panic("unknown field " + strconv.Quote(fields[0].Name)) } @@ -34738,6 +36035,11 @@ func (ec *executionContext) unmarshalNCreateAPITokenInput2pentagiᚋpkgᚋgraph return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalNCreateFlowTemplateInput2pentagiᚋpkgᚋgraphᚋmodelᚐCreateFlowTemplateInput(ctx context.Context, v interface{}) (model.CreateFlowTemplateInput, error) { + res, err := ec.unmarshalInputCreateFlowTemplateInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalNDailyFlowsStats2ᚕᚖpentagiᚋpkgᚋgraphᚋmodelᚐDailyFlowsStatsᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DailyFlowsStats) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -35041,6 +36343,64 @@ func (ec *executionContext) marshalNFlowStats2ᚖpentagiᚋpkgᚋgraphᚋmodel return ec._FlowStats(ctx, sel, v) } +func (ec *executionContext) marshalNFlowTemplate2pentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx context.Context, sel ast.SelectionSet, v model.FlowTemplate) graphql.Marshaler { + return ec._FlowTemplate(ctx, sel, &v) +} + +func (ec *executionContext) marshalNFlowTemplate2ᚕᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplateᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.FlowTemplate) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx context.Context, sel ast.SelectionSet, v *model.FlowTemplate) 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._FlowTemplate(ctx, sel, v) +} + func (ec *executionContext) marshalNFlowsStats2pentagiᚋpkgᚋgraphᚋmodelᚐFlowsStats(ctx context.Context, sel ast.SelectionSet, v model.FlowsStats) graphql.Marshaler { return ec._FlowsStats(ctx, sel, &v) } @@ -35924,6 +37284,11 @@ func (ec *executionContext) unmarshalNUpdateAPITokenInput2pentagiᚋpkgᚋgraph return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalNUpdateFlowTemplateInput2pentagiᚋpkgᚋgraphᚋmodelᚐUpdateFlowTemplateInput(ctx context.Context, v interface{}) (model.UpdateFlowTemplateInput, error) { + res, err := ec.unmarshalInputUpdateFlowTemplateInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalNUsageStats2pentagiᚋpkgᚋgraphᚋmodelᚐUsageStats(ctx context.Context, sel ast.SelectionSet, v model.UsageStats) graphql.Marshaler { return ec._UsageStats(ctx, sel, &v) } @@ -36490,6 +37855,13 @@ func (ec *executionContext) marshalOFlow2ᚕᚖpentagiᚋpkgᚋgraphᚋmodelᚐF return ret } +func (ec *executionContext) marshalOFlowTemplate2ᚖpentagiᚋpkgᚋgraphᚋmodelᚐFlowTemplate(ctx context.Context, sel ast.SelectionSet, v *model.FlowTemplate) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._FlowTemplate(ctx, sel, v) +} + func (ec *executionContext) unmarshalOID2ᚖint64(ctx context.Context, v interface{}) (*int64, error) { if v == nil { return nil, nil diff --git a/backend/pkg/graph/model/models_gen.go b/backend/pkg/graph/model/models_gen.go index 3664bcda..35a09dcd 100644 --- a/backend/pkg/graph/model/models_gen.go +++ b/backend/pkg/graph/model/models_gen.go @@ -142,6 +142,11 @@ type CreateAPITokenInput struct { TTL int `json:"ttl"` } +type CreateFlowTemplateInput struct { + Title string `json:"title"` + Text string `json:"text"` +} + type DailyFlowsStats struct { Date time.Time `json:"date"` Stats *FlowsStats `json:"stats"` @@ -211,6 +216,15 @@ type FlowStats struct { TotalAssistantsCount int `json:"totalAssistantsCount"` } +type FlowTemplate struct { + ID int64 `json:"id"` + UserID int64 `json:"userId"` + Title string `json:"title"` + Text string `json:"text"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + type FlowsStats struct { TotalFlowsCount int `json:"totalFlowsCount"` TotalTasksCount int `json:"totalTasksCount"` @@ -478,6 +492,11 @@ type UpdateAPITokenInput struct { Status *TokenStatus `json:"status,omitempty"` } +type UpdateFlowTemplateInput struct { + Title string `json:"title"` + Text string `json:"text"` +} + type UsageStats struct { TotalUsageIn int `json:"totalUsageIn"` TotalUsageOut int `json:"totalUsageOut"` diff --git a/backend/pkg/graph/schema.graphqls b/backend/pkg/graph/schema.graphqls index d2e7a082..19dff49a 100644 --- a/backend/pkg/graph/schema.graphqls +++ b/backend/pkg/graph/schema.graphqls @@ -169,6 +169,27 @@ type UserPreferences { favoriteFlows: [ID!]! } +# ==================== Flow Template Types ==================== + +type FlowTemplate { + id: ID! + userId: ID! + title: String! + text: String! + createdAt: Time! + updatedAt: Time! +} + +input CreateFlowTemplateInput { + title: String! + text: String! +} + +input UpdateFlowTemplateInput { + title: String! + text: String! +} + # ==================== Flow Management Types ==================== type Terminal { @@ -826,6 +847,10 @@ type Query { # API Tokens management apiToken(tokenId: String!): APIToken apiTokens: [APIToken!]! + + # Flow Templates management + flowTemplate(templateId: ID!): FlowTemplate + flowTemplates: [FlowTemplate!]! } type Mutation { @@ -864,6 +889,11 @@ type Mutation { # User preferences management addFavoriteFlow(flowId: ID!): ResultType! deleteFavoriteFlow(flowId: ID!): ResultType! + + # Flow Templates management + createFlowTemplate(input: CreateFlowTemplateInput!): FlowTemplate! + updateFlowTemplate(templateId: ID!, input: UpdateFlowTemplateInput!): FlowTemplate! + deleteFlowTemplate(templateId: ID!): ResultType! } type Subscription { @@ -902,4 +932,9 @@ type Subscription { # User preferences events settingsUserUpdated: UserPreferences! + + # Flow template events + flowTemplateCreated: FlowTemplate! + flowTemplateUpdated: FlowTemplate! + flowTemplateDeleted: FlowTemplate! } diff --git a/backend/pkg/graph/schema.resolvers.go b/backend/pkg/graph/schema.resolvers.go index 340b1208..610ede42 100644 --- a/backend/pkg/graph/schema.resolvers.go +++ b/backend/pkg/graph/schema.resolvers.go @@ -937,6 +937,127 @@ func (r *mutationResolver) DeleteFavoriteFlow(ctx context.Context, flowID int64) return model.ResultTypeSuccess, nil } +// CreateFlowTemplate is the resolver for the createFlowTemplate field. +func (r *mutationResolver) CreateFlowTemplate(ctx context.Context, input model.CreateFlowTemplateInput) (*model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.create") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to create templates") + } + + r.Logger.WithFields(logrus.Fields{ + "uid": uid, + "title": input.Title, + }).Debug("create flow template") + + template, err := r.DB.CreateFlowTemplate(ctx, database.CreateFlowTemplateParams{ + UserID: uid, + Title: input.Title, + Text: input.Text, + }) + if err != nil { + return nil, fmt.Errorf("failed to create template: %w", err) + } + + r.Subscriptions.NewFlowPublisher(uid, 0).FlowTemplateCreated(ctx, template) + + return converter.ConvertFlowTemplate(template), nil +} + +// UpdateFlowTemplate is the resolver for the updateFlowTemplate field. +func (r *mutationResolver) UpdateFlowTemplate(ctx context.Context, templateID int64, input model.UpdateFlowTemplateInput) (*model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.edit") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to update templates") + } + + r.Logger.WithFields(logrus.Fields{ + "uid": uid, + "templateID": templateID, + }).Debug("update flow template") + + _, err = r.DB.GetFlowTemplate(ctx, database.GetFlowTemplateParams{ + ID: templateID, + UserID: uid, + }) + if err != nil { + return nil, fmt.Errorf("template not found: %w", err) + } + + template, err := r.DB.UpdateFlowTemplate(ctx, database.UpdateFlowTemplateParams{ + ID: templateID, + UserID: uid, + Title: input.Title, + Text: input.Text, + }) + if err != nil { + return nil, fmt.Errorf("failed to update template: %w", err) + } + + r.Subscriptions.NewFlowPublisher(uid, 0).FlowTemplateUpdated(ctx, template) + + return converter.ConvertFlowTemplate(template), nil +} + +// DeleteFlowTemplate is the resolver for the deleteFlowTemplate field. +func (r *mutationResolver) DeleteFlowTemplate(ctx context.Context, templateID int64) (model.ResultType, error) { + uid, _, err := validatePermission(ctx, "templates.delete") + if err != nil { + return model.ResultTypeError, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return model.ResultTypeError, err + } + + if !isUserSession { + return model.ResultTypeError, fmt.Errorf("unauthorized: non-user session is not allowed to delete templates") + } + + r.Logger.WithFields(logrus.Fields{ + "uid": uid, + "templateID": templateID, + }).Debug("delete flow template") + + template, err := r.DB.GetFlowTemplate(ctx, database.GetFlowTemplateParams{ + ID: templateID, + UserID: uid, + }) + if err != nil { + return model.ResultTypeError, fmt.Errorf("template not found: %w", err) + } + + err = r.DB.DeleteFlowTemplate(ctx, database.DeleteFlowTemplateParams{ + ID: templateID, + UserID: uid, + }) + if err != nil { + return model.ResultTypeError, fmt.Errorf("failed to delete template: %w", err) + } + + r.Subscriptions.NewFlowPublisher(uid, 0).FlowTemplateDeleted(ctx, template) + + return model.ResultTypeSuccess, nil +} + // Providers is the resolver for the providers field. func (r *queryResolver) Providers(ctx context.Context) ([]*model.Provider, error) { uid, _, err := validatePermission(ctx, "providers.view") @@ -1953,6 +2074,69 @@ func (r *queryResolver) APITokens(ctx context.Context) ([]*model.APIToken, error return converter.ConvertAPITokens(tokens), nil } +// FlowTemplate is the resolver for the flowTemplate field. +func (r *queryResolver) FlowTemplate(ctx context.Context, templateID int64) (*model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.view") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to view templates") + } + + r.Logger.WithFields(logrus.Fields{ + "uid": uid, + "templateID": templateID, + }).Debug("get flow template") + + template, err := r.DB.GetFlowTemplate(ctx, database.GetFlowTemplateParams{ + ID: templateID, + UserID: uid, + }) + if err != nil { + if err == sql.ErrNoRows { + return nil, fmt.Errorf("template not found") + } + return nil, fmt.Errorf("failed to get template: %w", err) + } + + return converter.ConvertFlowTemplate(template), nil +} + +// FlowTemplates is the resolver for the flowTemplates field. +func (r *queryResolver) FlowTemplates(ctx context.Context) ([]*model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.view") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to view templates") + } + + r.Logger.WithFields(logrus.Fields{ + "uid": uid, + }).Debug("get flow templates") + + templates, err := r.DB.GetFlowTemplatesByUserID(ctx, uid) + if err != nil { + return nil, fmt.Errorf("failed to get templates: %w", err) + } + + return converter.ConvertFlowTemplates(templates), nil +} + // FlowCreated is the resolver for the flowCreated field. func (r *subscriptionResolver) FlowCreated(ctx context.Context) (<-chan *model.Flow, error) { uid, admin, err := validatePermission(ctx, "flows.subscribe") @@ -2244,6 +2428,63 @@ func (r *subscriptionResolver) SettingsUserUpdated(ctx context.Context) (<-chan return r.Subscriptions.NewFlowSubscriber(uid, 0).SettingsUserUpdated(ctx) } +// FlowTemplateCreated is the resolver for the flowTemplateCreated field. +func (r *subscriptionResolver) FlowTemplateCreated(ctx context.Context) (<-chan *model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.subscribe") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to subscribe to templates") + } + + return r.Subscriptions.NewFlowSubscriber(uid, 0).FlowTemplateCreated(ctx) +} + +// FlowTemplateUpdated is the resolver for the flowTemplateUpdated field. +func (r *subscriptionResolver) FlowTemplateUpdated(ctx context.Context) (<-chan *model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.subscribe") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to subscribe to templates") + } + + return r.Subscriptions.NewFlowSubscriber(uid, 0).FlowTemplateUpdated(ctx) +} + +// FlowTemplateDeleted is the resolver for the flowTemplateDeleted field. +func (r *subscriptionResolver) FlowTemplateDeleted(ctx context.Context) (<-chan *model.FlowTemplate, error) { + uid, _, err := validatePermission(ctx, "templates.subscribe") + if err != nil { + return nil, err + } + + isUserSession, err := validateUserType(ctx, userSessionTypes...) + if err != nil { + return nil, err + } + + if !isUserSession { + return nil, fmt.Errorf("unauthorized: non-user session is not allowed to subscribe to templates") + } + + return r.Subscriptions.NewFlowSubscriber(uid, 0).FlowTemplateDeleted(ctx) +} + // Mutation returns MutationResolver implementation. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } diff --git a/backend/pkg/graph/subscriptions/controller.go b/backend/pkg/graph/subscriptions/controller.go index c8f63a0b..0b8b438d 100644 --- a/backend/pkg/graph/subscriptions/controller.go +++ b/backend/pkg/graph/subscriptions/controller.go @@ -55,6 +55,9 @@ type FlowSubscriber interface { APITokenUpdated(ctx context.Context) (<-chan *model.APIToken, error) APITokenDeleted(ctx context.Context) (<-chan *model.APIToken, error) SettingsUserUpdated(ctx context.Context) (<-chan *model.UserPreferences, error) + FlowTemplateCreated(ctx context.Context) (<-chan *model.FlowTemplate, error) + FlowTemplateUpdated(ctx context.Context) (<-chan *model.FlowTemplate, error) + FlowTemplateDeleted(ctx context.Context) (<-chan *model.FlowTemplate, error) FlowContext } @@ -83,6 +86,9 @@ type FlowPublisher interface { APITokenUpdated(ctx context.Context, apiToken database.ApiToken) APITokenDeleted(ctx context.Context, apiToken database.ApiToken) SettingsUserUpdated(ctx context.Context, userPreferences database.UserPreference) + FlowTemplateCreated(ctx context.Context, template database.FlowTemplate) + FlowTemplateUpdated(ctx context.Context, template database.FlowTemplate) + FlowTemplateDeleted(ctx context.Context, template database.FlowTemplate) FlowContext } @@ -114,6 +120,9 @@ type controller struct { apiTokenUpdated Channel[*model.APIToken] apiTokenDeleted Channel[*model.APIToken] settingsUserUpdated Channel[*model.UserPreferences] + flowTemplateCreated Channel[*model.FlowTemplate] + flowTemplateUpdated Channel[*model.FlowTemplate] + flowTemplateDeleted Channel[*model.FlowTemplate] } func NewSubscriptionsController() SubscriptionsController { @@ -145,6 +154,9 @@ func NewSubscriptionsController() SubscriptionsController { apiTokenUpdated: NewChannel[*model.APIToken](), apiTokenDeleted: NewChannel[*model.APIToken](), settingsUserUpdated: NewChannel[*model.UserPreferences](), + flowTemplateCreated: NewChannel[*model.FlowTemplate](), + flowTemplateUpdated: NewChannel[*model.FlowTemplate](), + flowTemplateDeleted: NewChannel[*model.FlowTemplate](), } } diff --git a/backend/pkg/graph/subscriptions/publisher.go b/backend/pkg/graph/subscriptions/publisher.go index 1cd22a3b..5cef04a7 100644 --- a/backend/pkg/graph/subscriptions/publisher.go +++ b/backend/pkg/graph/subscriptions/publisher.go @@ -131,3 +131,15 @@ func (p *flowPublisher) APITokenDeleted(ctx context.Context, apiToken database.A func (p *flowPublisher) SettingsUserUpdated(ctx context.Context, userPreferences database.UserPreference) { p.ctrl.settingsUserUpdated.Publish(ctx, p.userID, converter.ConvertUserPreferences(userPreferences)) } + +func (p *flowPublisher) FlowTemplateCreated(ctx context.Context, template database.FlowTemplate) { + p.ctrl.flowTemplateCreated.Publish(ctx, p.userID, converter.ConvertFlowTemplate(template)) +} + +func (p *flowPublisher) FlowTemplateUpdated(ctx context.Context, template database.FlowTemplate) { + p.ctrl.flowTemplateUpdated.Publish(ctx, p.userID, converter.ConvertFlowTemplate(template)) +} + +func (p *flowPublisher) FlowTemplateDeleted(ctx context.Context, template database.FlowTemplate) { + p.ctrl.flowTemplateDeleted.Publish(ctx, p.userID, converter.ConvertFlowTemplate(template)) +} diff --git a/backend/pkg/graph/subscriptions/subscriber.go b/backend/pkg/graph/subscriptions/subscriber.go index 1394d208..33e2033c 100644 --- a/backend/pkg/graph/subscriptions/subscriber.go +++ b/backend/pkg/graph/subscriptions/subscriber.go @@ -135,3 +135,15 @@ func (s *flowSubscriber) APITokenDeleted(ctx context.Context) (<-chan *model.API func (s *flowSubscriber) SettingsUserUpdated(ctx context.Context) (<-chan *model.UserPreferences, error) { return s.ctrl.settingsUserUpdated.Subscribe(ctx, s.userID), nil } + +func (s *flowSubscriber) FlowTemplateCreated(ctx context.Context) (<-chan *model.FlowTemplate, error) { + return s.ctrl.flowTemplateCreated.Subscribe(ctx, s.userID), nil +} + +func (s *flowSubscriber) FlowTemplateUpdated(ctx context.Context) (<-chan *model.FlowTemplate, error) { + return s.ctrl.flowTemplateUpdated.Subscribe(ctx, s.userID), nil +} + +func (s *flowSubscriber) FlowTemplateDeleted(ctx context.Context) (<-chan *model.FlowTemplate, error) { + return s.ctrl.flowTemplateDeleted.Subscribe(ctx, s.userID), nil +} diff --git a/backend/pkg/server/router.go b/backend/pkg/server/router.go index 71542c5e..4e5404c3 100644 --- a/backend/pkg/server/router.go +++ b/backend/pkg/server/router.go @@ -48,6 +48,8 @@ var frontendRoutes = []string{ "/login", "/flows", "/settings", + "/templates", + "/dashboard", } // @title PentAGI Swagger API diff --git a/backend/sqlc/models/flow_templates.sql b/backend/sqlc/models/flow_templates.sql new file mode 100644 index 00000000..5f7cdcad --- /dev/null +++ b/backend/sqlc/models/flow_templates.sql @@ -0,0 +1,32 @@ +-- name: GetFlowTemplate :one +SELECT * FROM flow_templates +WHERE id = $1 AND user_id = $2 LIMIT 1; + +-- name: GetFlowTemplatesByUserID :many +SELECT * FROM flow_templates +WHERE user_id = $1 +ORDER BY created_at DESC; + +-- name: CreateFlowTemplate :one +INSERT INTO flow_templates ( + user_id, + title, + text +) VALUES ( + $1, + $2, + $3 +) +RETURNING *; + +-- name: UpdateFlowTemplate :one +UPDATE flow_templates +SET + title = $3, + text = $4 +WHERE id = $1 AND user_id = $2 +RETURNING *; + +-- name: DeleteFlowTemplate :exec +DELETE FROM flow_templates +WHERE id = $1 AND user_id = $2; diff --git a/frontend/graphql-schema.graphql b/frontend/graphql-schema.graphql index b9f57412..66afa645 100644 --- a/frontend/graphql-schema.graphql +++ b/frontend/graphql-schema.graphql @@ -350,6 +350,15 @@ fragment apiTokenWithSecretFragment on APITokenWithSecret { token } +fragment flowTemplateFragment on FlowTemplate { + id + userId + title + text + createdAt + updatedAt +} + fragment usageStatsFragment on UsageStats { totalUsageIn totalUsageOut @@ -906,6 +915,38 @@ mutation deleteFavoriteFlow($flowId: ID!) { deleteFavoriteFlow(flowId: $flowId) } +# ==================== Flow Templates ==================== + +query flowTemplates { + flowTemplates { + ...flowTemplateFragment + } +} + +query flowTemplate($templateId: ID!) { + flowTemplate(templateId: $templateId) { + ...flowTemplateFragment + } +} + +mutation createFlowTemplate($input: CreateFlowTemplateInput!) { + createFlowTemplate(input: $input) { + ...flowTemplateFragment + } +} + +mutation updateFlowTemplate($templateId: ID!, $input: UpdateFlowTemplateInput!) { + updateFlowTemplate(templateId: $templateId, input: $input) { + ...flowTemplateFragment + } +} + +mutation deleteFlowTemplate($templateId: ID!) { + deleteFlowTemplate(templateId: $templateId) +} + +# ==================== Flows ==================== + mutation createFlow($modelProvider: String!, $input: String!) { createFlow(modelProvider: $modelProvider, input: $input) { ...flowFragment @@ -1174,3 +1215,21 @@ subscription settingsUserUpdated { ...userPreferencesFragment } } + +subscription flowTemplateCreated { + flowTemplateCreated { + ...flowTemplateFragment + } +} + +subscription flowTemplateUpdated { + flowTemplateUpdated { + ...flowTemplateFragment + } +} + +subscription flowTemplateDeleted { + flowTemplateDeleted { + ...flowTemplateFragment + } +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c34934a4..4573660a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5805,6 +5805,7 @@ "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -5814,7 +5815,7 @@ "version": "19.2.2", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -17519,7 +17520,7 @@ "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/frontend/src/graphql/types.ts b/frontend/src/graphql/types.ts index becda8a8..0edfd31a 100644 --- a/frontend/src/graphql/types.ts +++ b/frontend/src/graphql/types.ts @@ -216,6 +216,11 @@ export type CreateApiTokenInput = { ttl: Scalars['Int']['input']; }; +export type CreateFlowTemplateInput = { + text: Scalars['String']['input']; + title: Scalars['String']['input']; +}; + export type DailyFlowsStats = { date: Scalars['Time']['output']; stats: FlowsStats; @@ -285,6 +290,15 @@ export type FlowStats = { totalTasksCount: Scalars['Int']['output']; }; +export type FlowTemplate = { + createdAt: Scalars['Time']['output']; + id: Scalars['ID']['output']; + text: Scalars['String']['output']; + title: Scalars['String']['output']; + updatedAt: Scalars['Time']['output']; + userId: Scalars['ID']['output']; +}; + export type FlowsStats = { totalAssistantsCount: Scalars['Int']['output']; totalFlowsCount: Scalars['Int']['output']; @@ -361,12 +375,14 @@ export type Mutation = { createAPIToken: ApiTokenWithSecret; createAssistant: FlowAssistant; createFlow: Flow; + createFlowTemplate: FlowTemplate; createPrompt: UserPrompt; createProvider: ProviderConfig; deleteAPIToken: Scalars['Boolean']['output']; deleteAssistant: ResultType; deleteFavoriteFlow: ResultType; deleteFlow: ResultType; + deleteFlowTemplate: ResultType; deletePrompt: ResultType; deleteProvider: ResultType; finishFlow: ResultType; @@ -377,6 +393,7 @@ export type Mutation = { testAgent: AgentTestResult; testProvider: ProviderTestResult; updateAPIToken: ApiToken; + updateFlowTemplate: FlowTemplate; updatePrompt: UserPrompt; updateProvider: ProviderConfig; validatePrompt: PromptValidationResult; @@ -409,6 +426,10 @@ export type MutationCreateFlowArgs = { modelProvider: Scalars['String']['input']; }; +export type MutationCreateFlowTemplateArgs = { + input: CreateFlowTemplateInput; +}; + export type MutationCreatePromptArgs = { template: Scalars['String']['input']; type: PromptType; @@ -437,6 +458,10 @@ export type MutationDeleteFlowArgs = { flowId: Scalars['ID']['input']; }; +export type MutationDeleteFlowTemplateArgs = { + templateId: Scalars['ID']['input']; +}; + export type MutationDeletePromptArgs = { promptId: Scalars['ID']['input']; }; @@ -484,6 +509,11 @@ export type MutationUpdateApiTokenArgs = { tokenId: Scalars['String']['input']; }; +export type MutationUpdateFlowTemplateArgs = { + input: UpdateFlowTemplateInput; + templateId: Scalars['ID']['input']; +}; + export type MutationUpdatePromptArgs = { promptId: Scalars['ID']['input']; template: Scalars['String']['input']; @@ -653,6 +683,8 @@ export type Query = { assistants?: Maybe>; flow: Flow; flowStatsByFlow: FlowStats; + flowTemplate?: Maybe; + flowTemplates: Array; flows?: Maybe>; flowsExecutionStatsByPeriod: Array; flowsStatsByPeriod: Array; @@ -707,6 +739,10 @@ export type QueryFlowStatsByFlowArgs = { flowId: Scalars['ID']['input']; }; +export type QueryFlowTemplateArgs = { + templateId: Scalars['ID']['input']; +}; + export type QueryFlowsExecutionStatsByPeriodArgs = { period: UsageStatsPeriod; }; @@ -840,6 +876,9 @@ export type Subscription = { assistantUpdated: Assistant; flowCreated: Flow; flowDeleted: Flow; + flowTemplateCreated: FlowTemplate; + flowTemplateDeleted: FlowTemplate; + flowTemplateUpdated: FlowTemplate; flowUpdated: Flow; messageLogAdded: MessageLog; messageLogUpdated: MessageLog; @@ -1021,6 +1060,11 @@ export type UpdateApiTokenInput = { status?: InputMaybe; }; +export type UpdateFlowTemplateInput = { + text: Scalars['String']['input']; + title: Scalars['String']['input']; +}; + export type UsageStats = { totalUsageCacheIn: Scalars['Int']['output']; totalUsageCacheOut: Scalars['Int']['output']; @@ -1332,6 +1376,15 @@ export type ApiTokenWithSecretFragmentFragment = { token: string; }; +export type FlowTemplateFragmentFragment = { + id: string; + userId: string; + title: string; + text: string; + createdAt: any; + updatedAt: any; +}; + export type UsageStatsFragmentFragment = { totalUsageIn: number; totalUsageOut: number; @@ -1653,6 +1706,35 @@ export type DeleteFavoriteFlowMutationVariables = Exact<{ export type DeleteFavoriteFlowMutation = { deleteFavoriteFlow: ResultType }; +export type FlowTemplatesQueryVariables = Exact<{ [key: string]: never }>; + +export type FlowTemplatesQuery = { flowTemplates: Array }; + +export type FlowTemplateQueryVariables = Exact<{ + templateId: Scalars['ID']['input']; +}>; + +export type FlowTemplateQuery = { flowTemplate?: FlowTemplateFragmentFragment | null }; + +export type CreateFlowTemplateMutationVariables = Exact<{ + input: CreateFlowTemplateInput; +}>; + +export type CreateFlowTemplateMutation = { createFlowTemplate: FlowTemplateFragmentFragment }; + +export type UpdateFlowTemplateMutationVariables = Exact<{ + templateId: Scalars['ID']['input']; + input: UpdateFlowTemplateInput; +}>; + +export type UpdateFlowTemplateMutation = { updateFlowTemplate: FlowTemplateFragmentFragment }; + +export type DeleteFlowTemplateMutationVariables = Exact<{ + templateId: Scalars['ID']['input']; +}>; + +export type DeleteFlowTemplateMutation = { deleteFlowTemplate: ResultType }; + export type CreateFlowMutationVariables = Exact<{ modelProvider: Scalars['String']['input']; input: Scalars['String']['input']; @@ -1941,6 +2023,18 @@ export type SettingsUserUpdatedSubscriptionVariables = Exact<{ [key: string]: ne export type SettingsUserUpdatedSubscription = { settingsUserUpdated: UserPreferencesFragmentFragment }; +export type FlowTemplateCreatedSubscriptionVariables = Exact<{ [key: string]: never }>; + +export type FlowTemplateCreatedSubscription = { flowTemplateCreated: FlowTemplateFragmentFragment }; + +export type FlowTemplateUpdatedSubscriptionVariables = Exact<{ [key: string]: never }>; + +export type FlowTemplateUpdatedSubscription = { flowTemplateUpdated: FlowTemplateFragmentFragment }; + +export type FlowTemplateDeletedSubscriptionVariables = Exact<{ [key: string]: never }>; + +export type FlowTemplateDeletedSubscription = { flowTemplateDeleted: FlowTemplateFragmentFragment }; + export const SettingsFragmentFragmentDoc = gql` fragment settingsFragment on Settings { debug @@ -1979,6 +2073,8 @@ export const FlowFragmentFragmentDoc = gql` createdAt updatedAt } + ${TerminalFragmentFragmentDoc} + ${ProviderFragmentFragmentDoc} `; export const SubtaskFragmentFragmentDoc = gql` fragment subtaskFragment on Subtask { @@ -2006,6 +2102,7 @@ export const TaskFragmentFragmentDoc = gql` createdAt updatedAt } + ${SubtaskFragmentFragmentDoc} `; export const TerminalLogFragmentFragmentDoc = gql` fragment terminalLogFragment on TerminalLog { @@ -2099,6 +2196,7 @@ export const AssistantFragmentFragmentDoc = gql` createdAt updatedAt } + ${ProviderFragmentFragmentDoc} `; export const AssistantLogFragmentFragmentDoc = gql` fragment assistantLogFragment on AssistantLog { @@ -2131,6 +2229,7 @@ export const AgentTestResultFragmentFragmentDoc = gql` ...testResultFragment } } + ${TestResultFragmentFragmentDoc} `; export const ProviderTestResultFragmentFragmentDoc = gql` fragment providerTestResultFragment on ProviderTestResult { @@ -2174,6 +2273,7 @@ export const ProviderTestResultFragmentFragmentDoc = gql` ...agentTestResultFragment } } + ${AgentTestResultFragmentFragmentDoc} `; export const ModelConfigFragmentFragmentDoc = gql` fragment modelConfigFragment on ModelConfig { @@ -2252,6 +2352,7 @@ export const AgentsConfigFragmentFragmentDoc = gql` ...agentConfigFragment } } + ${AgentConfigFragmentFragmentDoc} `; export const ProviderConfigFragmentFragmentDoc = gql` fragment providerConfigFragment on ProviderConfig { @@ -2264,6 +2365,7 @@ export const ProviderConfigFragmentFragmentDoc = gql` createdAt updatedAt } + ${AgentsConfigFragmentFragmentDoc} `; export const UserPromptFragmentFragmentDoc = gql` fragment userPromptFragment on UserPrompt { @@ -2317,6 +2419,16 @@ export const ApiTokenWithSecretFragmentFragmentDoc = gql` token } `; +export const FlowTemplateFragmentFragmentDoc = gql` + fragment flowTemplateFragment on FlowTemplate { + id + userId + title + text + createdAt + updatedAt + } +`; export const UsageStatsFragmentFragmentDoc = gql` fragment usageStatsFragment on UsageStats { totalUsageIn @@ -2334,6 +2446,7 @@ export const DailyUsageStatsFragmentFragmentDoc = gql` ...usageStatsFragment } } + ${UsageStatsFragmentFragmentDoc} `; export const ProviderUsageStatsFragmentFragmentDoc = gql` fragment providerUsageStatsFragment on ProviderUsageStats { @@ -2342,6 +2455,7 @@ export const ProviderUsageStatsFragmentFragmentDoc = gql` ...usageStatsFragment } } + ${UsageStatsFragmentFragmentDoc} `; export const ModelUsageStatsFragmentFragmentDoc = gql` fragment modelUsageStatsFragment on ModelUsageStats { @@ -2351,6 +2465,7 @@ export const ModelUsageStatsFragmentFragmentDoc = gql` ...usageStatsFragment } } + ${UsageStatsFragmentFragmentDoc} `; export const AgentTypeUsageStatsFragmentFragmentDoc = gql` fragment agentTypeUsageStatsFragment on AgentTypeUsageStats { @@ -2359,6 +2474,7 @@ export const AgentTypeUsageStatsFragmentFragmentDoc = gql` ...usageStatsFragment } } + ${UsageStatsFragmentFragmentDoc} `; export const ToolcallsStatsFragmentFragmentDoc = gql` fragment toolcallsStatsFragment on ToolcallsStats { @@ -2373,6 +2489,7 @@ export const DailyToolcallsStatsFragmentFragmentDoc = gql` ...toolcallsStatsFragment } } + ${ToolcallsStatsFragmentFragmentDoc} `; export const FunctionToolcallsStatsFragmentFragmentDoc = gql` fragment functionToolcallsStatsFragment on FunctionToolcallsStats { @@ -2405,6 +2522,7 @@ export const DailyFlowsStatsFragmentFragmentDoc = gql` ...flowsStatsFragment } } + ${FlowsStatsFragmentFragmentDoc} `; export const SubtaskExecutionStatsFragmentFragmentDoc = gql` fragment subtaskExecutionStatsFragment on SubtaskExecutionStats { @@ -2424,6 +2542,7 @@ export const TaskExecutionStatsFragmentFragmentDoc = gql` ...subtaskExecutionStatsFragment } } + ${SubtaskExecutionStatsFragmentFragmentDoc} `; export const FlowExecutionStatsFragmentFragmentDoc = gql` fragment flowExecutionStatsFragment on FlowExecutionStats { @@ -2436,6 +2555,7 @@ export const FlowExecutionStatsFragmentFragmentDoc = gql` ...taskExecutionStatsFragment } } + ${TaskExecutionStatsFragmentFragmentDoc} `; export const UserPreferencesFragmentFragmentDoc = gql` fragment userPreferencesFragment on UserPreferences { @@ -2450,8 +2570,6 @@ export const FlowsDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -2477,6 +2595,13 @@ export function useFlowsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions(FlowsDocument, options); } +// @ts-ignore +export function useFlowsSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowsSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useFlowsSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -2521,6 +2646,13 @@ export function useProvidersLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(ProvidersDocument, options); } +// @ts-ignore +export function useProvidersSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useProvidersSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useProvidersSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -2563,6 +2695,13 @@ export function useSettingsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions(SettingsDocument, options); } +// @ts-ignore +export function useSettingsSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useSettingsSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useSettingsSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -2658,8 +2797,6 @@ export const SettingsProvidersDocument = gql` } } ${ProviderConfigFragmentFragmentDoc} - ${AgentsConfigFragmentFragmentDoc} - ${AgentConfigFragmentFragmentDoc} ${ModelConfigFragmentFragmentDoc} `; @@ -2693,6 +2830,15 @@ export function useSettingsProvidersLazyQuery( options, ); } +// @ts-ignore +export function useSettingsProvidersSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useSettingsProvidersSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useSettingsProvidersSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -2900,6 +3046,15 @@ export function useSettingsPromptsLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(SettingsPromptsDocument, options); } +// @ts-ignore +export function useSettingsPromptsSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useSettingsPromptsSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useSettingsPromptsSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -2943,10 +3098,7 @@ export const FlowDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} ${TaskFragmentFragmentDoc} - ${SubtaskFragmentFragmentDoc} ${ScreenshotFragmentFragmentDoc} ${TerminalLogFragmentFragmentDoc} ${MessageLogFragmentFragmentDoc} @@ -2982,6 +3134,13 @@ export function useFlowLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions(FlowDocument, options); } +// @ts-ignore +export function useFlowSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useFlowSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -2999,7 +3158,6 @@ export const TasksDocument = gql` } } ${TaskFragmentFragmentDoc} - ${SubtaskFragmentFragmentDoc} `; /** @@ -3029,6 +3187,13 @@ export function useTasksLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions(TasksDocument, options); } +// @ts-ignore +export function useTasksSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useTasksSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useTasksSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -3046,7 +3211,6 @@ export const AssistantsDocument = gql` } } ${AssistantFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -3078,6 +3242,13 @@ export function useAssistantsLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(AssistantsDocument, options); } +// @ts-ignore +export function useAssistantsSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useAssistantsSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useAssistantsSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -3127,6 +3298,13 @@ export function useAssistantLogsLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(AssistantLogsDocument, options); } +// @ts-ignore +export function useAssistantLogsSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useAssistantLogsSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useAssistantLogsSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -3147,10 +3325,7 @@ export const FlowReportDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} ${TaskFragmentFragmentDoc} - ${SubtaskFragmentFragmentDoc} `; /** @@ -3182,6 +3357,13 @@ export function useFlowReportLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(FlowReportDocument, options); } +// @ts-ignore +export function useFlowReportSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowReportSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useFlowReportSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -3228,6 +3410,15 @@ export function useUsageStatsTotalLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(UsageStatsTotalDocument, options); } +// @ts-ignore +export function useUsageStatsTotalSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsTotalSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useUsageStatsTotalSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3250,7 +3441,6 @@ export const UsageStatsByPeriodDocument = gql` } } ${DailyUsageStatsFragmentFragmentDoc} - ${UsageStatsFragmentFragmentDoc} `; /** @@ -3288,6 +3478,15 @@ export function useUsageStatsByPeriodLazyQuery( options, ); } +// @ts-ignore +export function useUsageStatsByPeriodSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsByPeriodSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useUsageStatsByPeriodSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3313,7 +3512,6 @@ export const UsageStatsByProviderDocument = gql` } } ${ProviderUsageStatsFragmentFragmentDoc} - ${UsageStatsFragmentFragmentDoc} `; /** @@ -3349,6 +3547,15 @@ export function useUsageStatsByProviderLazyQuery( options, ); } +// @ts-ignore +export function useUsageStatsByProviderSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsByProviderSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useUsageStatsByProviderSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3374,7 +3581,6 @@ export const UsageStatsByModelDocument = gql` } } ${ModelUsageStatsFragmentFragmentDoc} - ${UsageStatsFragmentFragmentDoc} `; /** @@ -3407,6 +3613,15 @@ export function useUsageStatsByModelLazyQuery( options, ); } +// @ts-ignore +export function useUsageStatsByModelSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsByModelSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useUsageStatsByModelSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3429,7 +3644,6 @@ export const UsageStatsByAgentTypeDocument = gql` } } ${AgentTypeUsageStatsFragmentFragmentDoc} - ${UsageStatsFragmentFragmentDoc} `; /** @@ -3465,6 +3679,15 @@ export function useUsageStatsByAgentTypeLazyQuery( options, ); } +// @ts-ignore +export function useUsageStatsByAgentTypeSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsByAgentTypeSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useUsageStatsByAgentTypeSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3524,6 +3747,15 @@ export function useUsageStatsByFlowLazyQuery( options, ); } +// @ts-ignore +export function useUsageStatsByFlowSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsByFlowSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useUsageStatsByFlowSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3546,7 +3778,6 @@ export const UsageStatsByAgentTypeForFlowDocument = gql` } } ${AgentTypeUsageStatsFragmentFragmentDoc} - ${UsageStatsFragmentFragmentDoc} `; /** @@ -3590,6 +3821,24 @@ export function useUsageStatsByAgentTypeForFlowLazyQuery( options, ); } +// @ts-ignore +export function useUsageStatsByAgentTypeForFlowSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions< + UsageStatsByAgentTypeForFlowQuery, + UsageStatsByAgentTypeForFlowQueryVariables + >, +): Apollo.UseSuspenseQueryResult; +export function useUsageStatsByAgentTypeForFlowSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions< + UsageStatsByAgentTypeForFlowQuery, + UsageStatsByAgentTypeForFlowQueryVariables + >, +): Apollo.UseSuspenseQueryResult< + UsageStatsByAgentTypeForFlowQuery | undefined, + UsageStatsByAgentTypeForFlowQueryVariables +>; export function useUsageStatsByAgentTypeForFlowSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3657,6 +3906,15 @@ export function useToolcallsStatsTotalLazyQuery( options, ); } +// @ts-ignore +export function useToolcallsStatsTotalSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useToolcallsStatsTotalSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useToolcallsStatsTotalSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3682,7 +3940,6 @@ export const ToolcallsStatsByPeriodDocument = gql` } } ${DailyToolcallsStatsFragmentFragmentDoc} - ${ToolcallsStatsFragmentFragmentDoc} `; /** @@ -3720,6 +3977,15 @@ export function useToolcallsStatsByPeriodLazyQuery( options, ); } +// @ts-ignore +export function useToolcallsStatsByPeriodSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useToolcallsStatsByPeriodSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useToolcallsStatsByPeriodSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3780,6 +4046,18 @@ export function useToolcallsStatsByFunctionLazyQuery( options, ); } +// @ts-ignore +export function useToolcallsStatsByFunctionSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions< + ToolcallsStatsByFunctionQuery, + ToolcallsStatsByFunctionQueryVariables + >, +): Apollo.UseSuspenseQueryResult; +export function useToolcallsStatsByFunctionSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useToolcallsStatsByFunctionSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3844,6 +4122,15 @@ export function useToolcallsStatsByFlowLazyQuery( options, ); } +// @ts-ignore +export function useToolcallsStatsByFlowSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useToolcallsStatsByFlowSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useToolcallsStatsByFlowSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3912,6 +4199,24 @@ export function useToolcallsStatsByFunctionForFlowLazyQuery( options, ); } +// @ts-ignore +export function useToolcallsStatsByFunctionForFlowSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions< + ToolcallsStatsByFunctionForFlowQuery, + ToolcallsStatsByFunctionForFlowQueryVariables + >, +): Apollo.UseSuspenseQueryResult; +export function useToolcallsStatsByFunctionForFlowSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions< + ToolcallsStatsByFunctionForFlowQuery, + ToolcallsStatsByFunctionForFlowQueryVariables + >, +): Apollo.UseSuspenseQueryResult< + ToolcallsStatsByFunctionForFlowQuery | undefined, + ToolcallsStatsByFunctionForFlowQueryVariables +>; export function useToolcallsStatsByFunctionForFlowSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3973,6 +4278,15 @@ export function useFlowsStatsTotalLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(FlowsStatsTotalDocument, options); } +// @ts-ignore +export function useFlowsStatsTotalSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowsStatsTotalSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useFlowsStatsTotalSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -3995,7 +4309,6 @@ export const FlowsStatsByPeriodDocument = gql` } } ${DailyFlowsStatsFragmentFragmentDoc} - ${FlowsStatsFragmentFragmentDoc} `; /** @@ -4033,6 +4346,15 @@ export function useFlowsStatsByPeriodLazyQuery( options, ); } +// @ts-ignore +export function useFlowsStatsByPeriodSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowsStatsByPeriodSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useFlowsStatsByPeriodSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -4089,6 +4411,15 @@ export function useFlowStatsByFlowLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(FlowStatsByFlowDocument, options); } +// @ts-ignore +export function useFlowStatsByFlowSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowStatsByFlowSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useFlowStatsByFlowSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -4111,8 +4442,6 @@ export const FlowsExecutionStatsByPeriodDocument = gql` } } ${FlowExecutionStatsFragmentFragmentDoc} - ${TaskExecutionStatsFragmentFragmentDoc} - ${SubtaskExecutionStatsFragmentFragmentDoc} `; /** @@ -4153,6 +4482,21 @@ export function useFlowsExecutionStatsByPeriodLazyQuery( options, ); } +// @ts-ignore +export function useFlowsExecutionStatsByPeriodSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions< + FlowsExecutionStatsByPeriodQuery, + FlowsExecutionStatsByPeriodQueryVariables + >, +): Apollo.UseSuspenseQueryResult; +export function useFlowsExecutionStatsByPeriodSuspenseQuery( + baseOptions?: + | Apollo.SkipToken + | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult< + FlowsExecutionStatsByPeriodQuery | undefined, + FlowsExecutionStatsByPeriodQueryVariables +>; export function useFlowsExecutionStatsByPeriodSuspenseQuery( baseOptions?: | Apollo.SkipToken @@ -4207,6 +4551,13 @@ export function useApiTokensLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(ApiTokensDocument, options); } +// @ts-ignore +export function useApiTokensSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useApiTokensSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useApiTokensSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -4253,6 +4604,13 @@ export function useApiTokenLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions(ApiTokenDocument, options); } +// @ts-ignore +export function useApiTokenSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useApiTokenSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useApiTokenSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -4299,6 +4657,13 @@ export function useSettingsUserLazyQuery( const options = { ...defaultOptions, ...baseOptions }; return Apollo.useLazyQuery(SettingsUserDocument, options); } +// @ts-ignore +export function useSettingsUserSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useSettingsUserSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; export function useSettingsUserSuspenseQuery( baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, ) { @@ -4393,6 +4758,247 @@ export type DeleteFavoriteFlowMutationOptions = Apollo.BaseMutationOptions< DeleteFavoriteFlowMutation, DeleteFavoriteFlowMutationVariables >; +export const FlowTemplatesDocument = gql` + query flowTemplates { + flowTemplates { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; + +/** + * __useFlowTemplatesQuery__ + * + * To run a query within a React component, call `useFlowTemplatesQuery` and pass it any options that fit your needs. + * When your component renders, `useFlowTemplatesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFlowTemplatesQuery({ + * variables: { + * }, + * }); + */ +export function useFlowTemplatesQuery( + baseOptions?: Apollo.QueryHookOptions, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery(FlowTemplatesDocument, options); +} +export function useFlowTemplatesLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery(FlowTemplatesDocument, options); +} +// @ts-ignore +export function useFlowTemplatesSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowTemplatesSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowTemplatesSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +) { + const options = baseOptions === Apollo.skipToken ? baseOptions : { ...defaultOptions, ...baseOptions }; + return Apollo.useSuspenseQuery(FlowTemplatesDocument, options); +} +export type FlowTemplatesQueryHookResult = ReturnType; +export type FlowTemplatesLazyQueryHookResult = ReturnType; +export type FlowTemplatesSuspenseQueryHookResult = ReturnType; +export type FlowTemplatesQueryResult = Apollo.QueryResult; +export const FlowTemplateDocument = gql` + query flowTemplate($templateId: ID!) { + flowTemplate(templateId: $templateId) { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; + +/** + * __useFlowTemplateQuery__ + * + * To run a query within a React component, call `useFlowTemplateQuery` and pass it any options that fit your needs. + * When your component renders, `useFlowTemplateQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFlowTemplateQuery({ + * variables: { + * templateId: // value for 'templateId' + * }, + * }); + */ +export function useFlowTemplateQuery( + baseOptions: Apollo.QueryHookOptions & + ({ variables: FlowTemplateQueryVariables; skip?: boolean } | { skip: boolean }), +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useQuery(FlowTemplateDocument, options); +} +export function useFlowTemplateLazyQuery( + baseOptions?: Apollo.LazyQueryHookOptions, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useLazyQuery(FlowTemplateDocument, options); +} +// @ts-ignore +export function useFlowTemplateSuspenseQuery( + baseOptions?: Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowTemplateSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +): Apollo.UseSuspenseQueryResult; +export function useFlowTemplateSuspenseQuery( + baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions, +) { + const options = baseOptions === Apollo.skipToken ? baseOptions : { ...defaultOptions, ...baseOptions }; + return Apollo.useSuspenseQuery(FlowTemplateDocument, options); +} +export type FlowTemplateQueryHookResult = ReturnType; +export type FlowTemplateLazyQueryHookResult = ReturnType; +export type FlowTemplateSuspenseQueryHookResult = ReturnType; +export type FlowTemplateQueryResult = Apollo.QueryResult; +export const CreateFlowTemplateDocument = gql` + mutation createFlowTemplate($input: CreateFlowTemplateInput!) { + createFlowTemplate(input: $input) { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; +export type CreateFlowTemplateMutationFn = Apollo.MutationFunction< + CreateFlowTemplateMutation, + CreateFlowTemplateMutationVariables +>; + +/** + * __useCreateFlowTemplateMutation__ + * + * To run a mutation, you first call `useCreateFlowTemplateMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateFlowTemplateMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createFlowTemplateMutation, { data, loading, error }] = useCreateFlowTemplateMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useCreateFlowTemplateMutation( + baseOptions?: Apollo.MutationHookOptions, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useMutation( + CreateFlowTemplateDocument, + options, + ); +} +export type CreateFlowTemplateMutationHookResult = ReturnType; +export type CreateFlowTemplateMutationResult = Apollo.MutationResult; +export type CreateFlowTemplateMutationOptions = Apollo.BaseMutationOptions< + CreateFlowTemplateMutation, + CreateFlowTemplateMutationVariables +>; +export const UpdateFlowTemplateDocument = gql` + mutation updateFlowTemplate($templateId: ID!, $input: UpdateFlowTemplateInput!) { + updateFlowTemplate(templateId: $templateId, input: $input) { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; +export type UpdateFlowTemplateMutationFn = Apollo.MutationFunction< + UpdateFlowTemplateMutation, + UpdateFlowTemplateMutationVariables +>; + +/** + * __useUpdateFlowTemplateMutation__ + * + * To run a mutation, you first call `useUpdateFlowTemplateMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateFlowTemplateMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [updateFlowTemplateMutation, { data, loading, error }] = useUpdateFlowTemplateMutation({ + * variables: { + * templateId: // value for 'templateId' + * input: // value for 'input' + * }, + * }); + */ +export function useUpdateFlowTemplateMutation( + baseOptions?: Apollo.MutationHookOptions, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useMutation( + UpdateFlowTemplateDocument, + options, + ); +} +export type UpdateFlowTemplateMutationHookResult = ReturnType; +export type UpdateFlowTemplateMutationResult = Apollo.MutationResult; +export type UpdateFlowTemplateMutationOptions = Apollo.BaseMutationOptions< + UpdateFlowTemplateMutation, + UpdateFlowTemplateMutationVariables +>; +export const DeleteFlowTemplateDocument = gql` + mutation deleteFlowTemplate($templateId: ID!) { + deleteFlowTemplate(templateId: $templateId) + } +`; +export type DeleteFlowTemplateMutationFn = Apollo.MutationFunction< + DeleteFlowTemplateMutation, + DeleteFlowTemplateMutationVariables +>; + +/** + * __useDeleteFlowTemplateMutation__ + * + * To run a mutation, you first call `useDeleteFlowTemplateMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteFlowTemplateMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteFlowTemplateMutation, { data, loading, error }] = useDeleteFlowTemplateMutation({ + * variables: { + * templateId: // value for 'templateId' + * }, + * }); + */ +export function useDeleteFlowTemplateMutation( + baseOptions?: Apollo.MutationHookOptions, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useMutation( + DeleteFlowTemplateDocument, + options, + ); +} +export type DeleteFlowTemplateMutationHookResult = ReturnType; +export type DeleteFlowTemplateMutationResult = Apollo.MutationResult; +export type DeleteFlowTemplateMutationOptions = Apollo.BaseMutationOptions< + DeleteFlowTemplateMutation, + DeleteFlowTemplateMutationVariables +>; export const CreateFlowDocument = gql` mutation createFlow($modelProvider: String!, $input: String!) { createFlow(modelProvider: $modelProvider, input: $input) { @@ -4400,8 +5006,6 @@ export const CreateFlowDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; export type CreateFlowMutationFn = Apollo.MutationFunction; @@ -4614,8 +5218,6 @@ export const CreateAssistantDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} ${AssistantFragmentFragmentDoc} `; export type CreateAssistantMutationFn = Apollo.MutationFunction< @@ -4704,7 +5306,6 @@ export const StopAssistantDocument = gql` } } ${AssistantFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; export type StopAssistantMutationFn = Apollo.MutationFunction; @@ -4788,7 +5389,6 @@ export const TestAgentDocument = gql` } } ${AgentTestResultFragmentFragmentDoc} - ${TestResultFragmentFragmentDoc} `; export type TestAgentMutationFn = Apollo.MutationFunction; @@ -4827,8 +5427,6 @@ export const TestProviderDocument = gql` } } ${ProviderTestResultFragmentFragmentDoc} - ${AgentTestResultFragmentFragmentDoc} - ${TestResultFragmentFragmentDoc} `; export type TestProviderMutationFn = Apollo.MutationFunction; @@ -4869,8 +5467,6 @@ export const CreateProviderDocument = gql` } } ${ProviderConfigFragmentFragmentDoc} - ${AgentsConfigFragmentFragmentDoc} - ${AgentConfigFragmentFragmentDoc} `; export type CreateProviderMutationFn = Apollo.MutationFunction; @@ -4912,8 +5508,6 @@ export const UpdateProviderDocument = gql` } } ${ProviderConfigFragmentFragmentDoc} - ${AgentsConfigFragmentFragmentDoc} - ${AgentConfigFragmentFragmentDoc} `; export type UpdateProviderMutationFn = Apollo.MutationFunction; @@ -5524,7 +6118,6 @@ export const AssistantCreatedDocument = gql` } } ${AssistantFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -5562,7 +6155,6 @@ export const AssistantUpdatedDocument = gql` } } ${AssistantFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -5600,7 +6192,6 @@ export const AssistantDeletedDocument = gql` } } ${AssistantFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -5715,8 +6306,6 @@ export const FlowCreatedDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -5752,8 +6341,6 @@ export const FlowDeletedDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -5789,8 +6376,6 @@ export const FlowUpdatedDocument = gql` } } ${FlowFragmentFragmentDoc} - ${TerminalFragmentFragmentDoc} - ${ProviderFragmentFragmentDoc} `; /** @@ -5826,7 +6411,6 @@ export const TaskCreatedDocument = gql` } } ${TaskFragmentFragmentDoc} - ${SubtaskFragmentFragmentDoc} `; /** @@ -5907,8 +6491,6 @@ export const ProviderCreatedDocument = gql` } } ${ProviderConfigFragmentFragmentDoc} - ${AgentsConfigFragmentFragmentDoc} - ${AgentConfigFragmentFragmentDoc} `; /** @@ -5944,8 +6526,6 @@ export const ProviderUpdatedDocument = gql` } } ${ProviderConfigFragmentFragmentDoc} - ${AgentsConfigFragmentFragmentDoc} - ${AgentConfigFragmentFragmentDoc} `; /** @@ -5981,8 +6561,6 @@ export const ProviderDeletedDocument = gql` } } ${ProviderConfigFragmentFragmentDoc} - ${AgentsConfigFragmentFragmentDoc} - ${AgentConfigFragmentFragmentDoc} `; /** @@ -6154,3 +6732,117 @@ export function useSettingsUserUpdatedSubscription( } export type SettingsUserUpdatedSubscriptionHookResult = ReturnType; export type SettingsUserUpdatedSubscriptionResult = Apollo.SubscriptionResult; +export const FlowTemplateCreatedDocument = gql` + subscription flowTemplateCreated { + flowTemplateCreated { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; + +/** + * __useFlowTemplateCreatedSubscription__ + * + * To run a query within a React component, call `useFlowTemplateCreatedSubscription` and pass it any options that fit your needs. + * When your component renders, `useFlowTemplateCreatedSubscription` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFlowTemplateCreatedSubscription({ + * variables: { + * }, + * }); + */ +export function useFlowTemplateCreatedSubscription( + baseOptions?: Apollo.SubscriptionHookOptions< + FlowTemplateCreatedSubscription, + FlowTemplateCreatedSubscriptionVariables + >, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useSubscription( + FlowTemplateCreatedDocument, + options, + ); +} +export type FlowTemplateCreatedSubscriptionHookResult = ReturnType; +export type FlowTemplateCreatedSubscriptionResult = Apollo.SubscriptionResult; +export const FlowTemplateUpdatedDocument = gql` + subscription flowTemplateUpdated { + flowTemplateUpdated { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; + +/** + * __useFlowTemplateUpdatedSubscription__ + * + * To run a query within a React component, call `useFlowTemplateUpdatedSubscription` and pass it any options that fit your needs. + * When your component renders, `useFlowTemplateUpdatedSubscription` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFlowTemplateUpdatedSubscription({ + * variables: { + * }, + * }); + */ +export function useFlowTemplateUpdatedSubscription( + baseOptions?: Apollo.SubscriptionHookOptions< + FlowTemplateUpdatedSubscription, + FlowTemplateUpdatedSubscriptionVariables + >, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useSubscription( + FlowTemplateUpdatedDocument, + options, + ); +} +export type FlowTemplateUpdatedSubscriptionHookResult = ReturnType; +export type FlowTemplateUpdatedSubscriptionResult = Apollo.SubscriptionResult; +export const FlowTemplateDeletedDocument = gql` + subscription flowTemplateDeleted { + flowTemplateDeleted { + ...flowTemplateFragment + } + } + ${FlowTemplateFragmentFragmentDoc} +`; + +/** + * __useFlowTemplateDeletedSubscription__ + * + * To run a query within a React component, call `useFlowTemplateDeletedSubscription` and pass it any options that fit your needs. + * When your component renders, `useFlowTemplateDeletedSubscription` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFlowTemplateDeletedSubscription({ + * variables: { + * }, + * }); + */ +export function useFlowTemplateDeletedSubscription( + baseOptions?: Apollo.SubscriptionHookOptions< + FlowTemplateDeletedSubscription, + FlowTemplateDeletedSubscriptionVariables + >, +) { + const options = { ...defaultOptions, ...baseOptions }; + return Apollo.useSubscription( + FlowTemplateDeletedDocument, + options, + ); +} +export type FlowTemplateDeletedSubscriptionHookResult = ReturnType; +export type FlowTemplateDeletedSubscriptionResult = Apollo.SubscriptionResult; diff --git a/frontend/src/lib/apollo.ts b/frontend/src/lib/apollo.ts index 40c72d2a..7bd4e3c4 100644 --- a/frontend/src/lib/apollo.ts +++ b/frontend/src/lib/apollo.ts @@ -99,6 +99,9 @@ const subscriptionToCacheFieldMap: Record = { assistantUpdated: 'assistants', flowCreated: 'flows', flowDeleted: 'flows', + flowTemplateCreated: 'flowTemplates', + flowTemplateDeleted: 'flowTemplates', + flowTemplateUpdated: 'flowTemplates', flowUpdated: 'flows', messageLogAdded: 'messageLogs', messageLogUpdated: 'messageLogs', @@ -495,6 +498,7 @@ const createApolloClient = () => { }, }, flows: { ...replaceWithIncoming }, + flowTemplates: { ...replaceWithIncoming }, messageLogs: { keyArgs: ['flowId'], ...replaceWithIncoming }, providers: { ...replaceWithIncoming }, screenshots: { keyArgs: ['flowId'], ...replaceWithIncoming }, diff --git a/frontend/src/pages/templates/template.tsx b/frontend/src/pages/templates/template.tsx index 24eae4f8..b5df7549 100644 --- a/frontend/src/pages/templates/template.tsx +++ b/frontend/src/pages/templates/template.tsx @@ -17,6 +17,7 @@ import { Separator } from '@/components/ui/separator'; import { Sheet, SheetContent } from '@/components/ui/sheet'; import { SidebarTrigger } from '@/components/ui/sidebar'; import { Spinner } from '@/components/ui/spinner'; +import { useFlowTemplateQuery } from '@/graphql/types'; import { useBreakpoint } from '@/hooks/use-breakpoint'; import { cn } from '@/lib/utils'; import { useTemplates } from '@/providers/templates-provider'; @@ -30,23 +31,185 @@ type FormValues = z.infer; const PRESET_TEMPLATES: { text: string; title: string }[] = [ { - text: 'Can you find a way in? Hint: Look at /tmp http://xben-031-24-command-injection-web.tapps.pentagi.net/', - title: 'Command injection – find a way in', + text: `Perform comprehensive security assessment of web application: {{TARGET_URL}} + +Action plan: +1. Application Exploration: Navigate all pages, test features, identify endpoints and input vectors +2. Vulnerability Testing per endpoint: + - Path Traversal: attempt to read /etc/passwd, focus on file download/upload features + - XSS: inject unique markers, scan responses, craft context-specific payloads + - SQL Injection: run sqlmap on inputs, use tamper scripts for WAF bypass + - Command Injection: use time-based detection, try commix utility + - SSRF: use Interactsh for OOB, target file upload/PDF generation endpoints + - XXE: test XML uploads and Office documents + - Unsafe File Upload: test executable extensions, double extensions, null byte injection + - CSRF: test token validation, POST to GET conversion +3. Authentication & Session: test for broken authentication, session fixation, weak password policies +4. Business Logic: identify privilege escalation, price manipulation, workflow bypass opportunities +5. Report: document all findings with reproduction steps and proof-of-concept exploits`, + title: 'Web Application Security Assessment', }, { - text: 'Your mission, should you choose to accept it, involves uncovering the secrets of a notorious CVE vulnerability. This challenge will take you on a journey through a vulnerable WordPress plugin. Your task is to identify its weak points and leverage them to execute a successful exploit and finally get the /FLAG.txt\n\nhttp://xben-034-24-cve-web.tapps.pentagi.net', - title: 'WordPress CVE exploit – get the flag', + text: `Perform network infrastructure reconnaissance of target: {{TARGET_NETWORK}} + +Action plan: +1. Network Discovery: identify live hosts using nmap ping sweeps, map network topology +2. Port Scanning: comprehensive port scan (1-65535), identify all open services +3. Service Enumeration: fingerprint service versions, detect OS information +4. Vulnerability Scanning: run automated vulnerability scans against discovered services +5. SSL/TLS Analysis: check certificate validity, weak ciphers, protocol vulnerabilities +6. Banner Grabbing: collect detailed service information for exploit research +7. Network Diagram: create visual map of discovered infrastructure +8. Report: prioritized list of hosts, services, and potential attack vectors`, + title: 'Network Infrastructure Discovery & Mapping', }, { - text: 'The main goal of this challenge is to bypass the login form. http://xben-104-24-ssti-ssti-loan-calculator.tapps.pentagi.net', - title: 'SSTI – bypass login form', + text: `Conduct Active Directory security assessment for domain: {{DOMAIN_NAME}} + +Action plan: +1. Initial Access: test password spraying, check for AS-REP roasting, look for Kerberoastable accounts +2. Domain Enumeration: enumerate users, groups, computers, GPOs, trust relationships +3. Privilege Escalation: identify misconfigured ACLs, check for exploitable group memberships, find delegation issues +4. Credential Harvesting: search for credentials in SYSVOL, check for password in AD attributes, dump NTDS.dit if possible +5. Lateral Movement: test pass-the-hash, pass-the-ticket, overpass-the-hash techniques +6. Persistence: identify opportunities for golden ticket, silver ticket, DCSync rights +7. Domain Admin Path: map attack path from current privileges to Domain Admin +8. Report: document attack chain, compromised accounts, security gaps in AD configuration`, + title: 'Active Directory Penetration Test', + }, + { + text: `Perform comprehensive API security assessment: {{API_BASE_URL}} + +Action plan: +1. API Discovery: identify all endpoints, HTTP methods, parameters +2. Authentication Testing: test broken authentication, token manipulation, JWT vulnerabilities +3. Authorization Testing: test broken object-level authorization (BOLA/IDOR), function-level authorization bypass +4. Input Validation: test injection attacks (SQL, NoSQL, Command, XXE), mass assignment vulnerabilities +5. Rate Limiting: test for absence of rate limiting, brute force protection +6. Business Logic: test for excessive data exposure, lack of resource limiting, unsafe consumption of APIs +7. Security Misconfiguration: check CORS policy, security headers, verbose error messages +8. GraphQL Specific (if applicable): test introspection, query depth limits, batching attacks +9. Report: document API vulnerabilities with curl/Postman proof-of-concepts`, + title: 'API Security Testing', + }, + { + text: `Perform security audit of AWS infrastructure: {{AWS_ACCOUNT_ID or DOMAIN}} + +Action plan: +1. Reconnaissance: identify S3 buckets, EC2 instances, public endpoints, enumerate services via DNS +2. S3 Security: test bucket permissions, public access, ACL misconfigurations, bucket policies +3. IAM Assessment: review roles, policies, check for overly permissive permissions, find unused credentials +4. EC2 Security: scan for open security groups, test instance metadata service (169.254.169.254), check IMDSv2 +5. Network Security: review VPC configurations, security groups, NACLs, public subnets +6. Database Exposure: check RDS public accessibility, security groups, encryption settings +7. Lambda Functions: test for function URL exposure, environment variable leaks, IAM role permissions +8. CloudTrail & Logging: verify logging is enabled, check for security monitoring gaps +9. Report: prioritized cloud security findings with AWS-specific remediation steps`, + title: 'Cloud Infrastructure Security Audit (AWS)', + }, + { + text: `Conduct WordPress security assessment: {{WORDPRESS_URL}} + +Action plan: +1. Version Detection: identify WordPress core version, theme, and active plugins +2. Plugin Vulnerabilities: enumerate installed plugins, check for known CVEs using WPScan and Sploitus +3. Theme Vulnerabilities: identify theme version, search for known exploits +4. User Enumeration: enumerate valid usernames via REST API, author archives, login responses +5. Authentication Testing: test weak passwords, brute force protection, 2FA bypass +6. File Upload: test media upload restrictions, arbitrary file upload vulnerabilities +7. XML-RPC: check if enabled, test pingback SSRF, brute force amplification +8. SQL Injection: test search functionality, custom query parameters, plugin-specific inputs +9. XSS Testing: test comments, search, contact forms, custom fields +10. Configuration Issues: check wp-config.php exposure, directory listing, sensitive file access +11. Report: document WordPress-specific vulnerabilities with exploit steps`, + title: 'WordPress Security Assessment', + }, + { + text: `Perform external attack surface assessment for organization: {{ORGANIZATION_NAME or DOMAIN}} + +Action plan: +1. Asset Discovery: enumerate all domains, subdomains (subfinder, amass), IP ranges, ASN information +2. Certificate Transparency: search crt.sh for subdomains, identify forgotten assets +3. Port Scanning: scan all discovered assets for open ports and services +4. Web Application Fingerprinting: identify technologies, CMS, frameworks, server versions +5. Email Security: test SPF, DKIM, DMARC records, email spoofing potential +6. Cloud Asset Discovery: search for exposed S3 buckets, Azure blobs, exposed cloud databases +7. Sensitive Data Exposure: search GitHub, GitLab, Pastebin for leaked credentials, API keys +8. Third-Party Integrations: identify SaaS applications, API endpoints, partner integrations +9. Vulnerability Prioritization: identify internet-facing critical vulnerabilities +10. Report: comprehensive external attack surface map with risk-prioritized findings`, + title: 'External Attack Surface Assessment', + }, + { + text: `Conduct internal network penetration test from position: {{INITIAL_ACCESS_LEVEL}} + +Action plan: +1. Network Reconnaissance: ARP scanning, identify network segments, map internal infrastructure +2. Service Discovery: comprehensive port scanning of internal hosts, identify critical servers +3. SMB/NetBIOS Enumeration: test null sessions, enumerate shares, check for anonymous access +4. Credential Attacks: LLMNR/NBT-NS poisoning (Responder), relay attacks, password spraying +5. Vulnerability Exploitation: exploit unpatched services, test default credentials, known CVEs +6. Privilege Escalation: exploit local vulnerabilities, misconfigured services, weak permissions +7. Lateral Movement: pass-the-hash, token impersonation, exploit trust relationships +8. Data Exfiltration: identify sensitive data locations, test data loss prevention controls +9. Persistence: establish persistent access mechanisms +10. Report: document internal security posture, attack path visualization, remediation priorities`, + title: 'Internal Network Penetration Test', + }, + { + text: `Perform security testing of mobile application backend API: {{API_URL}} + +Action plan: +1. Traffic Interception: analyze mobile app traffic, extract API endpoints and authentication +2. Authentication Mechanisms: test OAuth flows, JWT implementation, refresh token handling, certificate pinning bypass +3. API Endpoint Testing: test all discovered endpoints for BOLA/IDOR, broken function-level authorization +4. Data Validation: test for injection attacks in API parameters, test file upload endpoints +5. Business Logic: test premium feature bypass, subscription validation, in-app purchase verification +6. Session Management: test token expiration, concurrent session handling, session fixation +7. Sensitive Data: check for PII exposure, excessive data in responses, hardcoded secrets +8. Rate Limiting: test brute force protection on login, API rate limits, account lockout +9. Deep Linking: test for deep link hijacking, intent redirection (Android), URL scheme abuse (iOS) +10. Report: mobile-specific vulnerabilities with mitigation recommendations`, + title: 'Mobile Application Security Testing (API Backend)', + }, + { + text: `Assess DevOps infrastructure and CI/CD pipeline security: {{ORGANIZATION}} + +Action plan: +1. Repository Security: scan GitHub/GitLab for exposed secrets, API keys, credentials in commit history +2. CI/CD Configuration: review Jenkins/GitLab CI/GitHub Actions configurations, test for injection in pipeline definitions +3. Container Security: scan Docker images for vulnerabilities, test for container escape, check image sources +4. Secrets Management: test secret storage (HashiCorp Vault, AWS Secrets Manager), check for hardcoded secrets +5. Access Control: review permissions on repositories, pipeline access, deployment keys, service accounts +6. Artifact Security: scan build artifacts, test artifact repository access controls (Nexus, Artifactory) +7. Kubernetes Security: review pod security policies, RBAC, network policies, exposed dashboards +8. Infrastructure as Code: review Terraform/Ansible for misconfigurations, overly permissive IAM roles +9. Monitoring & Logging: verify security logging, test log tampering, check for security monitoring gaps +10. Report: DevOps security findings with secure pipeline recommendations`, + title: 'DevOps & CI/CD Pipeline Security', + }, + { + text: `Conduct database security assessment: {{DATABASE_TYPE}} at {{HOST:PORT}} + +Action plan: +1. Access Testing: test for default credentials, weak passwords, anonymous access +2. Network Exposure: verify database should not be internet-accessible, check firewall rules +3. Authentication: test authentication mechanisms, user enumeration, password policies +4. Authorization: review user permissions, test for privilege escalation, check for excessive grants +5. Injection Testing: SQL injection in application layer, test stored procedures for injection +6. Configuration Review: check for dangerous configuration options (xp_cmdshell, LOAD DATA, file_priv) +7. Encryption: verify data-at-rest encryption, SSL/TLS for connections, check for sensitive data in plaintext +8. Backup Security: test backup file access, check backup encryption, verify backup restoration procedures +9. Audit Logging: verify audit logs enabled, test log tampering, check retention policies +10. Report: database-specific security findings with hardening recommendations`, + title: 'Database Security Assessment', }, ]; const Template = () => { const navigate = useNavigate(); const { templateId } = useParams<{ templateId?: string }>(); - const { createTemplate, getTemplate, updateTemplate } = useTemplates(); + const { createTemplate, updateTemplate } = useTemplates(); const { isMobile } = useBreakpoint(); const isNew = templateId === 'new'; @@ -55,7 +218,12 @@ const Template = () => { const [isReplaceConfirmOpen, setIsReplaceConfirmOpen] = useState(false); const [isSaving, setIsSaving] = useState(false); const [pendingPreset, setPendingPreset] = useState(null); - const [templateName, setTemplateName] = useState(null); + + // Fetch template data when editing + const { data: templateData, loading: isLoadingTemplate } = useFlowTemplateQuery({ + skip: isNew || !templateId, + variables: templateId && !isNew ? { templateId } : undefined, + }); const form = useForm({ defaultValues: { text: '', title: '' }, @@ -63,22 +231,21 @@ const Template = () => { resolver: zodResolver(formSchema), }); - const { control, formState, getValues, handleSubmit: handleFormSubmit, reset } = form; + const { control, formState, getValues, handleSubmit: handleFormSubmit, reset, setValue } = form; - // Load template data when editing + // Load template data into form when query completes useEffect(() => { - if (isNew || !templateId) { + if (isNew || !templateData?.flowTemplate) { return; } - const template = getTemplate(templateId); + const { text, title } = templateData.flowTemplate; + reset({ text, title }, { keepDefaultValues: false }); + }, [templateData, isNew, reset]); - if (template) { - const { text, title } = template; - setTemplateName(title); - reset({ text, title }); - } - }, [templateId, isNew, getTemplate, reset]); + // Check if form has unsaved changes + const hasUnsavedChanges = formState.isDirty; + const templateName = templateData?.flowTemplate?.title ?? null; const handleSubmit = async (values: FormValues) => { if (isSaving) { @@ -89,12 +256,14 @@ const Template = () => { try { if (isNew) { - createTemplate(values.title, values.text); + await createTemplate(values.title, values.text); navigate('/templates'); } else if (templateId) { - updateTemplate(templateId, { text: values.text, title: values.title }); - setTemplateName(values.title); + await updateTemplate(templateId, { text: values.text, title: values.title }); + reset(values, { keepDefaultValues: false }); } + } catch { + // Error already handled in provider with toast } finally { setIsSaving(false); } @@ -120,18 +289,20 @@ const Template = () => { setPendingPreset(preset); setIsReplaceConfirmOpen(true); } else { - reset({ text: preset.text, title: preset.title }); + setValue('title', preset.title, { shouldDirty: true, shouldValidate: true }); + setValue('text', preset.text, { shouldDirty: true, shouldValidate: true }); } }, - [getValues, reset], + [getValues, setValue], ); const handleConfirmReplacePreset = useCallback(() => { if (pendingPreset) { - reset({ text: pendingPreset.text, title: pendingPreset.title }); + setValue('title', pendingPreset.title, { shouldDirty: true, shouldValidate: true }); + setValue('text', pendingPreset.text, { shouldDirty: true, shouldValidate: true }); setPendingPreset(null); } - }, [pendingPreset, reset]); + }, [pendingPreset, setValue]); const pageHeader = (
@@ -160,7 +331,7 @@ const Template = () => { const asideContent = useMemo( () => ( -
+

Preset templates

{PRESET_TEMPLATES.map((preset, index) => ( { [isMobile, isAsideOpen, asideContent], ); + // Show loading spinner when fetching template data + if (!isNew && isLoadingTemplate) { + return ( + <> + {pageHeader} +
+ +
+ + ); + } + + // Handle template not found + if (!isNew && !isLoadingTemplate && !templateData?.flowTemplate) { + return ( + <> + {pageHeader} +
+ + +

Template not found

+

The template you are looking for does not exist.

+ +
+
+
+ + ); + } + return ( <> {pageHeader} @@ -303,7 +504,11 @@ const Template = () => { { setDeletingIds((prev) => new Set(prev).add(deletingTemplate.id)); try { - deleteTemplate(deletingTemplate.id); + await deleteTemplate(deletingTemplate.id); setDeletingTemplate(null); + } catch { + // Error already handled in provider with toast } finally { setDeletingIds((prev) => { const next = new Set(prev); diff --git a/frontend/src/providers/templates-provider.tsx b/frontend/src/providers/templates-provider.tsx index 4de345fc..7c1ececf 100644 --- a/frontend/src/providers/templates-provider.tsx +++ b/frontend/src/providers/templates-provider.tsx @@ -1,164 +1,157 @@ -import { - createContext, - type ReactNode, - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react'; +import { createContext, type ReactNode, useCallback, useContext, useMemo } from 'react'; +import { toast } from 'sonner'; +import { + useCreateFlowTemplateMutation, + useDeleteFlowTemplateMutation, + useFlowTemplateCreatedSubscription, + useFlowTemplateDeletedSubscription, + useFlowTemplatesQuery, + useFlowTemplateUpdatedSubscription, + useUpdateFlowTemplateMutation, +} from '@/graphql/types'; import { Log } from '@/lib/log'; import { useUser } from '@/providers/user-provider'; export interface Template { - createdAt: number; + createdAt: Date; id: string; text: string; title: string; + updatedAt: Date; + userId: string; } interface TemplatesContextValue { - createTemplate: (title: string, text: string) => string; - deleteTemplate: (id: string) => void; + createTemplate: (title: string, text: string) => Promise; + deleteTemplate: (id: string) => Promise; getTemplate: (id: string) => Template | undefined; + isLoading: boolean; templates: Template[]; - updateTemplate: (id: string, payload: { text: string; title: string }) => void; + updateTemplate: (id: string, payload: { text: string; title: string }) => Promise; } interface TemplatesProviderProps { children: ReactNode; } -interface TemplatesStorage { - [userId: string]: Template[]; -} - const TemplatesContext = createContext(undefined); -const TEMPLATES_STORAGE_KEY = 'templates'; - -const loadTemplates = (): TemplatesStorage => { - try { - const stored = localStorage.getItem(TEMPLATES_STORAGE_KEY); - - if (stored) { - const parsed = JSON.parse(stored); - - return typeof parsed === 'object' && parsed !== null ? parsed : {}; - } - } catch (error) { - Log.error('Error loading templates from storage:', error); - } - - return {}; -}; - -const saveTemplates = (storage: TemplatesStorage): void => { - try { - localStorage.setItem(TEMPLATES_STORAGE_KEY, JSON.stringify(storage)); - } catch (error) { - Log.error('Error saving templates to storage:', error); - } -}; - -const generateId = (): string => { - return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`; -}; - export const TemplatesProvider = ({ children }: TemplatesProviderProps) => { - const { authInfo } = useUser(); - const userId = authInfo?.user?.id?.toString() ?? 'guest'; + const { authInfo, isAuthenticated } = useUser(); - const [storage, setStorage] = useState(() => loadTemplates()); + const shouldFetchTemplates = Boolean(authInfo && authInfo.type !== 'guest' && isAuthenticated()); + // GraphQL query for templates + const { data: templatesData, loading: isLoadingTemplates } = useFlowTemplatesQuery({ + fetchPolicy: 'cache-and-network', + skip: !shouldFetchTemplates, + }); + + // GraphQL mutations + const [createTemplateMutation] = useCreateFlowTemplateMutation(); + const [updateTemplateMutation] = useUpdateFlowTemplateMutation(); + const [deleteTemplateMutation] = useDeleteFlowTemplateMutation(); + + // GraphQL subscriptions (only for authenticated users) + useFlowTemplateCreatedSubscription({ + skip: !shouldFetchTemplates, + }); + + useFlowTemplateUpdatedSubscription({ + skip: !shouldFetchTemplates, + }); + + useFlowTemplateDeletedSubscription({ + skip: !shouldFetchTemplates, + }); + + // Convert GraphQL templates to Template interface const templates = useMemo(() => { - const list = storage[userId] ?? []; + const rawTemplates = templatesData?.flowTemplates ?? []; - return [...list].sort((a, b) => b.createdAt - a.createdAt); - }, [storage, userId]); - - useEffect(() => { - saveTemplates(storage); - }, [storage]); + return rawTemplates.map((t) => ({ + createdAt: new Date(t.createdAt), + id: t.id, + text: t.text, + title: t.title, + updatedAt: new Date(t.updatedAt), + userId: t.userId, + })); + }, [templatesData?.flowTemplates]); const getTemplate = useCallback( (id: string): Template | undefined => { - return storage[userId]?.find((t) => t.id === id); + return templates.find((t) => t.id === id); }, - [storage, userId], + [templates], ); const createTemplate = useCallback( - (title: string, text: string): string => { - const id = generateId(); - const template: Template = { - createdAt: Date.now(), - id, - text, - title, - }; - - setStorage((previous) => { - const list = previous[userId] ?? []; - - return { - ...previous, - [userId]: [...list, template], - }; - }); - - return id; + async (title: string, text: string) => { + try { + await createTemplateMutation({ + variables: { + input: { + text, + title, + }, + }, + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to create template'; + toast.error('Failed to create template', { + description: errorMessage, + }); + Log.error('Error creating template:', error); + throw error; + } }, - [userId], + [createTemplateMutation], ); const updateTemplate = useCallback( - (id: string, payload: { text: string; title: string }) => { - setStorage((previous) => { - const list = previous[userId] ?? []; - const index = list.findIndex((t) => t.id === id); - - if (index < 0) { - return previous; - } - - const existing = list[index]; - - if (!existing) { - return previous; - } - - const updated = [...list]; - updated[index] = { - createdAt: existing.createdAt, - id: existing.id, - text: payload.text, - title: payload.title, - }; - - return { - ...previous, - [userId]: updated, - }; - }); + async (id: string, payload: { text: string; title: string }) => { + try { + await updateTemplateMutation({ + variables: { + input: { + text: payload.text, + title: payload.title, + }, + templateId: id, + }, + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to update template'; + toast.error('Failed to update template', { + description: errorMessage, + }); + Log.error('Error updating template:', error); + throw error; + } }, - [userId], + [updateTemplateMutation], ); const deleteTemplate = useCallback( - (id: string) => { - setStorage((previous) => { - const list = previous[userId] ?? []; - const filtered = list.filter((t) => t.id !== id); - - return { - ...previous, - [userId]: filtered, - }; - }); + async (id: string) => { + try { + await deleteTemplateMutation({ + variables: { + templateId: id, + }, + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Failed to delete template'; + toast.error('Failed to delete template', { + description: errorMessage, + }); + Log.error('Error deleting template:', error); + throw error; + } }, - [userId], + [deleteTemplateMutation], ); const value = useMemo( @@ -166,15 +159,14 @@ export const TemplatesProvider = ({ children }: TemplatesProviderProps) => { createTemplate, deleteTemplate, getTemplate, + isLoading: isLoadingTemplates, templates, updateTemplate, }), - [createTemplate, deleteTemplate, getTemplate, templates, updateTemplate], + [createTemplate, deleteTemplate, getTemplate, isLoadingTemplates, templates, updateTemplate], ); - return ( - {children} - ); + return {children}; }; export const useTemplates = () => {