From 5e50936328fceb15779fc9a39ab315cb884fe58d Mon Sep 17 00:00:00 2001 From: reffat <--replace-all> Date: Wed, 16 Oct 2024 19:34:40 +0300 Subject: [PATCH] fix: generics in GPT --- .../additional/GPT/GptDialog/GptDialog.tsx | 8 ++-- .../additional/GPT/MarkupGpt/index.ts | 6 ++- .../additional/GPT/MarkupGpt/plugin.ts | 6 ++- .../additional/GPT/MarkupGpt/popup.tsx | 11 +++-- .../additional/GPT/PresetList/PresetList.tsx | 42 +++++++++++++------ .../GPT/gptExtension/gptExtension.ts | 11 +++-- .../additional/GPT/gptExtension/view.tsx | 30 +++++++++---- .../additional/GPT/hooks/useGpt.tsx | 2 +- .../additional/GPT/hooks/usePresetList.ts | 16 +++++-- src/extensions/additional/GPT/plugin.ts | 8 +++- src/extensions/additional/GPT/utils.ts | 9 ++-- 11 files changed, 106 insertions(+), 43 deletions(-) diff --git a/src/extensions/additional/GPT/GptDialog/GptDialog.tsx b/src/extensions/additional/GPT/GptDialog/GptDialog.tsx index b305889be..4ab14a49b 100644 --- a/src/extensions/additional/GPT/GptDialog/GptDialog.tsx +++ b/src/extensions/additional/GPT/GptDialog/GptDialog.tsx @@ -1,4 +1,3 @@ -import type {FC} from 'react'; import React, {useCallback, useRef, useState} from 'react'; import {ArrowRight, ArrowRotateLeft, ThumbsDown, ThumbsUp} from '@gravity-ui/icons'; @@ -50,7 +49,10 @@ export type GptDialogProps< export const cnGptDialog = cn('gpt-dialog'); -export const GptDialog: FC = ({ +export const GptDialog = < + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>({ markup, answerRender, promptPresets, @@ -66,7 +68,7 @@ export const GptDialog: FC = ({ onDislike, onUpdate, gptAlertProps, -}) => { +}: GptDialogProps) => { const { answer, customPrompt, diff --git a/src/extensions/additional/GPT/MarkupGpt/index.ts b/src/extensions/additional/GPT/MarkupGpt/index.ts index 802a0f995..4ea1b5d19 100644 --- a/src/extensions/additional/GPT/MarkupGpt/index.ts +++ b/src/extensions/additional/GPT/MarkupGpt/index.ts @@ -1,6 +1,7 @@ import {keymap} from '@codemirror/view'; import {GptWidgetOptions} from '../../..'; +import {CommonAnswer} from '../ErrorScreen/types'; import {gptHotKeys} from '../constants'; import {runMarkupGpt} from './commands'; @@ -9,7 +10,10 @@ import {mGptPlugin} from './plugin'; export {mGptToolbarItem} from './toolbar'; export {showMarkupGpt, hideMarkupGpt} from './commands'; -export function mGptExtension(props: GptWidgetOptions) { +export function mGptExtension< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>(props: GptWidgetOptions) { return [ mGptPlugin(props).extension, keymap.of([ diff --git a/src/extensions/additional/GPT/MarkupGpt/plugin.ts b/src/extensions/additional/GPT/MarkupGpt/plugin.ts index f523d23f6..e79cfcdb4 100644 --- a/src/extensions/additional/GPT/MarkupGpt/plugin.ts +++ b/src/extensions/additional/GPT/MarkupGpt/plugin.ts @@ -10,6 +10,7 @@ import { type ViewUpdate, } from '../../../../cm/view'; import {ReactRendererFacet} from '../../../../markup'; +import {CommonAnswer} from '../ErrorScreen/types'; import {WIDGET_DECO_CLASS_NAME} from '../constants'; import {isEmptyGptPrompts} from '../utils'; @@ -35,7 +36,10 @@ class SpanWidget extends WidgetType { } } -export function mGptPlugin(gptProps: GptWidgetOptions) { +export function mGptPlugin< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>(gptProps: GptWidgetOptions) { return ViewPlugin.fromClass( class implements PluginValue { readonly _view: EditorView; diff --git a/src/extensions/additional/GPT/MarkupGpt/popup.tsx b/src/extensions/additional/GPT/MarkupGpt/popup.tsx index 705fe0c13..a16cc0907 100644 --- a/src/extensions/additional/GPT/MarkupGpt/popup.tsx +++ b/src/extensions/additional/GPT/MarkupGpt/popup.tsx @@ -6,16 +6,19 @@ import {CommonAnswer} from '../ErrorScreen/types'; import {GptDialog, GptDialogProps} from '../GptDialog/GptDialog'; import {cnGptPopup} from '../gptExtension/view'; -type Props = { +type Props = { onClose: () => void; markup: string; onConfirmOk?: () => void; onConfirmCancel?: () => void; -} & GptDialogProps & +} & GptDialogProps & Pick; -export function renderPopup(anchor: HTMLElement, props: Props) { - const handleUpdate = (result?: CommonAnswer) => props.onUpdate?.(result); +export function renderPopup< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>(anchor: HTMLElement, props: Props) { + const handleUpdate = (result?: AnswerData) => props.onUpdate?.(result); return ( = { - disablePromptPresets: GptDialogProps['disablePromptPresets']; - promptPresets: GptDialogProps['promptPresets']; - onPresetClick: (data: PromptData) => void; +export type PresetListProps< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +> = { + disablePromptPresets: GptDialogProps['disablePromptPresets']; + promptPresets: GptDialogProps['promptPresets']; + onPresetClick: (data?: PromptData) => void; }; -type PresetItemType = { - preset: PromptPreset; - onPresetClick: PresetListProps['onPresetClick']; +type PresetItemType< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +> = { + preset: PromptPreset; + onPresetClick: PresetListProps['onPresetClick']; disablePromptPresets?: PresetListProps['disablePromptPresets']; hotKey: string; }; export const cnGptDialogPresetList = cn('gpt-dialog-preset-list'); -const PresetItem: FC = ({preset, onPresetClick, disablePromptPresets, hotKey}) => { +const PresetItem = < + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>({ + preset, + onPresetClick, + disablePromptPresets, + hotKey, +}: PresetItemType) => { useGptHotKeys( hotKey, () => { @@ -52,13 +65,16 @@ const PresetItem: FC = ({preset, onPresetClick, disablePromptPre ); }; -export const PresetList: FC = ({ +export const PresetList = < + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>({ disablePromptPresets, promptPresets, onPresetClick, -}) => { +}: PresetListProps) => { const {presetsContainerRef, visiblePresets, hiddenPresets, showMoreButton, measured} = - usePresetList({ + usePresetList({ promptPresets, onPresetClick, }); diff --git a/src/extensions/additional/GPT/gptExtension/gptExtension.ts b/src/extensions/additional/GPT/gptExtension/gptExtension.ts index fa4f38d0b..b561b60e4 100644 --- a/src/extensions/additional/GPT/gptExtension/gptExtension.ts +++ b/src/extensions/additional/GPT/gptExtension/gptExtension.ts @@ -1,5 +1,4 @@ -import {Action, ExtensionWithOptions} from 'src/core'; - +import {Action, ExtensionBuilder} from '../../../../core'; import type {CommonAnswer} from '../ErrorScreen/types'; import {showGptWidget} from '../actions'; import {runGpt} from '../commands'; @@ -31,7 +30,13 @@ export type GptWidgetOptions< | 'gptAlertProps' >; -export const gptExtension: ExtensionWithOptions = (builder, options) => { +export const gptExtension = < + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>( + builder: ExtensionBuilder, + options: GptWidgetOptions, +) => { builder.addAction(gptActionName, showGptWidget); builder.addPlugin(({serializer, markupParser}) => { return gptWidgetPlugin({ diff --git a/src/extensions/additional/GPT/gptExtension/view.tsx b/src/extensions/additional/GPT/gptExtension/view.tsx index e49d04668..6c07558b4 100644 --- a/src/extensions/additional/GPT/gptExtension/view.tsx +++ b/src/extensions/additional/GPT/gptExtension/view.tsx @@ -34,17 +34,21 @@ export type GptWidgetDecoViewParams< gptPopupContainer?: PopupProps['container']; }; -export class GptWidgetDecoView implements Required { +export class GptWidgetDecoView< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +> implements Required +{ private readonly _view; private readonly _renderer; private _decoElem: Element | null = null; - private _params: GptWidgetDecoViewParams; + private _params: GptWidgetDecoViewParams; private _serializer: Serializer; private _parser: Parser; private _confirmOpen: boolean; - constructor(view: EditorView, params: GptWidgetDecoViewParams) { + constructor(view: EditorView, params: GptWidgetDecoViewParams) { this._view = view; this._params = params; @@ -144,7 +148,9 @@ export class GptWidgetDecoView implements Required { ); } - private _onGptAnswerUpdate: NonNullable = (answer) => { + private _onGptAnswerUpdate: NonNullable['onUpdate']> = ( + answer, + ) => { this._params.onUpdate?.(answer); }; @@ -233,15 +239,21 @@ export class GptWidgetDecoView implements Required { } } -type WidgetProps = Pick & { +type WidgetProps< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +> = Pick & { markup: string; onClose: () => void; confirmOpen: boolean; onConfirmOk: () => void; onConfirmCancel: () => void; -} & GptDialogProps; +} & GptDialogProps; -function Widget({ +function Widget< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>({ markup, anchorRef, answerRender, @@ -259,7 +271,7 @@ function Widget({ onUpdate, container, gptAlertProps, -}: WidgetProps) { +}: WidgetProps) { useMount(() => { if (anchorRef?.current && 'scrollIntoView' in anchorRef.current) { anchorRef.current.scrollIntoView({ @@ -270,7 +282,7 @@ function Widget({ }); const handleUpdate = useCallback( - (result?: CommonAnswer) => { + (result?: AnswerData) => { onUpdate?.(result); }, [onUpdate], diff --git a/src/extensions/additional/GPT/hooks/useGpt.tsx b/src/extensions/additional/GPT/hooks/useGpt.tsx index c6d6fa221..dabb56b0b 100644 --- a/src/extensions/additional/GPT/hooks/useGpt.tsx +++ b/src/extensions/additional/GPT/hooks/useGpt.tsx @@ -150,7 +150,7 @@ export const useGpt = < [handleCustomPromptApply], ); - const handlePresetClick = useCallback['onPresetClick']>( + const handlePresetClick = useCallback['onPresetClick']>( async (data) => { const gptRequestData: GptRequestData = { markup, diff --git a/src/extensions/additional/GPT/hooks/usePresetList.ts b/src/extensions/additional/GPT/hooks/usePresetList.ts index 6ae6441de..10aa220ff 100644 --- a/src/extensions/additional/GPT/hooks/usePresetList.ts +++ b/src/extensions/additional/GPT/hooks/usePresetList.ts @@ -2,17 +2,27 @@ import {useMemo, useRef} from 'react'; import type {DropdownMenuItem} from '@gravity-ui/uikit'; +import {CommonAnswer} from '../ErrorScreen/types'; import type {GptDialogProps} from '../GptDialog/GptDialog'; import type {PresetListProps} from '../PresetList/PresetList'; import {cnGptDialogPresetList} from '../PresetList/PresetList'; import {useOverflowingHorizontalItems} from './useOverflowingHorizontalItems'; -type UsePresetListProps = Pick & { - onPresetClick: PresetListProps['onPresetClick']; +type UsePresetListProps< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +> = Pick, 'promptPresets'> & { + onPresetClick: PresetListProps['onPresetClick']; }; -export const usePresetList = ({promptPresets, onPresetClick}: UsePresetListProps) => { +export const usePresetList = < + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>({ + promptPresets, + onPresetClick, +}: UsePresetListProps) => { const presetsContainerRef = useRef(null); const {visibleItems, hiddenItems, measured} = useOverflowingHorizontalItems({ diff --git a/src/extensions/additional/GPT/plugin.ts b/src/extensions/additional/GPT/plugin.ts index d794819d4..81a077e4c 100644 --- a/src/extensions/additional/GPT/plugin.ts +++ b/src/extensions/additional/GPT/plugin.ts @@ -1,6 +1,7 @@ import {Plugin, PluginKey} from 'prosemirror-state'; import {Decoration, DecorationSet} from 'prosemirror-view'; +import {CommonAnswer} from './ErrorScreen/types'; import {WIDGET_DECO_CLASS_NAME, WIDGET_DECO_SPEC_FLAG} from './constants'; import type {GptWidgetDecoViewParams} from './gptExtension/view'; import {GptWidgetDecoView} from './gptExtension/view'; @@ -20,7 +21,12 @@ const key = new PluginKey('gpt-widget'); export {key as pluginKey}; -export const gptWidgetPlugin = (params: GptWidgetDecoViewParams): Plugin => { +export const gptWidgetPlugin = < + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>( + params: GptWidgetDecoViewParams, +): Plugin => { return new Plugin({ key, state: { diff --git a/src/extensions/additional/GPT/utils.ts b/src/extensions/additional/GPT/utils.ts index 424664e51..519dc66f9 100644 --- a/src/extensions/additional/GPT/utils.ts +++ b/src/extensions/additional/GPT/utils.ts @@ -2,6 +2,7 @@ import type React from 'react'; import {i18n} from '../../../i18n/gpt/dialog'; +import {CommonAnswer} from './ErrorScreen/types'; import {GptDialogProps} from './GptDialog/GptDialog'; import {GptWidgetOptions} from './gptExtension/gptExtension'; @@ -41,10 +42,10 @@ export function focusWithoutScroll(element?: HTMLElement | null) { window.scrollTo(x, y); } -export function isEmptyGptPrompts( - gptWidgetOptions: GptWidgetOptions, - disablePromptPresets: boolean, -) { +export function isEmptyGptPrompts< + AnswerData extends CommonAnswer = CommonAnswer, + PromptData extends unknown = unknown, +>(gptWidgetOptions: GptWidgetOptions, disablePromptPresets: boolean) { if (disablePromptPresets && !gptWidgetOptions.onCustomPromptApply) return true; if (