Add API endpoints and frontend components for tool management and analytics
Implement CRUD operations for tools and ratings, introduce analytics endpoints, and develop frontend components for displaying tools, ratings, and analytics data. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 776963d0-f75d-42e2-a57b-cc36bdff8495 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: feaa4ce1-5aed-4cc0-bcea-47855b615b48 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0683fb79-a27c-485c-9333-5f4b288c4567/776963d0-f75d-42e2-a57b-cc36bdff8495/rx9K7bW Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -1,16 +1,271 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import * as zod from "zod";
|
||||
import * as zod from 'zod';
|
||||
|
||||
|
||||
/**
|
||||
* Returns server health status
|
||||
* @summary Health check
|
||||
*/
|
||||
export const HealthCheckResponse = zod.object({
|
||||
status: zod.string(),
|
||||
});
|
||||
"status": zod.string()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @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']).optional()
|
||||
})
|
||||
|
||||
export const ListToolsResponseItem = zod.object({
|
||||
"id": zod.number(),
|
||||
"name": zod.string(),
|
||||
"description": zod.string(),
|
||||
"category": zod.string(),
|
||||
"websiteUrl": 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(),
|
||||
"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(),
|
||||
"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().optional(),
|
||||
"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(),
|
||||
"features": zod.array(zod.string()).optional(),
|
||||
"tags": zod.array(zod.string()).optional(),
|
||||
"createdAt": zod.coerce.date(),
|
||||
"updatedAt": zod.coerce.date()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @summary Delete a tool
|
||||
*/
|
||||
export const DeleteToolParams = zod.object({
|
||||
"id": zod.coerce.number()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @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(),
|
||||
"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(),
|
||||
"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)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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 type { ToolWithStats } from './toolWithStats';
|
||||
|
||||
export interface AnalyticsSummary {
|
||||
totalTools: number;
|
||||
totalRatings: number;
|
||||
/** @nullable */
|
||||
avgUsefulness: number | null;
|
||||
/** @nullable */
|
||||
avgUsability: number | null;
|
||||
/** @nullable */
|
||||
avgCombined: number | null;
|
||||
categoriesCount: number;
|
||||
mostRatedTool?: ToolWithStats;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface CategoryStats {
|
||||
category: string;
|
||||
toolCount: number;
|
||||
totalRatings: number;
|
||||
/** @nullable */
|
||||
avgUsefulness: number | null;
|
||||
/** @nullable */
|
||||
avgUsability: number | null;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface ErrorResponse {
|
||||
error: string;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type GetRatingDistributionParams = {
|
||||
toolId?: number;
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type GetTopToolsMetric = typeof GetTopToolsMetric[keyof typeof GetTopToolsMetric];
|
||||
|
||||
|
||||
export const GetTopToolsMetric = {
|
||||
usefulness: 'usefulness',
|
||||
usability: 'usability',
|
||||
combined: 'combined',
|
||||
} as const;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 type { GetTopToolsMetric } from './getTopToolsMetric';
|
||||
|
||||
export type GetTopToolsParams = {
|
||||
limit?: number;
|
||||
metric?: GetTopToolsMetric;
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export * from "./healthStatus";
|
||||
export * from './analyticsSummary';
|
||||
export * from './categoryStats';
|
||||
export * from './errorResponse';
|
||||
export * from './getRatingDistributionParams';
|
||||
export * from './getTopToolsMetric';
|
||||
export * from './getTopToolsParams';
|
||||
export * from './healthStatus';
|
||||
export * from './listToolsParams';
|
||||
export * from './listToolsSort';
|
||||
export * from './rating';
|
||||
export * from './ratingDistribution';
|
||||
export * from './ratingInput';
|
||||
export * from './scoreBucket';
|
||||
export * from './tool';
|
||||
export * from './toolInput';
|
||||
export * from './toolUpdate';
|
||||
export * from './toolWithStats';
|
||||
export * from './topToolEntry';
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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 type { ListToolsSort } from './listToolsSort';
|
||||
|
||||
export type ListToolsParams = {
|
||||
category?: string;
|
||||
search?: string;
|
||||
sort?: ListToolsSort;
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ListToolsSort = typeof ListToolsSort[keyof typeof ListToolsSort];
|
||||
|
||||
|
||||
export const ListToolsSort = {
|
||||
newest: 'newest',
|
||||
top_rated: 'top_rated',
|
||||
most_reviewed: 'most_reviewed',
|
||||
} as const;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface Rating {
|
||||
id: number;
|
||||
toolId: number;
|
||||
/**
|
||||
* @minimum 1
|
||||
* @maximum 5
|
||||
*/
|
||||
usefulness: number;
|
||||
/**
|
||||
* @minimum 1
|
||||
* @maximum 5
|
||||
*/
|
||||
usability: number;
|
||||
/** @nullable */
|
||||
comment?: string | null;
|
||||
/** @nullable */
|
||||
reviewerName?: string | null;
|
||||
createdAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 type { ScoreBucket } from './scoreBucket';
|
||||
|
||||
export interface RatingDistribution {
|
||||
usefulness: ScoreBucket[];
|
||||
usability: ScoreBucket[];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface RatingInput {
|
||||
/**
|
||||
* @minimum 1
|
||||
* @maximum 5
|
||||
*/
|
||||
usefulness: number;
|
||||
/**
|
||||
* @minimum 1
|
||||
* @maximum 5
|
||||
*/
|
||||
usability: number;
|
||||
comment?: string;
|
||||
reviewerName?: string;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface ScoreBucket {
|
||||
score: number;
|
||||
count: number;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface Tool {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
/** @nullable */
|
||||
websiteUrl?: string | null;
|
||||
features?: string[];
|
||||
tags?: string[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface ToolInput {
|
||||
/** @minLength 1 */
|
||||
name: string;
|
||||
/** @minLength 1 */
|
||||
description: string;
|
||||
/** @minLength 1 */
|
||||
category: string;
|
||||
websiteUrl?: string;
|
||||
features?: string[];
|
||||
tags?: string[];
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface ToolUpdate {
|
||||
/** @minLength 1 */
|
||||
name?: string;
|
||||
description?: string;
|
||||
category?: string;
|
||||
websiteUrl?: string;
|
||||
features?: string[];
|
||||
tags?: string[];
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface ToolWithStats {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
/** @nullable */
|
||||
websiteUrl?: string | null;
|
||||
features?: string[];
|
||||
tags?: string[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ratingCount: number;
|
||||
/** @nullable */
|
||||
avgUsefulness: number | null;
|
||||
/** @nullable */
|
||||
avgUsability: number | null;
|
||||
/** @nullable */
|
||||
avgCombined: number | null;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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 type { ToolWithStats } from './toolWithStats';
|
||||
|
||||
export interface TopToolEntry {
|
||||
tool: ToolWithStats;
|
||||
score: number;
|
||||
ratingCount: number;
|
||||
}
|
||||
Reference in New Issue
Block a user