F: Implementing prompt UI pt1
This commit is contained in:
parent
1d11bd4ab5
commit
c980ebab5a
|
@ -85,6 +85,10 @@ export const Router = createBrowserRouter([
|
|||
path: `${routes.database_schema}`,
|
||||
lazy: () => import('@/features/home/database-schema-page')
|
||||
},
|
||||
{
|
||||
path: routes.prompt_templates,
|
||||
lazy: () => import('@/features/ai/pages/prompt-templates-page')
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
element: <NotFoundPage />
|
||||
|
|
|
@ -39,6 +39,8 @@ export const urls = {
|
|||
library_filter: (strategy: string) => `/library?filter=${strategy}`,
|
||||
create_schema: `/${routes.create_schema}`,
|
||||
prompt_templates: `/${routes.prompt_templates}`,
|
||||
prompt_template: (active: number | null, tab: number) =>
|
||||
`/prompt-templates?tab=${tab}${active ? `&active=${active}` : ''}`,
|
||||
manuals: `/${routes.manuals}`,
|
||||
help_topic: (topic: string) => `/manuals?topic=${topic}`,
|
||||
schema: (id: number | string, version?: number | string) =>
|
||||
|
|
|
@ -6,12 +6,12 @@ export function usePromptTemplate(id: number) {
|
|||
const { data, isLoading, error } = useQuery({
|
||||
...promptsApi.getPromptTemplateQueryOptions(id)
|
||||
});
|
||||
return { data, isLoading, error };
|
||||
return { promptTemplate: data, isLoading, error };
|
||||
}
|
||||
|
||||
export function usePromptTemplateSuspense(id: number) {
|
||||
const { data } = useSuspenseQuery({
|
||||
...promptsApi.getPromptTemplateQueryOptions(id)
|
||||
});
|
||||
return { data };
|
||||
return { promptTemplate: data };
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export { PromptTemplatesPage as Component } from './prompt-templates-page';
|
|
@ -0,0 +1,22 @@
|
|||
import { MiniButton } from '@/components/control';
|
||||
import { IconNewItem } from '@/components/icons';
|
||||
import { notImplemented } from '@/utils/utils';
|
||||
|
||||
export function MenuTemplates() {
|
||||
function handleNewTemplate() {
|
||||
notImplemented();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex border-r-2 px-2'>
|
||||
<MiniButton
|
||||
noHover
|
||||
noPadding
|
||||
title='Новый шаблон'
|
||||
icon={<IconNewItem size='1.25rem' />}
|
||||
className='h-full text-muted-foreground hover:text-constructive cc-animate-color bg-transparent'
|
||||
onClick={handleNewTemplate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import { useBlockNavigation } from '@/app';
|
||||
import { RequireAuth } from '@/features/auth/components/require-auth';
|
||||
|
||||
import { useQueryStrings } from '@/hooks/use-query-strings';
|
||||
import { useModificationStore } from '@/stores/modification';
|
||||
|
||||
import { PromptTabID, TemplatesTabs } from './templates-tabs';
|
||||
|
||||
const paramsSchema = z.strictObject({
|
||||
tab: z.preprocess(v => (v ? Number(v) : undefined), z.nativeEnum(PromptTabID).default(PromptTabID.LIST)),
|
||||
active: z.preprocess(v => (v ? Number(v) : undefined), z.number().nullable().default(null))
|
||||
});
|
||||
|
||||
export function PromptTemplatesPage() {
|
||||
const query = useQueryStrings();
|
||||
|
||||
const urlData = paramsSchema.parse({
|
||||
tab: query.get('tab'),
|
||||
active: query.get('active')
|
||||
});
|
||||
|
||||
const { isModified } = useModificationStore();
|
||||
useBlockNavigation(isModified);
|
||||
|
||||
return (
|
||||
<RequireAuth>
|
||||
<TemplatesTabs activeID={urlData.active} tab={urlData.tab} />
|
||||
</RequireAuth>
|
||||
);
|
||||
}
|
||||
|
||||
export default PromptTemplatesPage;
|
|
@ -0,0 +1,11 @@
|
|||
import { usePromptTemplateSuspense } from '../../backend/use-prompt-template';
|
||||
|
||||
interface TabEditTemplateProps {
|
||||
activeID: number;
|
||||
}
|
||||
|
||||
export function TabEditTemplate({ activeID }: TabEditTemplateProps) {
|
||||
const { promptTemplate } = usePromptTemplateSuspense(activeID);
|
||||
|
||||
return <div className='p-4 border rounded'>Prompt Editor {promptTemplate.label}</div>;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { TabListTemplates } from './tab-list-templates';
|
|
@ -0,0 +1,36 @@
|
|||
import { urls, useConceptNavigation } from '@/app';
|
||||
import { type IPromptTemplate } from '@/features/ai/backend/types';
|
||||
|
||||
import { DataTable } from '@/components/data-table';
|
||||
|
||||
import { PromptTabID } from '../templates-tabs';
|
||||
|
||||
// Placeholder for prompt list data
|
||||
const mockPrompts: IPromptTemplate[] = [
|
||||
{ id: 1, owner: null, label: 'Prompt 1', description: 'Description 1', text: '', is_shared: false },
|
||||
{ id: 2, owner: null, label: 'Prompt 2', description: 'Description 2', text: '', is_shared: false }
|
||||
];
|
||||
|
||||
interface TabListTemplatesProps {
|
||||
activeID: number | null;
|
||||
}
|
||||
|
||||
export function TabListTemplates({ activeID }: TabListTemplatesProps) {
|
||||
const router = useConceptNavigation();
|
||||
console.log(activeID);
|
||||
|
||||
function handleRowDoubleClicked(row: IPromptTemplate, event: React.MouseEvent<Element>) {
|
||||
router.push({ path: urls.prompt_template(row.id, PromptTabID.EDIT), newTab: event.ctrlKey || event.metaKey });
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
data={mockPrompts}
|
||||
columns={[
|
||||
{ accessorKey: 'label', header: 'Name' },
|
||||
{ accessorKey: 'description', header: 'Description' }
|
||||
]}
|
||||
onRowDoubleClicked={handleRowDoubleClicked}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export function TabViewVariables() {
|
||||
return <div className='p-4 border rounded'>View all variables</div>;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
import { Suspense } from 'react';
|
||||
|
||||
import { urls, useConceptNavigation } from '@/app';
|
||||
|
||||
import { Loader } from '@/components/loader';
|
||||
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
||||
|
||||
import { MenuTemplates } from './menu-templates';
|
||||
import { TabEditTemplate } from './tab-edit-template';
|
||||
import { TabListTemplates } from './tab-list-templates';
|
||||
import { TabViewVariables } from './tab-view-variables';
|
||||
|
||||
export const PromptTabID = {
|
||||
LIST: 0,
|
||||
EDIT: 1,
|
||||
VARIABLES: 2
|
||||
} as const;
|
||||
export type PromptTabID = (typeof PromptTabID)[keyof typeof PromptTabID];
|
||||
|
||||
interface TemplatesTabsProps {
|
||||
activeID: number | null;
|
||||
tab: PromptTabID;
|
||||
}
|
||||
|
||||
export function TemplatesTabs({ activeID, tab }: TemplatesTabsProps) {
|
||||
const router = useConceptNavigation();
|
||||
|
||||
function onSelectTab(index: number, last: number, event: Event) {
|
||||
if (last === index) {
|
||||
return;
|
||||
}
|
||||
if (event.type == 'keydown') {
|
||||
const kbEvent = event as KeyboardEvent;
|
||||
if (kbEvent.altKey) {
|
||||
if (kbEvent.code === 'ArrowLeft') {
|
||||
router.back();
|
||||
return;
|
||||
} else if (kbEvent.code === 'ArrowRight') {
|
||||
router.forward();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
router.replace({ path: urls.prompt_template(activeID, index as PromptTabID) });
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs selectedIndex={tab} onSelect={onSelectTab} className='relative flex flex-col min-w-fit items-center'>
|
||||
<TabList className='absolute z-sticky flex border-b-2 border-x-2 divide-x-2 bg-background'>
|
||||
<MenuTemplates />
|
||||
<TabLabel label='Список' />
|
||||
<TabLabel label='Редактор' />
|
||||
<TabLabel label='Переменные' />
|
||||
</TabList>
|
||||
<div className='overflow-x-hidden'>
|
||||
<TabPanel>
|
||||
<TabListTemplates activeID={activeID} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
{activeID ? (
|
||||
<Suspense fallback={<Loader circular scale={1.5} />}>
|
||||
<TabEditTemplate activeID={activeID} />
|
||||
</Suspense>
|
||||
) : null}
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<TabViewVariables />
|
||||
</TabPanel>
|
||||
</div>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user