F: Implement backend hooks for frontend
This commit is contained in:
parent
e4411c2c78
commit
1d11bd4ab5
|
@ -1,2 +1,2 @@
|
||||||
''' Serializers for persistent data manipulation (AI Prompts). '''
|
''' Serializers for persistent data manipulation (AI Prompts). '''
|
||||||
from .data_access import PromptTemplateSerializer
|
from .data_access import PromptTemplateListSerializer, PromptTemplateSerializer
|
||||||
|
|
|
@ -37,3 +37,12 @@ class PromptTemplateSerializer(serializers.ModelSerializer):
|
||||||
if validated_data['is_shared'] and not (user.is_superuser or user.is_staff):
|
if validated_data['is_shared'] and not (user.is_superuser or user.is_staff):
|
||||||
raise serializers.ValidationError(msg.promptSharedPermissionDenied())
|
raise serializers.ValidationError(msg.promptSharedPermissionDenied())
|
||||||
return super().update(instance, validated_data)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
class PromptTemplateListSerializer(serializers.ModelSerializer):
|
||||||
|
'''Serializer for listing PromptTemplates without the 'text' field.'''
|
||||||
|
class Meta:
|
||||||
|
''' serializer metadata. '''
|
||||||
|
model = PromptTemplate
|
||||||
|
fields = ['id', 'owner', 'is_shared', 'label', 'description']
|
||||||
|
read_only_fields = ['id', 'owner']
|
||||||
|
|
|
@ -98,6 +98,8 @@ class TestPromptTemplateViewSet(EndpointTester):
|
||||||
labels = [item['label'] for item in response.data]
|
labels = [item['label'] for item in response.data]
|
||||||
self.assertIn('Mine', labels)
|
self.assertIn('Mine', labels)
|
||||||
self.assertIn('Shared', labels)
|
self.assertIn('Shared', labels)
|
||||||
|
for item in response.data:
|
||||||
|
self.assertNotIn('text', item)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/prompts/{item}/', method='patch')
|
@decl_endpoint('/api/prompts/{item}/', method='patch')
|
||||||
|
|
|
@ -7,7 +7,7 @@ from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from ..models import PromptTemplate
|
from ..models import PromptTemplate
|
||||||
from ..serializers import PromptTemplateSerializer
|
from ..serializers import PromptTemplateListSerializer, PromptTemplateSerializer
|
||||||
|
|
||||||
|
|
||||||
class IsOwnerOrAdmin(permissions.BasePermission):
|
class IsOwnerOrAdmin(permissions.BasePermission):
|
||||||
|
@ -48,5 +48,5 @@ class PromptTemplateViewSet(viewsets.ModelViewSet):
|
||||||
owned = PromptTemplate.objects.filter(owner=user)
|
owned = PromptTemplate.objects.filter(owner=user)
|
||||||
shared = PromptTemplate.objects.filter(is_shared=True)
|
shared = PromptTemplate.objects.filter(is_shared=True)
|
||||||
templates = (owned | shared).distinct()
|
templates = (owned | shared).distinct()
|
||||||
serializer = self.get_serializer(templates, many=True)
|
serializer = PromptTemplateListSerializer(templates, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
|
@ -16,6 +16,7 @@ export const KEYS = {
|
||||||
library: 'library',
|
library: 'library',
|
||||||
users: 'users',
|
users: 'users',
|
||||||
cctext: 'cctext',
|
cctext: 'cctext',
|
||||||
|
prompts: 'prompts',
|
||||||
global_mutation: 'global_mutation',
|
global_mutation: 'global_mutation',
|
||||||
|
|
||||||
composite: {
|
composite: {
|
||||||
|
|
70
rsconcept/frontend/src/features/ai/backend/api.ts
Normal file
70
rsconcept/frontend/src/features/ai/backend/api.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import { queryOptions } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { axiosDelete, axiosGet, axiosPatch, axiosPost } from '@/backend/api-transport';
|
||||||
|
import { DELAYS, KEYS } from '@/backend/configuration';
|
||||||
|
import { infoMsg } from '@/utils/labels';
|
||||||
|
|
||||||
|
import {
|
||||||
|
type ICreatePromptTemplateDTO,
|
||||||
|
type IPromptTemplateDTO,
|
||||||
|
type IPromptTemplateListDTO,
|
||||||
|
type IUpdatePromptTemplateDTO,
|
||||||
|
schemaPromptTemplate,
|
||||||
|
schemaPromptTemplateList
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
export const promptsApi = {
|
||||||
|
baseKey: KEYS.prompts,
|
||||||
|
|
||||||
|
getAvailableTemplatesQueryOptions: () =>
|
||||||
|
queryOptions({
|
||||||
|
queryKey: [KEYS.prompts, 'available'] as const,
|
||||||
|
staleTime: DELAYS.staleShort,
|
||||||
|
queryFn: meta =>
|
||||||
|
axiosGet<IPromptTemplateListDTO>({
|
||||||
|
schema: schemaPromptTemplateList,
|
||||||
|
endpoint: '/api/prompts/available/',
|
||||||
|
options: { signal: meta.signal }
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
getPromptTemplateQueryOptions: (id: number) =>
|
||||||
|
queryOptions({
|
||||||
|
queryKey: [KEYS.prompts, id],
|
||||||
|
staleTime: DELAYS.staleShort,
|
||||||
|
queryFn: meta =>
|
||||||
|
axiosGet<IPromptTemplateDTO>({
|
||||||
|
schema: schemaPromptTemplate,
|
||||||
|
endpoint: `/api/prompts/${id}/`,
|
||||||
|
options: { signal: meta.signal }
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
createPromptTemplate: (data: ICreatePromptTemplateDTO) =>
|
||||||
|
axiosPost<ICreatePromptTemplateDTO, IPromptTemplateDTO>({
|
||||||
|
schema: schemaPromptTemplate,
|
||||||
|
endpoint: '/api/prompts/',
|
||||||
|
request: {
|
||||||
|
data: data,
|
||||||
|
successMessage: infoMsg.changesSaved
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
updatePromptTemplate: (id: number, data: IUpdatePromptTemplateDTO) =>
|
||||||
|
axiosPatch<IUpdatePromptTemplateDTO, IPromptTemplateDTO>({
|
||||||
|
schema: schemaPromptTemplate,
|
||||||
|
endpoint: `/api/prompts/${id}/`,
|
||||||
|
request: {
|
||||||
|
data: data,
|
||||||
|
successMessage: infoMsg.changesSaved
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
deletePromptTemplate: (id: number) =>
|
||||||
|
axiosDelete({
|
||||||
|
endpoint: `/api/prompts/${id}/`,
|
||||||
|
request: {
|
||||||
|
successMessage: infoMsg.changesSaved
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} as const;
|
|
@ -1,11 +1,54 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
/** Represents AI prompt. */
|
/** Represents AI prompt. */
|
||||||
export interface IPromptTemplate {
|
export type IPromptTemplate = IPromptTemplateDTO;
|
||||||
id: number;
|
|
||||||
owner: number | null;
|
export type IPromptTemplateInfo = z.infer<typeof schemaPromptTemplateInfo>;
|
||||||
is_shared: boolean;
|
|
||||||
label: string;
|
/** Full prompt template as returned by backend. */
|
||||||
description: string;
|
export type IPromptTemplateDTO = z.infer<typeof schemaPromptTemplate>;
|
||||||
text: string;
|
|
||||||
}
|
/** List item for available prompt templates (no text field). */
|
||||||
|
export type IPromptTemplateListDTO = z.infer<typeof schemaPromptTemplateList>;
|
||||||
|
|
||||||
|
/** Data for creating a prompt template. */
|
||||||
|
export type ICreatePromptTemplateDTO = z.infer<typeof schemaCreatePromptTemplate>;
|
||||||
|
|
||||||
|
/** Data for updating a prompt template. */
|
||||||
|
export type IUpdatePromptTemplateDTO = z.infer<typeof schemaUpdatePromptTemplate>;
|
||||||
|
|
||||||
// ========= SCHEMAS ========
|
// ========= SCHEMAS ========
|
||||||
|
|
||||||
|
export const schemaPromptTemplate = z.strictObject({
|
||||||
|
id: z.number(),
|
||||||
|
owner: z.number().nullable(),
|
||||||
|
label: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
text: z.string(),
|
||||||
|
is_shared: z.boolean()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const schemaCreatePromptTemplate = schemaPromptTemplate.pick({
|
||||||
|
label: true,
|
||||||
|
description: true,
|
||||||
|
text: true,
|
||||||
|
is_shared: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const schemaUpdatePromptTemplate = schemaPromptTemplate.pick({
|
||||||
|
owner: true,
|
||||||
|
label: true,
|
||||||
|
description: true,
|
||||||
|
text: true,
|
||||||
|
is_shared: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const schemaPromptTemplateInfo = schemaPromptTemplate.pick({
|
||||||
|
id: true,
|
||||||
|
owner: true,
|
||||||
|
label: true,
|
||||||
|
description: true,
|
||||||
|
is_shared: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const schemaPromptTemplateList = schemaPromptTemplateInfo.array();
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { promptsApi } from './api';
|
||||||
|
|
||||||
|
export function useAvailableTemplates() {
|
||||||
|
const { data, isLoading, error } = useQuery({
|
||||||
|
...promptsApi.getAvailableTemplatesQueryOptions()
|
||||||
|
});
|
||||||
|
return { data, isLoading, error };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAvailableTemplatesSuspense() {
|
||||||
|
const { data } = useSuspenseQuery({
|
||||||
|
...promptsApi.getAvailableTemplatesQueryOptions()
|
||||||
|
});
|
||||||
|
return { data };
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { promptsApi } from './api';
|
||||||
|
|
||||||
|
export function useCreatePromptTemplate() {
|
||||||
|
const client = useQueryClient();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationKey: [promptsApi.baseKey, 'create'],
|
||||||
|
mutationFn: promptsApi.createPromptTemplate,
|
||||||
|
onSuccess: () => {
|
||||||
|
void client.invalidateQueries({ queryKey: [promptsApi.baseKey] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
createPromptTemplate: mutation.mutateAsync,
|
||||||
|
isPending: mutation.isPending,
|
||||||
|
error: mutation.error,
|
||||||
|
reset: mutation.reset
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { promptsApi } from './api';
|
||||||
|
|
||||||
|
export function useDeletePromptTemplate() {
|
||||||
|
const client = useQueryClient();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationKey: [promptsApi.baseKey, 'delete'],
|
||||||
|
mutationFn: promptsApi.deletePromptTemplate,
|
||||||
|
onSuccess: (_data, id) => {
|
||||||
|
void client.invalidateQueries({ queryKey: [promptsApi.baseKey] });
|
||||||
|
void client.invalidateQueries({ queryKey: [promptsApi.baseKey, id] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
deletePromptTemplate: mutation.mutateAsync,
|
||||||
|
isPending: mutation.isPending,
|
||||||
|
error: mutation.error,
|
||||||
|
reset: mutation.reset
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { promptsApi } from './api';
|
||||||
|
|
||||||
|
export function usePromptTemplate(id: number) {
|
||||||
|
const { data, isLoading, error } = useQuery({
|
||||||
|
...promptsApi.getPromptTemplateQueryOptions(id)
|
||||||
|
});
|
||||||
|
return { data, isLoading, error };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePromptTemplateSuspense(id: number) {
|
||||||
|
const { data } = useSuspenseQuery({
|
||||||
|
...promptsApi.getPromptTemplateQueryOptions(id)
|
||||||
|
});
|
||||||
|
return { data };
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { promptsApi } from './api';
|
||||||
|
import { type IUpdatePromptTemplateDTO } from './types';
|
||||||
|
|
||||||
|
export function useUpdatePromptTemplate() {
|
||||||
|
const client = useQueryClient();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationKey: [promptsApi.baseKey, 'update'],
|
||||||
|
mutationFn: ({ id, data }: { id: number; data: IUpdatePromptTemplateDTO }) =>
|
||||||
|
promptsApi.updatePromptTemplate(id, data),
|
||||||
|
onSuccess: (_, variables) => {
|
||||||
|
void client.invalidateQueries({ queryKey: [promptsApi.baseKey, variables.id] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
updatePromptTemplate: mutation.mutateAsync,
|
||||||
|
isPending: mutation.isPending,
|
||||||
|
error: mutation.error,
|
||||||
|
reset: mutation.reset
|
||||||
|
};
|
||||||
|
}
|
|
@ -89,9 +89,7 @@ export interface ICheckConstituentaDTO {
|
||||||
/** Represents data, used in merging multiple {@link IConstituenta}. */
|
/** Represents data, used in merging multiple {@link IConstituenta}. */
|
||||||
export type ISubstitutionsDTO = z.infer<typeof schemaSubstitutions>;
|
export type ISubstitutionsDTO = z.infer<typeof schemaSubstitutions>;
|
||||||
|
|
||||||
/**
|
/** Represents Constituenta list. */
|
||||||
* Represents Constituenta list.
|
|
||||||
*/
|
|
||||||
export interface IConstituentaList {
|
export interface IConstituentaList {
|
||||||
items: number[];
|
items: number[];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user