78244c3197
Build & Push Docker Image / build (push) Successful in 2m25s
- view modes grid | table | rows + density cozy/compact, persisted via localStorage and shareable ?view=?density= URL params (URL wins) - table view: sortable columns (name, rating, reviews), new sort options name_asc/name_desc/recently_updated (backend enum + handler) - live debounced search, removable filter chips, '/' focuses search - virtualization via @tanstack/react-virtual for table and rows views - profile sync: users.preferences jsonb + GET/PUT /api/auth/me/preferences; preference precedence URL > server profile > localStorage > default - add local rollup/lightningcss/tailwindcss oxide native binaries for macos dev
539 lines
14 KiB
TypeScript
539 lines
14 KiB
TypeScript
/**
|
|
* Generated by orval v8.9.1 🍺
|
|
* Do not edit manually.
|
|
* Api
|
|
* ToolRate API — Tool listing and rating platform
|
|
* OpenAPI spec version: 0.1.0
|
|
*/
|
|
import * as zod from 'zod';
|
|
|
|
|
|
/**
|
|
* Returns server health status
|
|
* @summary Health check
|
|
*/
|
|
export const HealthCheckResponse = zod.object({
|
|
"status": zod.string()
|
|
})
|
|
|
|
|
|
/**
|
|
* Returns the running build version, commit SHA and build date
|
|
* @summary Build version information
|
|
*/
|
|
export const GetVersionResponse = zod.object({
|
|
"version": zod.string(),
|
|
"commitSha": zod.string().nullish(),
|
|
"buildDate": zod.string().nullish(),
|
|
"trashRetentionDays": zod.number().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List all tools
|
|
*/
|
|
export const ListToolsQueryParams = zod.object({
|
|
"category": zod.coerce.string().optional(),
|
|
"search": zod.coerce.string().optional(),
|
|
"sort": zod.enum(['newest', 'top_rated', 'most_reviewed', 'name_asc', 'name_desc', 'recently_updated']).optional()
|
|
})
|
|
|
|
export const ListToolsResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string(),
|
|
"category": zod.string(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"createdBy": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional(),
|
|
"createdAt": zod.coerce.date(),
|
|
"updatedAt": zod.coerce.date(),
|
|
"ratingCount": zod.number(),
|
|
"avgUsefulness": zod.number().nullable(),
|
|
"avgUsability": zod.number().nullable(),
|
|
"avgCombined": zod.number().nullable()
|
|
})
|
|
export const ListToolsResponse = zod.array(ListToolsResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Create a new tool
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
export const CreateToolBody = zod.object({
|
|
"name": zod.string().min(1),
|
|
"description": zod.string().min(1),
|
|
"category": zod.string().min(1),
|
|
"websiteUrl": zod.string().optional(),
|
|
"iconUrl": zod.string().optional(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Get a tool by ID
|
|
*/
|
|
export const GetToolParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const GetToolResponse = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string(),
|
|
"category": zod.string(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"createdBy": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional(),
|
|
"createdAt": zod.coerce.date(),
|
|
"updatedAt": zod.coerce.date(),
|
|
"ratingCount": zod.number(),
|
|
"avgUsefulness": zod.number().nullable(),
|
|
"avgUsability": zod.number().nullable(),
|
|
"avgCombined": zod.number().nullable()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Update a tool
|
|
*/
|
|
export const UpdateToolParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
|
|
|
|
export const UpdateToolBody = zod.object({
|
|
"name": zod.string().min(1).optional(),
|
|
"description": zod.string().optional(),
|
|
"category": zod.string().optional(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional()
|
|
})
|
|
|
|
export const UpdateToolResponse = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string(),
|
|
"category": zod.string(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"createdBy": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional(),
|
|
"createdAt": zod.coerce.date(),
|
|
"updatedAt": zod.coerce.date(),
|
|
"deletedAt": zod.coerce.date().nullish(),
|
|
"deletedBy": zod.string().nullish()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Delete a tool
|
|
*/
|
|
export const DeleteToolParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List trashed (soft-deleted) tools
|
|
*/
|
|
export const ListTrashedToolsQueryParams = zod.object({
|
|
"search": zod.coerce.string().optional()
|
|
})
|
|
|
|
export const ListTrashedToolsResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string(),
|
|
"category": zod.string(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"createdBy": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional(),
|
|
"createdAt": zod.coerce.date(),
|
|
"updatedAt": zod.coerce.date(),
|
|
"deletedAt": zod.coerce.date().nullish(),
|
|
"deletedBy": zod.string().nullish()
|
|
})
|
|
export const ListTrashedToolsResponse = zod.array(ListTrashedToolsResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Move tools to trash (admin)
|
|
*/
|
|
export const trashToolsBodyIdsMax = 500;
|
|
|
|
|
|
|
|
export const TrashToolsBody = zod.object({
|
|
"ids": zod.array(zod.number()).min(1).max(trashToolsBodyIdsMax)
|
|
})
|
|
|
|
export const TrashToolsResponse = zod.object({
|
|
"trashed": zod.number().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Permanently delete trashed tools (admin)
|
|
*/
|
|
export const deleteTrashedToolsBodyIdsMax = 500;
|
|
|
|
|
|
|
|
export const DeleteTrashedToolsBody = zod.object({
|
|
"ids": zod.array(zod.number()).min(1).max(deleteTrashedToolsBodyIdsMax)
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Restore trashed tools
|
|
*/
|
|
export const restoreToolsBodyIdsMax = 500;
|
|
|
|
|
|
|
|
export const RestoreToolsBody = zod.object({
|
|
"ids": zod.array(zod.number()).min(1).max(restoreToolsBodyIdsMax)
|
|
})
|
|
|
|
export const RestoreToolsResponse = zod.object({
|
|
"restored": zod.number().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Permanently delete all trashed tools (admin)
|
|
*/
|
|
export const EmptyTrashResponse = zod.object({
|
|
"deleted": zod.number().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List ratings for a tool
|
|
*/
|
|
export const ListToolRatingsParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const listToolRatingsResponseUsefulnessMax = 5;
|
|
|
|
export const listToolRatingsResponseUsabilityMax = 5;
|
|
|
|
|
|
|
|
export const ListToolRatingsResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"toolId": zod.number(),
|
|
"usefulness": zod.number().min(1).max(listToolRatingsResponseUsefulnessMax),
|
|
"usability": zod.number().min(1).max(listToolRatingsResponseUsabilityMax),
|
|
"comment": zod.string().nullish(),
|
|
"reviewerName": zod.string().nullish(),
|
|
"createdAt": zod.coerce.date()
|
|
})
|
|
export const ListToolRatingsResponse = zod.array(ListToolRatingsResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Submit a rating for a tool
|
|
*/
|
|
export const CreateRatingParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const createRatingBodyUsefulnessMax = 5;
|
|
|
|
export const createRatingBodyUsabilityMax = 5;
|
|
|
|
|
|
|
|
export const CreateRatingBody = zod.object({
|
|
"usefulness": zod.number().min(1).max(createRatingBodyUsefulnessMax),
|
|
"usability": zod.number().min(1).max(createRatingBodyUsabilityMax),
|
|
"comment": zod.string().optional(),
|
|
"reviewerName": zod.string().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Overall platform statistics
|
|
*/
|
|
export const GetAnalyticsSummaryResponse = zod.object({
|
|
"totalTools": zod.number(),
|
|
"totalRatings": zod.number(),
|
|
"avgUsefulness": zod.number().nullable(),
|
|
"avgUsability": zod.number().nullable(),
|
|
"avgCombined": zod.number().nullable(),
|
|
"categoriesCount": zod.number(),
|
|
"mostRatedTool": zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string(),
|
|
"category": zod.string(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"createdBy": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional(),
|
|
"createdAt": zod.coerce.date(),
|
|
"updatedAt": zod.coerce.date(),
|
|
"ratingCount": zod.number(),
|
|
"avgUsefulness": zod.number().nullable(),
|
|
"avgUsability": zod.number().nullable(),
|
|
"avgCombined": zod.number().nullable()
|
|
}).optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Top-rated tools
|
|
*/
|
|
export const GetTopToolsQueryParams = zod.object({
|
|
"limit": zod.coerce.number().optional(),
|
|
"metric": zod.enum(['usefulness', 'usability', 'combined']).optional()
|
|
})
|
|
|
|
export const GetTopToolsResponseItem = zod.object({
|
|
"tool": zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string(),
|
|
"category": zod.string(),
|
|
"websiteUrl": zod.string().nullish(),
|
|
"iconUrl": zod.string().nullish(),
|
|
"createdBy": zod.string().nullish(),
|
|
"features": zod.array(zod.string()).optional(),
|
|
"tags": zod.array(zod.string()).optional(),
|
|
"createdAt": zod.coerce.date(),
|
|
"updatedAt": zod.coerce.date(),
|
|
"ratingCount": zod.number(),
|
|
"avgUsefulness": zod.number().nullable(),
|
|
"avgUsability": zod.number().nullable(),
|
|
"avgCombined": zod.number().nullable()
|
|
}),
|
|
"score": zod.number(),
|
|
"ratingCount": zod.number()
|
|
})
|
|
export const GetTopToolsResponse = zod.array(GetTopToolsResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Rating statistics grouped by category
|
|
*/
|
|
export const GetAnalyticsByCategoryResponseItem = zod.object({
|
|
"category": zod.string(),
|
|
"toolCount": zod.number(),
|
|
"totalRatings": zod.number(),
|
|
"avgUsefulness": zod.number().nullable(),
|
|
"avgUsability": zod.number().nullable()
|
|
})
|
|
export const GetAnalyticsByCategoryResponse = zod.array(GetAnalyticsByCategoryResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Distribution of rating scores across the platform
|
|
*/
|
|
export const GetRatingDistributionQueryParams = zod.object({
|
|
"toolId": zod.coerce.number().optional()
|
|
})
|
|
|
|
export const GetRatingDistributionResponse = zod.object({
|
|
"usefulness": zod.array(zod.object({
|
|
"score": zod.number(),
|
|
"count": zod.number()
|
|
})),
|
|
"usability": zod.array(zod.object({
|
|
"score": zod.number(),
|
|
"count": zod.number()
|
|
}))
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List all distinct tool categories
|
|
*/
|
|
export const ListCategoriesResponseItem = zod.string()
|
|
export const ListCategoriesResponse = zod.array(ListCategoriesResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary List all distinct feature strings across all tools
|
|
*/
|
|
export const ListAllFeaturesResponseItem = zod.string()
|
|
export const ListAllFeaturesResponse = zod.array(ListAllFeaturesResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary List all distinct tag strings across all tools
|
|
*/
|
|
export const ListAllTagsResponseItem = zod.string()
|
|
export const ListAllTagsResponse = zod.array(ListAllTagsResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Get authentication mode (oidc or local)
|
|
*/
|
|
export const GetAuthModeResponse = zod.object({
|
|
"mode": zod.enum(['oidc', 'local'])
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Local username/password login
|
|
*/
|
|
export const LocalLoginBody = zod.object({
|
|
"username": zod.string(),
|
|
"password": zod.string()
|
|
})
|
|
|
|
export const LocalLoginResponse = zod.object({
|
|
"sub": zod.string(),
|
|
"email": zod.string().nullish(),
|
|
"name": zod.string().nullish(),
|
|
"preferredUsername": zod.string().nullish(),
|
|
"role": zod.enum(['admin', 'user']).optional(),
|
|
"tier": zod.enum(['free', 'premium', 'enterprise']).optional(),
|
|
"entitlements": zod.array(zod.string()).optional(),
|
|
"isLocal": zod.boolean().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Get current authenticated user
|
|
*/
|
|
export const GetMeResponse = zod.object({
|
|
"sub": zod.string(),
|
|
"email": zod.string().nullish(),
|
|
"name": zod.string().nullish(),
|
|
"preferredUsername": zod.string().nullish(),
|
|
"role": zod.enum(['admin', 'user']).optional(),
|
|
"tier": zod.enum(['free', 'premium', 'enterprise']).optional(),
|
|
"entitlements": zod.array(zod.string()).optional(),
|
|
"isLocal": zod.boolean().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Get current user's browse preferences
|
|
*/
|
|
export const GetMePreferencesResponse = zod.object({
|
|
"view": zod.enum(['grid', 'table', 'rows']).optional(),
|
|
"density": zod.enum(['cozy', 'compact']).optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Update current user's browse preferences
|
|
*/
|
|
export const UpdateMePreferencesBody = zod.object({
|
|
"view": zod.enum(['grid', 'table', 'rows']).optional(),
|
|
"density": zod.enum(['cozy', 'compact']).optional()
|
|
})
|
|
|
|
export const UpdateMePreferencesResponse = zod.object({
|
|
"view": zod.enum(['grid', 'table', 'rows']).optional(),
|
|
"density": zod.enum(['cozy', 'compact']).optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List all local users (admin only)
|
|
*/
|
|
export const ListUsersResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"username": zod.string(),
|
|
"email": zod.string().nullish(),
|
|
"role": zod.enum(['admin', 'user']),
|
|
"tier": zod.enum(['free', 'premium', 'enterprise']).optional(),
|
|
"createdAt": zod.coerce.date()
|
|
})
|
|
export const ListUsersResponse = zod.array(ListUsersResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Create a new local user (admin only)
|
|
*/
|
|
export const createUserBodyUsernameMin = 2;
|
|
|
|
export const createUserBodyPasswordMin = 6;
|
|
|
|
|
|
|
|
export const CreateUserBody = zod.object({
|
|
"username": zod.string().min(createUserBodyUsernameMin),
|
|
"password": zod.string().min(createUserBodyPasswordMin),
|
|
"email": zod.string().optional(),
|
|
"role": zod.enum(['admin', 'user']).optional(),
|
|
"tier": zod.enum(['free', 'premium', 'enterprise']).optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Update user role (admin only)
|
|
*/
|
|
export const UpdateUserParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const UpdateUserBody = zod.object({
|
|
"role": zod.enum(['admin', 'user']).optional(),
|
|
"tier": zod.enum(['free', 'premium', 'enterprise']).optional()
|
|
})
|
|
|
|
export const UpdateUserResponse = zod.object({
|
|
"id": zod.number(),
|
|
"username": zod.string(),
|
|
"email": zod.string().nullish(),
|
|
"role": zod.enum(['admin', 'user']),
|
|
"tier": zod.enum(['free', 'premium', 'enterprise']).optional(),
|
|
"createdAt": zod.coerce.date()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Delete a user (admin only)
|
|
*/
|
|
export const DeleteUserParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List audit log entries (admin only)
|
|
*/
|
|
export const ListAuditLogsQueryParams = zod.object({
|
|
"entityType": zod.coerce.string().optional(),
|
|
"entityId": zod.coerce.number().optional(),
|
|
"limit": zod.coerce.number().optional()
|
|
})
|
|
|
|
export const ListAuditLogsResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"entityType": zod.string(),
|
|
"entityId": zod.number().nullish(),
|
|
"action": zod.string(),
|
|
"userId": zod.string(),
|
|
"username": zod.string(),
|
|
"changes": zod.string().nullish(),
|
|
"createdAt": zod.coerce.date()
|
|
})
|
|
export const ListAuditLogsResponse = zod.array(ListAuditLogsResponseItem)
|
|
|
|
|