import { jsonLanguage } from '@codemirror/lang-json'; import { linter } from '@codemirror/lint'; import classNames from 'classnames'; import type { EditorView } from 'codemirror'; import { handleRefresh, jsonCompletion, jsonSchemaLinter, updateSchema, stateExtensions, } from 'codemirror-json-schema'; import { useEffect, useMemo, useRef } from 'react'; import { useAlert } from '../hooks/useAlert'; import type { ReflectResponseService } from '../hooks/useGrpc'; import { tryFormatJson } from '../lib/formatters'; import type { GrpcRequest } from '@yaakapp/api'; import { count } from '../lib/pluralize'; import { Button } from './core/Button'; import type { EditorProps } from './core/Editor'; import { Editor } from './core/Editor'; import { FormattedError } from './core/FormattedError'; import { InlineCode } from './core/InlineCode'; import { VStack } from './core/Stacks'; import { useDialog } from './DialogContext'; import { GrpcProtoSelection } from './GrpcProtoSelection'; type Props = Pick & { services: ReflectResponseService[] | null; reflectionError?: string; reflectionLoading?: boolean; request: GrpcRequest; protoFiles: string[]; }; export function GrpcEditor({ services, reflectionError, reflectionLoading, request, protoFiles, ...extraEditorProps }: Props) { const editorViewRef = useRef(null); const alert = useAlert(); const dialog = useDialog(); // Find the schema for the selected service and method and update the editor useEffect(() => { if ( editorViewRef.current == null || services === null || request.service === null || request.method === null ) { return; } const s = services.find((s) => s.name === request.service); if (s == null) { console.log('Failed to find service', { service: request.service, services }); alert({ id: 'grpc-find-service-error', title: "Couldn't Find Service", body: ( <> Failed to find service {request.service} in schema ), }); return; } const schema = s.methods.find((m) => m.name === request.method)?.schema; if (request.method != null && schema == null) { console.log('Failed to find method', { method: request.method, methods: s?.methods }); alert({ id: 'grpc-find-schema-error', title: "Couldn't Find Method", body: ( <> Failed to find method {request.method} for{' '} {request.service} in schema ), }); return; } if (schema == null) { return; } try { updateSchema(editorViewRef.current, JSON.parse(schema)); } catch (err) { alert({ id: 'grpc-parse-schema-error', title: 'Failed to Parse Schema', body: (

For service {request.service} and method{' '} {request.method}

{String(err)}
), }); } }, [alert, services, request.method, request.service]); const extraExtensions = useMemo( () => [ linter(jsonSchemaLinter(), { delay: 200, needsRefresh: handleRefresh, }), jsonLanguage.data.of({ autocomplete: jsonCompletion(), }), stateExtensions(/** Init with empty schema **/), ], [], ); const reflectionUnavailable = reflectionError?.match(/unimplemented/i); reflectionError = reflectionUnavailable ? undefined : reflectionError; const actions = useMemo( () => [
, ], [ dialog, protoFiles.length, reflectionError, reflectionLoading, reflectionUnavailable, request.id, services, ], ); return (
); }