diff --git a/packages/otelbin/.eslintignore b/packages/otelbin/.eslintignore index 2603e704..4e8caaa5 100644 --- a/packages/otelbin/.eslintignore +++ b/packages/otelbin/.eslintignore @@ -1 +1,2 @@ -src/lib/urlState/jsurl2.ts \ No newline at end of file +src/lib/urlState/jsurl2.ts +src/components/textArea.tsx \ No newline at end of file diff --git a/packages/otelbin/package-lock.json b/packages/otelbin/package-lock.json index 8423c7c3..8f17a114 100644 --- a/packages/otelbin/package-lock.json +++ b/packages/otelbin/package-lock.json @@ -16,6 +16,7 @@ "@monaco-editor/react": "^4.6.0", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", @@ -3646,6 +3647,29 @@ } } }, + "node_modules/@radix-ui/react-label": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz", + "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popover": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.7.tgz", diff --git a/packages/otelbin/package.json b/packages/otelbin/package.json index df12ecb9..7e300eda 100644 --- a/packages/otelbin/package.json +++ b/packages/otelbin/package.json @@ -22,6 +22,7 @@ "@monaco-editor/react": "^4.6.0", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", diff --git a/packages/otelbin/src/components/EnvVarForm.tsx b/packages/otelbin/src/components/EnvVarForm.tsx new file mode 100644 index 00000000..99d34f0d --- /dev/null +++ b/packages/otelbin/src/components/EnvVarForm.tsx @@ -0,0 +1,153 @@ +// SPDX-FileCopyrightText: 2023 Dash0 Inc. +// SPDX-License-Identifier: Apache-2.0 + +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { type IEnvVar, useEnvVarMenu, useEnvLines, type ILine } from "~/contexts/EditorContext"; +import { IconButton } from "./icon-button"; +import { Check, X, XCircle } from "lucide-react"; +import { Label } from "./label"; +import { Textarea } from "./textArea"; +import { useUrlState } from "~/lib/urlState/client/useUrlState"; +import { envVarBinding } from "./validation/binding"; +import { editorBinding } from "./monaco-editor/editorBinding"; +import { extractEnvVarData, extractVariables } from "./monaco-editor/parseYaml"; + +export default function EnvVarForm() { + const { openEnvVarMenu, setOpenEnvVarMenu } = useEnvVarMenu(); + const { envVarLine } = useEnvLines(); + const [{ env, config }] = useUrlState([editorBinding, envVarBinding]); + const variables = useMemo(() => extractVariables(config), [config]); + const envVarData = extractEnvVarData(variables, env); + const [envVarDataState, setEnvVarDataState] = useState(envVarData); + function handleClose() { + setOpenEnvVarMenu(false); + } + + const unboundVariables = Object.values(envVarDataState).filter( + (envVar) => envVar.submittedValue === undefined && envVar.defaultValue === "" + ); + + useEffect(() => { + setEnvVarDataState(extractEnvVarData(variables, env)); + }, [variables, env]); + + return ( +
+
+
+
+ 0 ? "#F87171" : "#69F18E", + }} + > + {unboundVariables.length} + {" "} + {`${unboundVariables.length === 1 ? "variable" : "variables"} unbound`} +
+ + + +
+
+ {Object.values(envVarDataState).map((envVar) => ( + + ))} +
+
+
+ ); +} + +function EnvVar({ envVar, lines }: { envVar: IEnvVar; lines?: ILine }) { + const textAreaRef = useRef(null); + const [{ env }, getLink] = useUrlState([envVarBinding, editorBinding]); + const [envVarValue, setEnvVarValue] = useState(env[envVar.name] ?? envVar.defaultValue ?? ""); + + function handleEnvVarChange(event: React.ChangeEvent) { + setEnvVarValue(event.target.value); + } + + function handleEnvVarSubmit() { + if (typeof window !== "undefined") { + window.history.pushState(null, "", getLink({ env: { ...env, [envVar.name]: envVarValue } })); + } + } + + useEffect(() => { + //To enable automatic resizing of the textarea + if (textAreaRef.current) { + textAreaRef.current.style.height = "0px"; + const scrollHeight = textAreaRef.current.scrollHeight; + textAreaRef.current.style.height = scrollHeight + "px"; + } + }, [envVarValue]); + + useEffect(() => { + if (envVar.defaultValue === "") { + setEnvVarValue(env[envVar.name] ?? ""); + } else if (envVar.defaultValue !== "" && envVar.defaultValue !== undefined) { + setEnvVarValue(env[envVar.name] ?? envVar.defaultValue ?? ""); + } + }, [env, envVar.defaultValue, envVar.name]); + + return ( +
+
+
+ + {envVarValue === env[envVar.name] && } +
+
+