Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/extensions/additional/GPT/GptDialog/GptDialog.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -50,7 +49,10 @@ export type GptDialogProps<

export const cnGptDialog = cn('gpt-dialog');

export const GptDialog: FC<GptDialogProps> = ({
export const GptDialog = <
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
>({
markup,
answerRender,
promptPresets,
Expand All @@ -66,7 +68,7 @@ export const GptDialog: FC<GptDialogProps> = ({
onDislike,
onUpdate,
gptAlertProps,
}) => {
}: GptDialogProps<AnswerData, PromptData>) => {
const {
answer,
customPrompt,
Expand Down
6 changes: 5 additions & 1 deletion src/extensions/additional/GPT/MarkupGpt/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<AnswerData, PromptData>) {
return [
mGptPlugin(props).extension,
keymap.of([
Expand Down
6 changes: 5 additions & 1 deletion src/extensions/additional/GPT/MarkupGpt/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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<AnswerData, PromptData>) {
return ViewPlugin.fromClass(
class implements PluginValue {
readonly _view: EditorView;
Expand Down
11 changes: 7 additions & 4 deletions src/extensions/additional/GPT/MarkupGpt/popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ import {CommonAnswer} from '../ErrorScreen/types';
import {GptDialog, GptDialogProps} from '../GptDialog/GptDialog';
import {cnGptPopup} from '../gptExtension/view';

type Props = {
type Props<AnswerData extends CommonAnswer = CommonAnswer, PromptData extends unknown = unknown> = {
onClose: () => void;
markup: string;
onConfirmOk?: () => void;
onConfirmCancel?: () => void;
} & GptDialogProps &
} & GptDialogProps<AnswerData, PromptData> &
Pick<PopupProps, 'anchorRef' | 'container'>;

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<AnswerData, PromptData>) {
const handleUpdate = (result?: AnswerData) => props.onUpdate?.(result);

return (
<Popup
Expand Down
42 changes: 29 additions & 13 deletions src/extensions/additional/GPT/PresetList/PresetList.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
import React from 'react';
import type {FC} from 'react';

import {ActionTooltip, Button, DropdownMenu} from '@gravity-ui/uikit';

import {cn} from '../../../../classname';
import {i18n} from '../../../../i18n/gpt/dialog';
import {type PromptPreset} from '../ErrorScreen/types';
import {CommonAnswer, type PromptPreset} from '../ErrorScreen/types';
import type {GptDialogProps} from '../GptDialog/GptDialog';
import {gptHotKeys} from '../constants';
import {useGptHotKeys} from '../hooks/useGptHotKeys';
import {usePresetList} from '../hooks/usePresetList';

import './Presetlist.scss';

export type PresetListProps<PromptData extends unknown = unknown> = {
disablePromptPresets: GptDialogProps['disablePromptPresets'];
promptPresets: GptDialogProps['promptPresets'];
onPresetClick: (data: PromptData) => void;
export type PresetListProps<
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
> = {
disablePromptPresets: GptDialogProps<AnswerData, PromptData>['disablePromptPresets'];
promptPresets: GptDialogProps<AnswerData, PromptData>['promptPresets'];
onPresetClick: (data?: PromptData) => void;
};

type PresetItemType = {
preset: PromptPreset<unknown>;
onPresetClick: PresetListProps['onPresetClick'];
type PresetItemType<
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
> = {
preset: PromptPreset<PromptData>;
onPresetClick: PresetListProps<AnswerData, PromptData>['onPresetClick'];
disablePromptPresets?: PresetListProps['disablePromptPresets'];
hotKey: string;
};

export const cnGptDialogPresetList = cn('gpt-dialog-preset-list');

const PresetItem: FC<PresetItemType> = ({preset, onPresetClick, disablePromptPresets, hotKey}) => {
const PresetItem = <
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
>({
preset,
onPresetClick,
disablePromptPresets,
hotKey,
}: PresetItemType<AnswerData, PromptData>) => {
useGptHotKeys(
hotKey,
() => {
Expand All @@ -52,13 +65,16 @@ const PresetItem: FC<PresetItemType> = ({preset, onPresetClick, disablePromptPre
);
};

export const PresetList: FC<PresetListProps> = ({
export const PresetList = <
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
>({
disablePromptPresets,
promptPresets,
onPresetClick,
}) => {
}: PresetListProps<AnswerData, PromptData>) => {
const {presetsContainerRef, visiblePresets, hiddenPresets, showMoreButton, measured} =
usePresetList({
usePresetList<AnswerData, PromptData>({
promptPresets,
onPresetClick,
});
Expand Down
11 changes: 8 additions & 3 deletions src/extensions/additional/GPT/gptExtension/gptExtension.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -31,7 +30,13 @@ export type GptWidgetOptions<
| 'gptAlertProps'
>;

export const gptExtension: ExtensionWithOptions<GptWidgetOptions> = (builder, options) => {
export const gptExtension = <
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
>(
builder: ExtensionBuilder,
options: GptWidgetOptions<AnswerData, PromptData>,
) => {
builder.addAction(gptActionName, showGptWidget);
builder.addPlugin(({serializer, markupParser}) => {
return gptWidgetPlugin({
Expand Down
30 changes: 21 additions & 9 deletions src/extensions/additional/GPT/gptExtension/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,21 @@ export type GptWidgetDecoViewParams<
gptPopupContainer?: PopupProps['container'];
};

export class GptWidgetDecoView implements Required<PluginView> {
export class GptWidgetDecoView<
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
> implements Required<PluginView>
{
private readonly _view;
private readonly _renderer;

private _decoElem: Element | null = null;
private _params: GptWidgetDecoViewParams;
private _params: GptWidgetDecoViewParams<AnswerData, PromptData>;
private _serializer: Serializer;
private _parser: Parser;
private _confirmOpen: boolean;

constructor(view: EditorView, params: GptWidgetDecoViewParams) {
constructor(view: EditorView, params: GptWidgetDecoViewParams<AnswerData, PromptData>) {
this._view = view;

this._params = params;
Expand Down Expand Up @@ -144,7 +148,9 @@ export class GptWidgetDecoView implements Required<PluginView> {
);
}

private _onGptAnswerUpdate: NonNullable<WidgetProps['onUpdate']> = (answer) => {
private _onGptAnswerUpdate: NonNullable<WidgetProps<AnswerData, PromptData>['onUpdate']> = (
answer,
) => {
this._params.onUpdate?.(answer);
};

Expand Down Expand Up @@ -233,15 +239,21 @@ export class GptWidgetDecoView implements Required<PluginView> {
}
}

type WidgetProps = Pick<PopupProps, 'anchorRef' | 'container'> & {
type WidgetProps<
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
> = Pick<PopupProps, 'anchorRef' | 'container'> & {
markup: string;
onClose: () => void;
confirmOpen: boolean;
onConfirmOk: () => void;
onConfirmCancel: () => void;
} & GptDialogProps;
} & GptDialogProps<AnswerData, PromptData>;

function Widget({
function Widget<
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
>({
markup,
anchorRef,
answerRender,
Expand All @@ -259,7 +271,7 @@ function Widget({
onUpdate,
container,
gptAlertProps,
}: WidgetProps) {
}: WidgetProps<AnswerData, PromptData>) {
useMount(() => {
if (anchorRef?.current && 'scrollIntoView' in anchorRef.current) {
anchorRef.current.scrollIntoView({
Expand All @@ -270,7 +282,7 @@ function Widget({
});

const handleUpdate = useCallback(
(result?: CommonAnswer) => {
(result?: AnswerData) => {
onUpdate?.(result);
},
[onUpdate],
Expand Down
2 changes: 1 addition & 1 deletion src/extensions/additional/GPT/hooks/useGpt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export const useGpt = <
[handleCustomPromptApply],
);

const handlePresetClick = useCallback<PresetListProps<PromptData>['onPresetClick']>(
const handlePresetClick = useCallback<PresetListProps<AnswerData, PromptData>['onPresetClick']>(
async (data) => {
const gptRequestData: GptRequestData<PromptData> = {
markup,
Expand Down
16 changes: 13 additions & 3 deletions src/extensions/additional/GPT/hooks/usePresetList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<GptDialogProps, 'promptPresets'> & {
onPresetClick: PresetListProps['onPresetClick'];
type UsePresetListProps<
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
> = Pick<GptDialogProps<AnswerData, PromptData>, 'promptPresets'> & {
onPresetClick: PresetListProps<AnswerData, PromptData>['onPresetClick'];
};

export const usePresetList = ({promptPresets, onPresetClick}: UsePresetListProps) => {
export const usePresetList = <
AnswerData extends CommonAnswer = CommonAnswer,
PromptData extends unknown = unknown,
>({
promptPresets,
onPresetClick,
}: UsePresetListProps<AnswerData, PromptData>) => {
const presetsContainerRef = useRef<HTMLDivElement>(null);

const {visibleItems, hiddenItems, measured} = useOverflowingHorizontalItems({
Expand Down
8 changes: 7 additions & 1 deletion src/extensions/additional/GPT/plugin.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -20,7 +21,12 @@ const key = new PluginKey<DecorationSet>('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<AnswerData, PromptData>,
): Plugin => {
return new Plugin({
key,
state: {
Expand Down
9 changes: 5 additions & 4 deletions src/extensions/additional/GPT/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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<AnswerData, PromptData>, disablePromptPresets: boolean) {
if (disablePromptPresets && !gptWidgetOptions.onCustomPromptApply) return true;

if (
Expand Down
Loading