mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-15 22:05:23 +00:00
fix (#219)
This commit is contained in:
parent
bdab90ba41
commit
8f6052c8e1
6 changed files with 57 additions and 31 deletions
|
|
@ -6,15 +6,8 @@ import { useThemeNormalized } from "@/hooks/useThemeNormalized";
|
||||||
import { json, jsonLanguage, jsonParseLinter } from "@codemirror/lang-json";
|
import { json, jsonLanguage, jsonParseLinter } from "@codemirror/lang-json";
|
||||||
import { linter } from "@codemirror/lint";
|
import { linter } from "@codemirror/lint";
|
||||||
import { EditorView, hoverTooltip } from "@codemirror/view";
|
import { EditorView, hoverTooltip } from "@codemirror/view";
|
||||||
import CodeMirror, { ReactCodeMirrorRef } from "@uiw/react-codemirror";
|
import CodeMirror, { Extension, ReactCodeMirrorRef } from "@uiw/react-codemirror";
|
||||||
import {
|
import { useRef, forwardRef, useImperativeHandle, Ref, ReactNode, useState, useEffect } from "react";
|
||||||
handleRefresh,
|
|
||||||
jsonCompletion,
|
|
||||||
jsonSchemaHover,
|
|
||||||
jsonSchemaLinter,
|
|
||||||
stateExtensions
|
|
||||||
} from "codemirror-json-schema";
|
|
||||||
import { useRef, forwardRef, useImperativeHandle, Ref, ReactNode, useState } from "react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Schema } from "ajv";
|
import { Schema } from "ajv";
|
||||||
|
|
@ -120,7 +113,6 @@ const ConfigEditor = <T,>(props: ConfigEditorProps<T>, forwardedRef: Ref<ReactCo
|
||||||
const editorRef = useRef<ReactCodeMirrorRef>(null);
|
const editorRef = useRef<ReactCodeMirrorRef>(null);
|
||||||
const [isViewMoreActionsEnabled, setIsViewMoreActionsEnabled] = useState(false);
|
const [isViewMoreActionsEnabled, setIsViewMoreActionsEnabled] = useState(false);
|
||||||
const [height, setHeight] = useState(224);
|
const [height, setHeight] = useState(224);
|
||||||
|
|
||||||
useImperativeHandle(
|
useImperativeHandle(
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
() => editorRef.current as ReactCodeMirrorRef
|
() => editorRef.current as ReactCodeMirrorRef
|
||||||
|
|
@ -129,6 +121,51 @@ const ConfigEditor = <T,>(props: ConfigEditorProps<T>, forwardedRef: Ref<ReactCo
|
||||||
const keymapExtension = useKeymapExtension(editorRef.current?.view);
|
const keymapExtension = useKeymapExtension(editorRef.current?.view);
|
||||||
const { theme } = useThemeNormalized();
|
const { theme } = useThemeNormalized();
|
||||||
|
|
||||||
|
// ⚠️ DISGUSTING HACK AHEAD ⚠️
|
||||||
|
// Background: When navigating to the /connections/:id?tab=settings page, we were hitting a 500 error with the following
|
||||||
|
// message server side:
|
||||||
|
//
|
||||||
|
// > Internal error: Error: Element type is invalid: expected a string (for built-in components) or a class/function
|
||||||
|
// > (for composite components) but got: undefined. You likely forgot to export your component from the file it's
|
||||||
|
// > defined in, or you might have mixed up default and named imports.
|
||||||
|
//
|
||||||
|
// Why was this happening? We have no idea, but we isolated it to the extensions exported by the `codemirror-json-schema`
|
||||||
|
// package. The solution that worked was to dynamically import the package inside of the useEffect and load the extensions
|
||||||
|
// async.
|
||||||
|
//
|
||||||
|
// So, yeah. - Brendan
|
||||||
|
const [jsonSchemaExtensions, setJsonSchemaExtensions] = useState<Extension[]>([]);
|
||||||
|
useEffect(() => {
|
||||||
|
const loadExtensions = async () => {
|
||||||
|
const {
|
||||||
|
handleRefresh,
|
||||||
|
jsonCompletion,
|
||||||
|
jsonSchemaHover,
|
||||||
|
jsonSchemaLinter,
|
||||||
|
stateExtensions
|
||||||
|
} = await import('codemirror-json-schema');
|
||||||
|
return [
|
||||||
|
linter(jsonParseLinter(), {
|
||||||
|
delay: 300,
|
||||||
|
}),
|
||||||
|
linter(jsonSchemaLinter(), {
|
||||||
|
needsRefresh: handleRefresh,
|
||||||
|
}),
|
||||||
|
jsonLanguage.data.of({
|
||||||
|
autocomplete: jsonCompletion(),
|
||||||
|
}),
|
||||||
|
hoverTooltip(jsonSchemaHover()),
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
stateExtensions(schema as any),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
loadExtensions().then((extensions) => {
|
||||||
|
console.debug('Loaded json schema extensions');
|
||||||
|
setJsonSchemaExtensions(extensions);
|
||||||
|
});
|
||||||
|
}, [schema]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border rounded-md">
|
<div className="border rounded-md">
|
||||||
<div className="flex flex-row items-center flex-wrap p-1">
|
<div className="flex flex-row items-center flex-wrap p-1">
|
||||||
|
|
@ -211,19 +248,8 @@ const ConfigEditor = <T,>(props: ConfigEditorProps<T>, forwardedRef: Ref<ReactCo
|
||||||
extensions={[
|
extensions={[
|
||||||
keymapExtension,
|
keymapExtension,
|
||||||
json(),
|
json(),
|
||||||
linter(jsonParseLinter(), {
|
|
||||||
delay: 300,
|
|
||||||
}),
|
|
||||||
linter(jsonSchemaLinter(), {
|
|
||||||
needsRefresh: handleRefresh,
|
|
||||||
}),
|
|
||||||
jsonLanguage.data.of({
|
|
||||||
autocomplete: jsonCompletion(),
|
|
||||||
}),
|
|
||||||
hoverTooltip(jsonSchemaHover()),
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
stateExtensions(schema as any),
|
|
||||||
customAutocompleteStyle,
|
customAutocompleteStyle,
|
||||||
|
...jsonSchemaExtensions,
|
||||||
]}
|
]}
|
||||||
theme={theme === "dark" ? "dark" : "light"}
|
theme={theme === "dark" ? "dark" : "light"}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export const EditorContextMenu = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}, [captureEvent, path, repoName, selection.from, selection.to, toast, view, revisionName]);
|
}, [selection.from, selection.to, domain, repoName, revisionName, path, toast, captureEvent, view]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
import { getDisplayTime } from "@/lib/utils";
|
import { getDisplayTime } from "@/lib/utils";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { StatusIcon } from "../../components/statusIcon";
|
import { StatusIcon } from "../../components/statusIcon";
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ export default async function ConnectionManagementPage({ params, searchParams }:
|
||||||
|
|
||||||
const currentTab = searchParams.tab || "overview";
|
const currentTab = searchParams.tab || "overview";
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs value={currentTab} className="w-full">
|
<Tabs value={currentTab} className="w-full">
|
||||||
<Header className="mb-6" withTopMargin={false}>
|
<Header className="mb-6" withTopMargin={false}>
|
||||||
|
|
@ -85,12 +86,7 @@ export default async function ConnectionManagementPage({ params, searchParams }:
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent
|
<TabsContent
|
||||||
value="settings"
|
value="settings"
|
||||||
// @note: There was some bugginess with the ConfigEditor ref not being set again
|
className="flex flex-col gap-6"
|
||||||
// after the parent component was unmounted and remounted. This workarouns makes it
|
|
||||||
// s.t., hide the settings tab when it is inactive, instead of unmounting it.
|
|
||||||
// @see: https://github.com/radix-ui/primitives/issues/2359#issuecomment-2481321719
|
|
||||||
className="flex flex-col gap-6 data-[state=inactive]:hidden"
|
|
||||||
forceMount={true}
|
|
||||||
>
|
>
|
||||||
<DisplayNameSetting connectionId={connection.id} name={connection.name} />
|
<DisplayNameSetting connectionId={connection.id} name={connection.name} />
|
||||||
<ConfigSetting
|
<ConfigSetting
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
import { cn, CodeHostType, getCodeHostIcon } from "@/lib/utils";
|
import { cn, CodeHostType, getCodeHostIcon } from "@/lib/utils";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import useCaptureEvent from "@/hooks/useCaptureEvent";
|
||||||
import { useNonEmptyQueryParam } from "@/hooks/useNonEmptyQueryParam";
|
import { useNonEmptyQueryParam } from "@/hooks/useNonEmptyQueryParam";
|
||||||
import { useSearchHistory } from "@/hooks/useSearchHistory";
|
import { useSearchHistory } from "@/hooks/useSearchHistory";
|
||||||
import { Repository, SearchQueryParams, SearchResultFile } from "@/lib/types";
|
import { Repository, SearchQueryParams, SearchResultFile } from "@/lib/types";
|
||||||
import { createPathWithQueryParams, measureSync } from "@/lib/utils";
|
import { createPathWithQueryParams } from "@/lib/utils";
|
||||||
import { SymbolIcon } from "@radix-ui/react-icons";
|
import { SymbolIcon } from "@radix-ui/react-icons";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue