Add user authentication and dynamic feature/category inputs

Implement Keycloak authentication, protected routes, and add combobox and autocomplete components for tool categories and features.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 776963d0-f75d-42e2-a57b-cc36bdff8495
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 0b145113-c016-4f54-b000-13bd3b0ba8f0
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0683fb79-a27c-485c-9333-5f4b288c4567/776963d0-f75d-42e2-a57b-cc36bdff8495/z4uWN6A
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
cheffe01
2026-05-25 13:20:15 +00:00
parent e03c51a75e
commit 7abb048edc
22 changed files with 1027 additions and 68 deletions
@@ -138,6 +138,16 @@ export interface RatingDistribution {
usability: ScoreBucket[];
}
export interface AuthUser {
sub: string;
/** @nullable */
email?: string | null;
/** @nullable */
name?: string | null;
/** @nullable */
preferredUsername?: string | null;
}
export interface ErrorResponse {
error: string;
}
+155
View File
@@ -21,6 +21,7 @@ import type {
import type {
AnalyticsSummary,
AuthUser,
CategoryStats,
ErrorResponse,
GetRatingDistributionParams,
@@ -1049,3 +1050,157 @@ export function useListCategories<TData = Awaited<ReturnType<typeof listCategori
export const getListAllFeaturesUrl = () => {
return `/api/features/all`
}
/**
* @summary List all distinct feature strings across all tools
*/
export const listAllFeatures = async ( options?: RequestInit): Promise<string[]> => {
return customFetch<string[]>(getListAllFeaturesUrl(),
{
...options,
method: 'GET'
}
);}
export const getListAllFeaturesQueryKey = () => {
return [
`/api/features/all`
] as const;
}
export const getListAllFeaturesQueryOptions = <TData = Awaited<ReturnType<typeof listAllFeatures>>, TError = ErrorType<unknown>>( options?: { query?:UseQueryOptions<Awaited<ReturnType<typeof listAllFeatures>>, TError, TData>, request?: SecondParameter<typeof customFetch>}
) => {
const {query: queryOptions, request: requestOptions} = options ?? {};
const queryKey = queryOptions?.queryKey ?? getListAllFeaturesQueryKey();
const queryFn: QueryFunction<Awaited<ReturnType<typeof listAllFeatures>>> = ({ signal }) => listAllFeatures({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions} as UseQueryOptions<Awaited<ReturnType<typeof listAllFeatures>>, TError, TData> & { queryKey: QueryKey }
}
export type ListAllFeaturesQueryResult = NonNullable<Awaited<ReturnType<typeof listAllFeatures>>>
export type ListAllFeaturesQueryError = ErrorType<unknown>
/**
* @summary List all distinct feature strings across all tools
*/
export function useListAllFeatures<TData = Awaited<ReturnType<typeof listAllFeatures>>, TError = ErrorType<unknown>>(
options?: { query?:UseQueryOptions<Awaited<ReturnType<typeof listAllFeatures>>, TError, TData>, request?: SecondParameter<typeof customFetch>}
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListAllFeaturesQueryOptions(options)
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & { queryKey: QueryKey };
return { ...query, queryKey: queryOptions.queryKey };
}
export const getGetMeUrl = () => {
return `/api/auth/me`
}
/**
* @summary Get current authenticated user
*/
export const getMe = async ( options?: RequestInit): Promise<AuthUser> => {
return customFetch<AuthUser>(getGetMeUrl(),
{
...options,
method: 'GET'
}
);}
export const getGetMeQueryKey = () => {
return [
`/api/auth/me`
] as const;
}
export const getGetMeQueryOptions = <TData = Awaited<ReturnType<typeof getMe>>, TError = ErrorType<ErrorResponse>>( options?: { query?:UseQueryOptions<Awaited<ReturnType<typeof getMe>>, TError, TData>, request?: SecondParameter<typeof customFetch>}
) => {
const {query: queryOptions, request: requestOptions} = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetMeQueryKey();
const queryFn: QueryFunction<Awaited<ReturnType<typeof getMe>>> = ({ signal }) => getMe({ signal, ...requestOptions });
return { queryKey, queryFn, ...queryOptions} as UseQueryOptions<Awaited<ReturnType<typeof getMe>>, TError, TData> & { queryKey: QueryKey }
}
export type GetMeQueryResult = NonNullable<Awaited<ReturnType<typeof getMe>>>
export type GetMeQueryError = ErrorType<ErrorResponse>
/**
* @summary Get current authenticated user
*/
export function useGetMe<TData = Awaited<ReturnType<typeof getMe>>, TError = ErrorType<ErrorResponse>>(
options?: { query?:UseQueryOptions<Awaited<ReturnType<typeof getMe>>, TError, TData>, request?: SecondParameter<typeof customFetch>}
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetMeQueryOptions(options)
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & { queryKey: QueryKey };
return { ...query, queryKey: queryOptions.queryKey };
}