Files
kandev/apps/backend/internal/plugins/webapp_protocol_json.go
T

219 lines
8.9 KiB
Go

package plugins
import (
"encoding/json"
"net/http"
"github.com/kandev/kandev/pkg/pluginsdk"
)
type webAppPageInfo struct {
NextCursor string `json:"next_cursor,omitempty"`
HasMore bool `json:"has_more"`
}
type webAppPage[T any] struct {
Items []T `json:"items"`
PageInfo webAppPageInfo `json:"page_info"`
}
func webAppPageFromSDK[T any](items []T, info *pluginsdk.PageInfo) webAppPage[T] {
page := webAppPage[T]{Items: items}
if info != nil {
page.PageInfo = webAppPageInfo{NextCursor: info.NextCursor, HasMore: info.HasMore}
}
return page
}
func writeWebAppJSON(w http.ResponseWriter, r *http.Request, status int, value any) {
body, err := json.Marshal(value)
if err != nil {
writeWebAppError(w, http.StatusInternalServerError, webAppRuntimeUnavailable)
return
}
if len(body) > webAppResponseLimit {
writeWebAppError(w, http.StatusInternalServerError, "response_too_large")
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
if r == nil || r.Method != http.MethodHead {
_, _ = w.Write(body)
}
}
func writeWebAppError(w http.ResponseWriter, status int, code string) {
body, err := json.Marshal(struct {
Error string `json:"error"`
}{Error: code})
if err != nil {
body = []byte(`{"error":"runtime_unavailable"}`)
}
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
_, _ = w.Write(body)
}
type webAppTaskRepository struct {
ID string `json:"id"`
RepositoryID string `json:"repository_id"`
BaseBranch string `json:"base_branch"`
Position int32 `json:"position"`
CheckoutBranch string `json:"checkout_branch"`
}
type webAppPullRequest struct {
Number int64 `json:"number"`
URL string `json:"url"`
Title string `json:"title"`
State string `json:"state"`
HeadBranch string `json:"head_branch"`
BaseBranch string `json:"base_branch"`
IsDraft bool `json:"is_draft"`
Provider string `json:"provider"`
MergedAt *string `json:"merged_at,omitempty"`
ClosedAt *string `json:"closed_at,omitempty"`
ReviewState string `json:"review_state"`
ChecksState string `json:"checks_state"`
MergeableState string `json:"mergeable_state"`
UnresolvedReviewThreads int32 `json:"unresolved_review_threads"`
ChecksTotal int32 `json:"checks_total"`
ChecksPassing int32 `json:"checks_passing"`
Additions int32 `json:"additions"`
Deletions int32 `json:"deletions"`
AuthorLogin string `json:"author_login"`
}
type webAppTask struct {
ID string `json:"id"`
WorkspaceID string `json:"workspace_id"`
WorkflowID string `json:"workflow_id"`
Title string `json:"title"`
Description string `json:"description"`
State string `json:"state"`
Priority string `json:"priority"`
CreatedBy string `json:"created_by"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
StartedAt *string `json:"started_at,omitempty"`
CompletedAt *string `json:"completed_at,omitempty"`
ParentID *string `json:"parent_id,omitempty"`
Identifier string `json:"identifier"`
IsEphemeral bool `json:"is_ephemeral"`
Repositories []webAppTaskRepository `json:"repositories,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
ArchivedAt *string `json:"archived_at,omitempty"`
PullRequests []webAppPullRequest `json:"pull_requests,omitempty"`
WorkflowStepID string `json:"workflow_step_id"`
Position int32 `json:"position"`
AssigneeAgentProfileID string `json:"assignee_agent_profile_id"`
Labels []string `json:"labels,omitempty"`
Autopilot bool `json:"autopilot"`
WIPAdmitted bool `json:"wip_admitted"`
QueuedForStepID string `json:"queued_for_step_id,omitempty"`
QueuedAt *string `json:"queued_at,omitempty"`
ProjectID string `json:"project_id,omitempty"`
ExternalID string `json:"external_id,omitempty"`
}
func webAppTaskFromSDK(task pluginsdk.Task) webAppTask {
result := webAppTask{
ID: task.ID,
WorkspaceID: task.WorkspaceID,
WorkflowID: task.WorkflowID,
Title: task.Title,
Description: task.Description,
State: task.State,
Priority: task.Priority,
CreatedBy: task.CreatedBy,
CreatedAt: task.CreatedAt,
UpdatedAt: task.UpdatedAt,
StartedAt: task.StartedAt,
CompletedAt: task.CompletedAt,
ParentID: task.ParentID,
Identifier: task.Identifier,
IsEphemeral: task.IsEphemeral,
Metadata: task.Metadata,
ArchivedAt: task.ArchivedAt,
WorkflowStepID: task.WorkflowStepID,
Position: task.Position,
AssigneeAgentProfileID: task.AssigneeAgentProfileID,
Labels: task.Labels, //nolint:staticcheck // retain API v1 label compatibility
Autopilot: task.Autopilot,
WIPAdmitted: task.WIPAdmitted,
QueuedForStepID: task.QueuedForStepID,
QueuedAt: task.QueuedAt,
ProjectID: task.ProjectID,
ExternalID: task.ExternalID,
}
if len(task.Repositories) > 0 {
result.Repositories = make([]webAppTaskRepository, len(task.Repositories))
for i, repository := range task.Repositories {
result.Repositories[i] = webAppTaskRepository{
ID: repository.ID, RepositoryID: repository.RepositoryID,
BaseBranch: repository.BaseBranch, Position: repository.Position,
CheckoutBranch: repository.CheckoutBranch,
}
}
}
if len(task.PullRequests) > 0 {
result.PullRequests = make([]webAppPullRequest, len(task.PullRequests))
for i, pullRequest := range task.PullRequests {
result.PullRequests[i] = webAppPullRequest{
Number: pullRequest.Number, URL: pullRequest.URL, Title: pullRequest.Title,
State: pullRequest.State, HeadBranch: pullRequest.HeadBranch,
BaseBranch: pullRequest.BaseBranch, IsDraft: pullRequest.IsDraft,
Provider: pullRequest.Provider, MergedAt: pullRequest.MergedAt,
ClosedAt: pullRequest.ClosedAt, ReviewState: pullRequest.ReviewState,
ChecksState: pullRequest.ChecksState, MergeableState: pullRequest.MergeableState,
UnresolvedReviewThreads: pullRequest.UnresolvedReviewThreads,
ChecksTotal: pullRequest.ChecksTotal, ChecksPassing: pullRequest.ChecksPassing,
Additions: pullRequest.Additions, Deletions: pullRequest.Deletions,
AuthorLogin: pullRequest.AuthorLogin,
}
}
}
return result
}
type webAppWorkflow struct {
ID string `json:"id"`
WorkspaceID string `json:"workspace_id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
SortOrder int32 `json:"sort_order"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
func webAppWorkflowFromSDK(workflow pluginsdk.Workflow) webAppWorkflow {
return webAppWorkflow{
ID: workflow.ID, WorkspaceID: workflow.WorkspaceID, Name: workflow.Name,
Description: workflow.Description, SortOrder: workflow.SortOrder,
CreatedAt: workflow.CreatedAt, UpdatedAt: workflow.UpdatedAt,
}
}
type webAppWorkflowStep struct {
ID string `json:"id"`
WorkflowID string `json:"workflow_id"`
Name string `json:"name"`
Position int32 `json:"position"`
StageType string `json:"stage_type"`
Color string `json:"color"`
IsStartStep bool `json:"is_start_step"`
WIPLimit int32 `json:"wip_limit"`
AgentProfileID string `json:"agent_profile_id"`
OnEnterActionTypes []string `json:"on_enter_action_types,omitempty"`
}
func webAppWorkflowStepFromSDK(step pluginsdk.WorkflowStep) webAppWorkflowStep {
return webAppWorkflowStep{
ID: step.ID, WorkflowID: step.WorkflowID, Name: step.Name,
Position: step.Position, StageType: step.StageType, Color: step.Color,
IsStartStep: step.IsStartStep, WIPLimit: step.WIPLimit,
AgentProfileID: step.AgentProfileID, OnEnterActionTypes: step.OnEnterActionTypes,
}
}