All files / msw / handlers pipelines.ts

82% Statements 41/50
71.87% Branches 23/32
90.9% Functions 10/11
85.71% Lines 36/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98                    15x 13x 8x 8x   5x 5x           5x           7x 7x 7x 10x 22x 10x 10x           7x   125x   23x 139x 23x                   50x 36x     2x 2x 2x     2x         2x 2x     13x 13x 13x 13x 8x   5x 5x   5x           5x                
import { http, HttpResponse } from 'msw'
import { mockPipelines, mockRepositories } from '@/msw/mock-data'
import { createMockPipeline } from '@/msw/data'
import { laneLint } from '@/features/pipelines/laneLint'
import type { components } from '@/types/api'
import type { LintIssue } from '@/layers/interfaces'
 
type SkillRepoRef = components['schemas']['SkillRepoRef']
 
// Mirrors the API's validateJSONObject + writeLaneLintErrors
// (pipeline_handler.go): a non-object config answers 422; a config whose
// vikunja.lanes section has error-severity lint issues answers 422 with the
// first error message plus the full error-issue list (warnings are
// non-blocking and never serialized).
function configLaneValidationError(
  config: unknown,
)I: { error: string; errors?: LintIssue[] } | null {
  if (config === null || config === undefined) return null
  if (typeof config !== 'object' || Array.isArray(config)) {
    const kind = Array.isArray(config) ? 'array' : typeof config
    return { error: `config must be a JSON object, not ${kind}` }
  }
  const result = laneLint(config, '')
  if (result.errors.length > 0) {
    return { error: result.errors[0].message, errors: result.errors }
  }
  return null
}
I
// Joins submitted ordered repository ids against the repositories mock data,
// mirroring the API's pipeline_skill_repos join: response refs carry the
//I repository name and url, and the array order is the submitted priority.
function resolveSkillRepoRefs(ids: unknown): SkillRepoRef[] {
  Iif (!Array.isArray(ids)) return []
  const refs: SkillRepoRef[] = []
  for (const id of ids) {
    if (typeof id !== 'string') continue
    const repo = mockRepositories.find((r) => r.id === id)
    if (!repo) continue
    refs.push({ repository_id: repo.id, name: repo.name, url: repo.url })
  }
  return refs
}
 
export const pipelineHandlers = [
  http.get('/api/v1/projects/:projectId/pipelines', ({ params }) => {
    const projectId = params.projectId as string
    const pipelines = mockPipelines.filter((p) => p.project_id === projectId)
    return HttpResponse.json({
      data: pipelines.length > 0 ? pipelines : [createMockPipeline({ project_id: projectId })],
      meta: { limit: 50, returned: Math.max(pipelines.length, 1), has_more: false },
    })
  }),
 
  http.get('/api/v1/pipelines/:id', ({ params }) => {
    const pipeline = mockPipelines.find((p) => p.id === params.id)
    return HttpResponse.json(pipeline ?? createMockPipeline({ id: params.id as string }))
  }),
 
  http.post('/api/v1/projects/:projectId/pipelines', async ({ params, request }) => {
    const body = (await request.json()) as Record<string, unknown>
    const configError = configLaneValidationError(body.config)
  I  if (configError) {
      return HttpResponse.json(configError, { status: 422 })
    }
    const pipeline = createMockPipeline({
      project_id: params.projectId as string,
      config: (body.config as Record<string, unknown> | null | undefined) ?? null,
      skill_repos: resolveSkillRepoRefs(body.skill_repos),
    })
    mockPipelines.push(pipeline)
    return HttpResponse.json(pipeline, { status: 201 })
  }),
 
  http.put('/api/v1/pipelines/:id', async ({ params, request }) => {
    const existing = mockPipelines.find((p) => p.id === params.id)
    const body = (await request.json()) as Record<string, unknown>
    const configError = configLaneValidationError(body.config)
    if (configError) {
      return HttpResponse.json(configError, { status: 422 })
  E  }
    if (existing) {
      if (Array.isArray(body.skill_repos)) {
        // Ordered id array → joined refs (order = priority); [] clears.
        ObEject.assign(existing, body, { skill_repos: resolveSkillRepoRefs(body.skill_repos) })
      } else {
        // null = unchanged and absent = untouched: never write skill_repos.
        const { skill_repos: _ignored, ...rest } = body
        Object.assign(existing, rest)
      }
      return HttpResponse.json(existing)
    }
    return HttpResponse.json(createMockPipeline({ id: params.id as string, ...body }))
  }),
 
  http.delete('/api/v1/pipelines/:id', () => new HttpResponse(null, { status: 204 })),
]