fix: backend alignment - remove drafts toggle, clean dead code, truncation indicator

- Remove non-functional drafts toggle and clean TreeFilters type
- Fix AccountInvite type to match backend schema
- Remove dead API methods: pinnedFlows.pin/reorder, trees.getSharedTree
- Remove unused types: SessionListResponse, RatingCreate.is_verified_use
- Add session list truncation indicator with size=51 lookahead

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-19 14:37:16 -05:00
parent 6d8f361d7d
commit 6e5039977d
9 changed files with 24 additions and 54 deletions

View File

@@ -22,19 +22,9 @@ export const pinnedFlowsApi = {
return data return data
}, },
pin: async (treeId: string): Promise<PinnedFlow> => {
const { data } = await apiClient.post(`/trees/${treeId}/pin`)
return data
},
unpin: async (treeId: string): Promise<void> => { unpin: async (treeId: string): Promise<void> => {
await apiClient.delete(`/trees/${treeId}/pin`) await apiClient.delete(`/trees/${treeId}/pin`)
}, },
reorder: async (order: { tree_id: string; display_order: number }[]): Promise<PinnedFlowsResponse> => {
const { data } = await apiClient.patch('/trees/pinned/reorder', { order })
return data
},
} }
export default pinnedFlowsApi export default pinnedFlowsApi

View File

@@ -15,14 +15,6 @@ export interface SessionListParams {
completed_before?: string completed_before?: string
} }
export interface SessionListResponse {
items: Session[]
total: number
page: number
size: number
pages: number
}
export const sessionsApi = { export const sessionsApi = {
async list(params?: SessionListParams): Promise<Session[]> { async list(params?: SessionListParams): Promise<Session[]> {
const response = await apiClient.get<Session[]>('/sessions', { params }) const response = await apiClient.get<Session[]>('/sessions', { params })

View File

@@ -1,5 +1,5 @@
import apiClient from './client' import apiClient from './client'
import type { Tree, TreeListItem, TreeCreate, TreeUpdate, TreeFilters, TreeShareCreate, TreeShare, TreeVisibilityUpdate, SharedTree, TreeValidationResponse } from '@/types' import type { Tree, TreeListItem, TreeCreate, TreeUpdate, TreeFilters, TreeShareCreate, TreeShare, TreeVisibilityUpdate, TreeValidationResponse } from '@/types'
export const treesApi = { export const treesApi = {
async list(params?: TreeFilters): Promise<TreeListItem[]> { async list(params?: TreeFilters): Promise<TreeListItem[]> {
@@ -60,11 +60,6 @@ export const treesApi = {
return response.data return response.data
}, },
async getSharedTree(shareToken: string): Promise<SharedTree> {
const response = await apiClient.get<SharedTree>(`/shared/${shareToken}`)
return response.data
},
// Tree validation // Tree validation
async canPublish(id: string): Promise<TreeValidationResponse> { async canPublish(id: string): Promise<TreeValidationResponse> {
const response = await apiClient.post<TreeValidationResponse>(`/trees/${id}/can-publish`) const response = await apiClient.post<TreeValidationResponse>(`/trees/${id}/can-publish`)

View File

@@ -244,8 +244,7 @@ export function SessionDetailPage() {
rating: data.rating, rating: data.rating,
review_text: data.review || undefined, review_text: data.review || undefined,
was_helpful: data.helpful !== null ? data.helpful : undefined, was_helpful: data.helpful !== null ? data.helpful : undefined,
session_id: session.id, session_id: session.id
is_verified_use: true
}) })
) )

View File

@@ -17,6 +17,7 @@ export function SessionHistoryPage() {
const [searchParams, setSearchParams] = useSearchParams() const [searchParams, setSearchParams] = useSearchParams()
const [sessions, setSessions] = useState<Session[]>([]) const [sessions, setSessions] = useState<Session[]>([])
const [hasMore, setHasMore] = useState(false)
const [trees, setTrees] = useState<TreeListItem[]>([]) const [trees, setTrees] = useState<TreeListItem[]>([])
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
const [filter, setFilter] = useState<'all' | 'completed' | 'active'>('all') const [filter, setFilter] = useState<'all' | 'completed' | 'active'>('all')
@@ -111,8 +112,10 @@ export function SessionHistoryPage() {
} }
} }
const sessionsData = await sessionsApi.list(params) const sessionsData = await sessionsApi.list({ ...params, size: 51 })
setSessions(sessionsData) const truncated = sessionsData.length > 50
setHasMore(truncated)
setSessions(truncated ? sessionsData.slice(0, 50) : sessionsData)
} catch (err) { } catch (err) {
toast.error('Failed to load sessions') toast.error('Failed to load sessions')
console.error(err) console.error(err)
@@ -295,6 +298,15 @@ export function SessionHistoryPage() {
</div> </div>
</div> </div>
))} ))}
{hasMore ? (
<p className="text-center text-sm text-muted-foreground py-4">
Showing the 50 most recent sessions
</p>
) : sessions.length > 0 ? (
<p className="text-center text-sm text-muted-foreground py-4">
Showing all {sessions.length} sessions
</p>
) : null}
</div> </div>
)} )}
</div> </div>

View File

@@ -33,8 +33,6 @@ export function TreeLibraryPage() {
const [selectedFolderId, setSelectedFolderId] = useState<string | null>(null) const [selectedFolderId, setSelectedFolderId] = useState<string | null>(null)
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
const [showDrafts, setShowDrafts] = useState(false)
// Read type filter from URL query params (e.g. /trees?type=procedural) // Read type filter from URL query params (e.g. /trees?type=procedural)
const urlType = searchParams.get('type') const urlType = searchParams.get('type')
const [typeFilter, setTypeFilter] = useState<'all' | 'troubleshooting' | 'procedural' | 'maintenance'>( const [typeFilter, setTypeFilter] = useState<'all' | 'troubleshooting' | 'procedural' | 'maintenance'>(
@@ -131,7 +129,7 @@ export function TreeLibraryPage() {
// Load trees when filters change // Load trees when filters change
useEffect(() => { useEffect(() => {
loadTrees() loadTrees()
}, [selectedCategoryId, selectedTags, selectedFolderId, treeLibrarySortBy, showDrafts, typeFilter]) }, [selectedCategoryId, selectedTags, selectedFolderId, treeLibrarySortBy, typeFilter])
// Load folders on mount and listen for changes // Load folders on mount and listen for changes
useEffect(() => { useEffect(() => {
@@ -150,7 +148,6 @@ export function TreeLibraryPage() {
tags: selectedTags.length > 0 ? selectedTags.join(',') : undefined, tags: selectedTags.length > 0 ? selectedTags.join(',') : undefined,
folder_id: selectedFolderId || undefined, folder_id: selectedFolderId || undefined,
sort_by: treeLibrarySortBy, sort_by: treeLibrarySortBy,
include_drafts: showDrafts || undefined,
}) })
setTrees(treesData) setTrees(treesData)
} catch (err) { } catch (err) {
@@ -326,33 +323,22 @@ export function TreeLibraryPage() {
{/* View Controls */} {/* View Controls */}
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"> <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
{/* Type filter tabs — includes Drafts as a first-class filter */} {/* Type filter tabs */}
<div className="flex rounded-lg border border-border p-0.5"> <div className="flex rounded-lg border border-border p-0.5">
{(['all', 'troubleshooting', 'procedural', 'maintenance', 'drafts'] as const).map((t) => { {(['all', 'troubleshooting', 'procedural', 'maintenance'] as const).map((t) => (
const isActive = t === 'drafts' ? showDrafts && typeFilter === 'all' : !showDrafts && typeFilter === t
return (
<button <button
key={t} key={t}
onClick={() => { onClick={() => setTypeFilter(t)}
if (t === 'drafts') {
setShowDrafts(true)
setTypeFilter('all')
} else {
setShowDrafts(false)
setTypeFilter(t)
}
}}
className={cn( className={cn(
'rounded-md px-3 py-1 text-xs font-medium transition-colors', 'rounded-md px-3 py-1 text-xs font-medium transition-colors',
isActive typeFilter === t
? 'bg-accent text-foreground' ? 'bg-accent text-foreground'
: 'text-muted-foreground hover:text-foreground' : 'text-muted-foreground hover:text-foreground'
)} )}
> >
{t === 'all' ? 'All' : t === 'troubleshooting' ? 'Troubleshooting' : t === 'procedural' ? 'Projects' : t === 'maintenance' ? 'Maintenance' : 'Drafts'} {t === 'all' ? 'All' : t === 'troubleshooting' ? 'Troubleshooting' : t === 'procedural' ? 'Projects' : 'Maintenance'}
</button> </button>
) ))}
})}
</div> </div>
{/* Right controls: sort + view toggle */} {/* Right controls: sort + view toggle */}

View File

@@ -44,9 +44,7 @@ export interface AccountInvite {
email: string email: string
role: 'engineer' | 'viewer' role: 'engineer' | 'viewer'
code: string code: string
invited_by_id: string expires_at: string | null
accepted_by_id: string | null
expires_at: string
used_at: string | null used_at: string | null
created_at: string created_at: string
} }

View File

@@ -121,7 +121,6 @@ export interface RatingCreate {
review_text?: string review_text?: string
was_helpful?: boolean was_helpful?: boolean
session_id?: string session_id?: string
is_verified_use?: boolean
} }
export interface RatingUpdate { export interface RatingUpdate {

View File

@@ -215,7 +215,6 @@ export interface TreeFilters {
is_active?: boolean is_active?: boolean
author_id?: string author_id?: string
is_public?: boolean is_public?: boolean
include_drafts?: boolean
sort_by?: 'usage_count' | 'updated_at' | 'created_at' | 'name' | 'name_desc' | 'version' sort_by?: 'usage_count' | 'updated_at' | 'created_at' | 'name' | 'name_desc' | 'version'
skip?: number skip?: number
limit?: number limit?: number