import { jsoncLanguage } from "@shopify/lang-jsonc"; import { linter } from "@codemirror/lint"; import type { EditorView } from "@codemirror/view"; import type { GrpcRequest } from "@yaakapp-internal/models"; import classNames from "classnames"; import { handleRefresh, jsonCompletion, jsonSchemaLinter, stateExtensions, updateSchema, } from "codemirror-json-schema"; import { useCallback, useEffect, useMemo, useState } from "react"; import type { ReflectResponseService } from "../hooks/useGrpc"; import { showAlert } from "../lib/alert"; import { showDialog } from "../lib/dialog"; import { pluralizeCount } from "../lib/pluralize"; import { Button } from "./core/Button"; import type { EditorProps } from "./core/Editor/Editor"; import { Editor } from "./core/Editor/LazyEditor"; import { FormattedError } from "./core/FormattedError"; import { InlineCode } from "./core/InlineCode"; import { VStack } from "./core/Stacks"; import { GrpcProtoSelectionDialog } from "./GrpcProtoSelectionDialog"; 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 [editorView, setEditorView] = useState(null); const handleInitEditorViewRef = useCallback((h: EditorView | null) => { setEditorView(h); }, []); // Find the schema for the selected service and method and update the editor useEffect(() => { if ( editorView == 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 }); showAlert({ 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 }); showAlert({ 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(editorView, JSON.parse(schema)); } catch (err) { showAlert({ id: "grpc-parse-schema-error", title: "Failed to Parse Schema", body: (

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

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