2a1273b683
* Added the new colours to the Tailwind config * Fixed Tsailwind compile errors * WIP Geist working in the app * WIP Storybook * Storybook is working again… ouch * Use Geist mono for CodeMirror * Some find/replace class changes * Resizable colours improved * WIP on primary button * Minor style improvements * Improve the side menu header styling * Improved v2 breadcrumbs * Account side menu tweaks * The page now works with the NavBar and UpgradePrompt * Removed unused import * Refactored the buttons to be dry-er * Removed the breadcrumbs * WIP on nav bar * WIP updating the button styles * Fix for the old test page * Fix for type errors * Removed console.log * Colour change in the resizable handle * New loading bar divider * Removed the design plugin * Creating our own storybook pages * Added some “storybook” pages * Added DetailCell storybook * WIP new animation for the loading page * Added the new loading divider * Fix for the time frame filter having a green border * Style improvements to the new test page * Small style improvements * Improvements to the list pagination components * Nav bar back button improved * Improvements to the run page * Lots of v2 style improvements * Help looks better * Improvements to the regenerate API key modal * More general improvements * Added section titles to our storybook * Added form stories * Fix for missing key prop * Loading bar is working * Fixed button submitting state * Fix for the test button icon * Code bg improved * Improved oauth buttons * Integration page header fix * Various improvements, mainly changing button variants * Segmented control style updates * Added an outline of 3px for the segment control * Fixes for the billing pages * More pricing improvements * Added dialog to storybook * Typography now in storybook * Free usage bar added to storybook * Added inline clode to storybook * Separated menu types into a sub section in storybook * NamedIcon now in storybook * Added page header to storybook * Added pricing callout to storybook * Added radio groups to storybook * Added segmented controllers to storybook * Added shortcuts to storybook * Added switches to storybook * Added toast to storybook * Added tooltips to storybook * Added tree view to storybook * Added usage charts to storybook * Tarted up the environment variables page * Fix for the FreePlanUsage panel bg colours * Added new badge variants * Added the <TaskPath /> to the tasks table * Span header improvements * Started work on the timeline * Started work on the timeline * Fix for the run page header * Timeline tick marks are working * Timeline working * Got the durations showing on hover * Button improvements * Experimenting with how the duration should be shown * Lots of refinements to the timeline * Much nicer API for the Timeline * The switch is now purple to match the design, with inverted thumb when on * Removed old stuff * Export the props * Added the span with duration back in * Simplified more and fixed the span durations * Put in some decent dummy data * Rendering defaults * Wip with the mouse cursor * Improvements to the story * Added Slider primitive * Integrated the icons into the slider * Lots of layout improvements * Cleaned up imports * “Root” indicator * Animated background on partials * Pull the styles through to the spans and log dots * Fixed some bugs in the TreeView when nodes get created or destroyed * Fix for incorrect parentTask reference * Added run streaming endpoint for live refreshing * Added the tabs to Storybook * Fix for status font size mismatch * Fix for the misaligned run filter status * Set a minimum duration on the timeline * The TreeView now re-calculates if the number of nodes has changed * Partials now render to the end * Improved the durations gutter * The duration is calculated using the current time if there are partial events * Added the environment label to storybook * Improved the environment label style * Removed bottom margin from badge * Button style improvements * Callouts style fits the new design better * Got the scrollbars to appear on the tree/timeline * Added scroll support * Synced scrolling working * Close button and exit icon for the detail panel * secure field shows start of env * Clipboard improvements * Latest lockfile * Fix for the durations wrapping --------- Co-authored-by: James Ritchie <james@jamesritchie.co.uk>
154 lines
4.1 KiB
TypeScript
154 lines
4.1 KiB
TypeScript
import { json as jsonLang } from "@codemirror/lang-json";
|
|
import type { ViewUpdate } from "@codemirror/view";
|
|
import { CheckIcon, ClipboardIcon, TrashIcon } from "@heroicons/react/20/solid";
|
|
import type { ReactCodeMirrorProps, UseCodeMirror } from "@uiw/react-codemirror";
|
|
import { useCodeMirror } from "@uiw/react-codemirror";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { cn } from "~/utils/cn";
|
|
import { Button } from "../primitives/Buttons";
|
|
import { getEditorSetup } from "./codeMirrorSetup";
|
|
import { darkTheme } from "./codeMirrorTheme";
|
|
|
|
export interface JSONEditorProps extends Omit<ReactCodeMirrorProps, "onBlur"> {
|
|
defaultValue?: string;
|
|
language?: "json";
|
|
readOnly?: boolean;
|
|
onChange?: (value: string) => void;
|
|
onUpdate?: (update: ViewUpdate) => void;
|
|
onBlur?: (code: string) => void;
|
|
showCopyButton?: boolean;
|
|
showClearButton?: boolean;
|
|
}
|
|
|
|
const languages = {
|
|
json: jsonLang,
|
|
};
|
|
|
|
type JSONEditorDefaultProps = Partial<JSONEditorProps>;
|
|
|
|
const defaultProps: JSONEditorDefaultProps = {
|
|
language: "json",
|
|
readOnly: true,
|
|
basicSetup: false,
|
|
};
|
|
|
|
export function JSONEditor(opts: JSONEditorProps) {
|
|
const {
|
|
defaultValue = "",
|
|
language,
|
|
readOnly,
|
|
onChange,
|
|
onUpdate,
|
|
onBlur,
|
|
basicSetup,
|
|
autoFocus,
|
|
showCopyButton = true,
|
|
showClearButton = true,
|
|
} = {
|
|
...defaultProps,
|
|
...opts,
|
|
};
|
|
|
|
const extensions = getEditorSetup();
|
|
|
|
if (!language) throw new Error("language is required");
|
|
const languageExtension = languages[language];
|
|
|
|
extensions.push(languageExtension());
|
|
|
|
const editor = useRef<HTMLDivElement>(null);
|
|
const settings: Omit<UseCodeMirror, "onBlur"> = {
|
|
...opts,
|
|
container: editor.current,
|
|
extensions,
|
|
editable: !readOnly,
|
|
contentEditable: !readOnly,
|
|
value: defaultValue,
|
|
autoFocus,
|
|
theme: darkTheme(),
|
|
indentWithTab: false,
|
|
basicSetup,
|
|
onChange,
|
|
onUpdate,
|
|
};
|
|
const { setContainer, view } = useCodeMirror(settings);
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (editor.current) {
|
|
setContainer(editor.current);
|
|
}
|
|
}, [setContainer]);
|
|
|
|
//if the defaultValue changes update the editor
|
|
useEffect(() => {
|
|
if (view !== undefined) {
|
|
if (view.state.doc.toString() === defaultValue) return;
|
|
view.dispatch({
|
|
changes: { from: 0, to: view.state.doc.length, insert: defaultValue },
|
|
});
|
|
}
|
|
}, [defaultValue, view]);
|
|
|
|
const clear = useCallback(() => {
|
|
if (view === undefined) return;
|
|
view.dispatch({
|
|
changes: { from: 0, to: view.state.doc.length, insert: undefined },
|
|
});
|
|
onChange?.("");
|
|
}, [view]);
|
|
|
|
const copy = useCallback(() => {
|
|
if (view === undefined) return;
|
|
navigator.clipboard.writeText(view.state.doc.toString());
|
|
setCopied(true);
|
|
setTimeout(() => {
|
|
setCopied(false);
|
|
}, 1500);
|
|
}, [view]);
|
|
|
|
return (
|
|
<div className={cn(opts.className, "grid grid-rows-[2.5rem_1fr]")}>
|
|
<div className="mx-3 flex items-center justify-end gap-2 border-b border-grid-dimmed">
|
|
{showClearButton && (
|
|
<Button
|
|
type="button"
|
|
variant="minimal/small"
|
|
TrailingIcon={TrashIcon}
|
|
onClick={(event) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
clear();
|
|
}}
|
|
>
|
|
Clear
|
|
</Button>
|
|
)}
|
|
{showCopyButton && (
|
|
<Button
|
|
type="button"
|
|
variant="minimal/small"
|
|
TrailingIcon={copied ? CheckIcon : ClipboardIcon}
|
|
trailingIconClassName={copied ? "text-green-500 group-hover:text-green-500" : undefined}
|
|
onClick={(event) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
copy();
|
|
}}
|
|
>
|
|
Copy
|
|
</Button>
|
|
)}
|
|
</div>
|
|
<div
|
|
className="w-full overflow-auto"
|
|
ref={editor}
|
|
onBlur={() => {
|
|
if (!onBlur) return;
|
|
onBlur(editor.current?.textContent ?? "");
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|