feat: Add Step Library API foundation (Phase 1: B.1-B.3, B.7)
Implements foundational types and API clients for Step Library: Task B.3 - TypeScript Types: - Created types/step.ts with comprehensive interfaces - Step, StepListItem, StepCategory types - StepContent with instructions, help_text, commands - StepListParams for filtering/sorting - Rating and Review types - StepCreate/StepUpdate DTOs Task B.1 - Steps API Client: - Created api/steps.ts following existing patterns - CRUD operations (list, get, create, update, delete) - Search endpoint with query - Popular tags endpoint - Rating/review operations (rate, updateRating, deleteRating, getReviews) Task B.2 - Step Categories API Client: - Created api/stepCategories.ts - List and get operations for categories Task B.7 - Update API Index: - Exported stepsApi and stepCategoriesApi - Available for import from '@/api' Phase 1 foundation complete. Ready for Phase 2 (UI components). Build tested successfully. Related: Issue #10 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,3 +6,5 @@ export { default as inviteApi } from './invite'
|
||||
export { default as tagsApi } from './tags'
|
||||
export { default as categoriesApi } from './categories'
|
||||
export { default as foldersApi } from './folders'
|
||||
export { default as stepsApi } from './steps'
|
||||
export { default as stepCategoriesApi } from './stepCategories'
|
||||
|
||||
16
frontend/src/api/stepCategories.ts
Normal file
16
frontend/src/api/stepCategories.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import apiClient from './client'
|
||||
import type { StepCategory } from '@/types/step'
|
||||
|
||||
export const stepCategoriesApi = {
|
||||
async list(): Promise<StepCategory[]> {
|
||||
const response = await apiClient.get<StepCategory[]>('/step-categories')
|
||||
return response.data
|
||||
},
|
||||
|
||||
async get(id: string): Promise<StepCategory> {
|
||||
const response = await apiClient.get<StepCategory>(`/step-categories/${id}`)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
||||
export default stepCategoriesApi
|
||||
72
frontend/src/api/steps.ts
Normal file
72
frontend/src/api/steps.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import apiClient from './client'
|
||||
import type {
|
||||
Step,
|
||||
StepListItem,
|
||||
StepCreate,
|
||||
StepUpdate,
|
||||
StepListParams,
|
||||
PopularTag,
|
||||
RatingCreate,
|
||||
RatingUpdate,
|
||||
Rating,
|
||||
Review
|
||||
} from '@/types/step'
|
||||
|
||||
export const stepsApi = {
|
||||
async list(params?: StepListParams): Promise<StepListItem[]> {
|
||||
const response = await apiClient.get<StepListItem[]>('/steps', { params })
|
||||
return response.data
|
||||
},
|
||||
|
||||
async get(id: string): Promise<Step> {
|
||||
const response = await apiClient.get<Step>(`/steps/${id}`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async create(data: StepCreate): Promise<Step> {
|
||||
const response = await apiClient.post<Step>('/steps', data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async update(id: string, data: StepUpdate): Promise<Step> {
|
||||
const response = await apiClient.put<Step>(`/steps/${id}`, data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await apiClient.delete(`/steps/${id}`)
|
||||
},
|
||||
|
||||
async search(query: string): Promise<StepListItem[]> {
|
||||
const response = await apiClient.get<StepListItem[]>('/steps/search', {
|
||||
params: { q: query }
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getPopularTags(): Promise<PopularTag[]> {
|
||||
const response = await apiClient.get<PopularTag[]>('/steps/popular-tags')
|
||||
return response.data
|
||||
},
|
||||
|
||||
async rate(id: string, data: RatingCreate): Promise<Rating> {
|
||||
const response = await apiClient.post<Rating>(`/steps/${id}/ratings`, data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async updateRating(id: string, data: RatingUpdate): Promise<Rating> {
|
||||
const response = await apiClient.put<Rating>(`/steps/${id}/ratings`, data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async deleteRating(id: string): Promise<void> {
|
||||
await apiClient.delete(`/steps/${id}/ratings`)
|
||||
},
|
||||
|
||||
async getReviews(id: string): Promise<Review[]> {
|
||||
const response = await apiClient.get<Review[]>(`/steps/${id}/reviews`)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
||||
export default stepsApi
|
||||
124
frontend/src/types/step.ts
Normal file
124
frontend/src/types/step.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
// Step Library Types
|
||||
|
||||
export interface StepCommand {
|
||||
label: string
|
||||
command: string
|
||||
command_type?: string
|
||||
}
|
||||
|
||||
export interface StepContent {
|
||||
instructions: string
|
||||
help_text?: string
|
||||
commands?: StepCommand[]
|
||||
}
|
||||
|
||||
export interface Step {
|
||||
id: string
|
||||
title: string
|
||||
step_type: 'decision' | 'action' | 'solution'
|
||||
content: StepContent
|
||||
visibility: 'private' | 'team' | 'public'
|
||||
category_id?: string
|
||||
category_name?: string
|
||||
tags: string[]
|
||||
usage_count: number
|
||||
rating_average: number
|
||||
rating_count: number
|
||||
helpful_yes: number
|
||||
helpful_no: number
|
||||
is_featured: boolean
|
||||
is_verified: boolean
|
||||
created_by: string
|
||||
author_name?: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface StepListItem {
|
||||
id: string
|
||||
title: string
|
||||
step_type: string
|
||||
visibility: string
|
||||
category_id?: string
|
||||
category_name?: string
|
||||
tags: string[]
|
||||
usage_count: number
|
||||
rating_average: number
|
||||
rating_count: number
|
||||
is_featured: boolean
|
||||
created_by: string
|
||||
author_name?: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface StepCategory {
|
||||
id: string
|
||||
name: string
|
||||
description?: string
|
||||
display_order: number
|
||||
team_id?: string
|
||||
is_active: boolean
|
||||
}
|
||||
|
||||
export interface StepListParams {
|
||||
visibility?: 'private' | 'team' | 'public'
|
||||
category_id?: string
|
||||
tags?: string[]
|
||||
min_rating?: number
|
||||
step_type?: 'decision' | 'action' | 'solution'
|
||||
sort_by?: 'recent' | 'popular' | 'highest_rated' | 'most_used'
|
||||
limit?: number
|
||||
offset?: number
|
||||
}
|
||||
|
||||
export interface PopularTag {
|
||||
tag: string
|
||||
count: number
|
||||
}
|
||||
|
||||
export interface StepCreate {
|
||||
title: string
|
||||
step_type: 'decision' | 'action' | 'solution'
|
||||
content: StepContent
|
||||
visibility: 'private' | 'team' | 'public'
|
||||
category_id?: string
|
||||
tags?: string[]
|
||||
}
|
||||
|
||||
export interface StepUpdate {
|
||||
title?: string
|
||||
step_type?: 'decision' | 'action' | 'solution'
|
||||
content?: StepContent
|
||||
visibility?: 'private' | 'team' | 'public'
|
||||
category_id?: string
|
||||
tags?: string[]
|
||||
}
|
||||
|
||||
export interface RatingCreate {
|
||||
rating: number
|
||||
review_text?: string
|
||||
verified_use: boolean
|
||||
}
|
||||
|
||||
export interface RatingUpdate {
|
||||
rating?: number
|
||||
review_text?: string
|
||||
}
|
||||
|
||||
export interface Rating {
|
||||
id: string
|
||||
step_id: string
|
||||
user_id: string
|
||||
rating: number
|
||||
review_text?: string
|
||||
verified_use: boolean
|
||||
helpful_yes: number
|
||||
helpful_no: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
user_name?: string
|
||||
}
|
||||
|
||||
export interface Review extends Rating {
|
||||
// Same as Rating, just an alias for clarity
|
||||
}
|
||||
Reference in New Issue
Block a user