-
Notifications
You must be signed in to change notification settings - Fork 944
feat: setup url autofill for dynamic parameters #17739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4209d7d
1d798ea
9d10195
ec35a7f
04c7f83
03dde8a
afdab85
a76159f
6711e28
7dc96bb
eb413fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,23 +32,27 @@ import { | |
TooltipProvider, | ||
TooltipTrigger, | ||
} from "components/Tooltip/Tooltip"; | ||
import { Info, Settings, TriangleAlert } from "lucide-react"; | ||
import { Info, Link, Settings, TriangleAlert } from "lucide-react"; | ||
import { type FC, useEffect, useId, useState } from "react"; | ||
import type { AutofillBuildParameter } from "utils/richParameters"; | ||
import * as Yup from "yup"; | ||
|
||
export interface DynamicParameterProps { | ||
parameter: PreviewParameter; | ||
value?: string; | ||
onChange: (value: string) => void; | ||
disabled?: boolean; | ||
isPreset?: boolean; | ||
autofill?: AutofillBuildParameter; | ||
} | ||
|
||
export const DynamicParameter: FC<DynamicParameterProps> = ({ | ||
parameter, | ||
value, | ||
onChange, | ||
disabled, | ||
isPreset, | ||
autofill, | ||
}) => { | ||
const id = useId(); | ||
|
||
|
@@ -57,13 +61,18 @@ export const DynamicParameter: FC<DynamicParameterProps> = ({ | |
className="flex flex-col gap-2" | ||
data-testid={`parameter-field-${parameter.name}`} | ||
> | ||
<ParameterLabel parameter={parameter} isPreset={isPreset} /> | ||
<ParameterLabel | ||
parameter={parameter} | ||
isPreset={isPreset} | ||
autofill={autofill} | ||
/> | ||
<div className="max-w-lg"> | ||
<ParameterField | ||
id={id} | ||
parameter={parameter} | ||
value={value} | ||
onChange={onChange} | ||
disabled={disabled} | ||
id={id} | ||
/> | ||
</div> | ||
{parameter.diagnostics.length > 0 && ( | ||
|
@@ -76,9 +85,14 @@ export const DynamicParameter: FC<DynamicParameterProps> = ({ | |
interface ParameterLabelProps { | ||
parameter: PreviewParameter; | ||
isPreset?: boolean; | ||
autofill?: AutofillBuildParameter; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is only being used for a truthy check to influence the conditional rendering, can we replace this with an |
||
} | ||
|
||
const ParameterLabel: FC<ParameterLabelProps> = ({ parameter, isPreset }) => { | ||
const ParameterLabel: FC<ParameterLabelProps> = ({ | ||
parameter, | ||
isPreset, | ||
autofill, | ||
}) => { | ||
const hasDescription = parameter.description && parameter.description !== ""; | ||
jaaydenh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const displayName = parameter.display_name | ||
? parameter.display_name | ||
|
@@ -137,6 +151,23 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ parameter, isPreset }) => { | |
</Tooltip> | ||
</TooltipProvider> | ||
)} | ||
{autofill && ( | ||
<TooltipProvider delayDuration={100}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something I've been wondering about: when do you think it makes sense to define a global Defining the providers every single time still works, but there's more risk of the durations getting out of sync, which can make the UX feel inconsistent across the product There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default delay duration is too slow, I do think the delayDuration should be set globally but haven't had a chance to do this yet. Already there are inconsistencies between the TooltipProvider and the legacy MUI tooltips. |
||
<Tooltip> | ||
<TooltipTrigger asChild> | ||
<span className="flex items-center"> | ||
<Badge size="sm"> | ||
<Link /> | ||
jaaydenh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
URL Autofill | ||
</Badge> | ||
</span> | ||
</TooltipTrigger> | ||
<TooltipContent className="max-w-xs"> | ||
Autofilled from the URL | ||
</TooltipContent> | ||
</Tooltip> | ||
</TooltipProvider> | ||
)} | ||
</Label> | ||
|
||
{hasDescription && ( | ||
|
@@ -153,22 +184,27 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ parameter, isPreset }) => { | |
|
||
interface ParameterFieldProps { | ||
parameter: PreviewParameter; | ||
value?: string; | ||
onChange: (value: string) => void; | ||
disabled?: boolean; | ||
id: string; | ||
} | ||
|
||
const ParameterField: FC<ParameterFieldProps> = ({ | ||
parameter, | ||
value, | ||
onChange, | ||
disabled, | ||
id, | ||
}) => { | ||
const value = validValue(parameter.value); | ||
const [localValue, setLocalValue] = useState(value); | ||
const initialValue = | ||
value !== undefined ? value : validValue(parameter.value); | ||
const [localValue, setLocalValue] = useState(initialValue); | ||
|
||
useEffect(() => { | ||
setLocalValue(value); | ||
if (value !== undefined) { | ||
setLocalValue(value); | ||
} | ||
}, [value]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For something like this, you don't want to sync state via This is how I'd do it, and the React Docs recommend it, too: const [localValue, setLocalValue] = useState(
value !== undefined ? value : validValue(parameter.value),
);
if (value !== undefined && value !== localValue) {
setLocalValue(value);
} Setting state mid-render is valid, as long as you eventually hit a case where you stop calling the state setter. Inside an event handler, the state setter will bail out of re-renders if you dispatch a state value that's equal to the value currently in state. That protection is removed during a render to make sure the user doesn't call a state setter unconditionally This approach limits the "scope of the redo", because what happens is:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Though (lol), after writing all that out, I think the better option would be to remove the state entirely, and then pass this to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How much churn has this component had? I see a bunch of undefined checks for |
||
|
||
switch (parameter.form_type) { | ||
|
@@ -469,14 +505,14 @@ export const getInitialParameterValues = ( | |
({ name }) => name === parameter.name, | ||
); | ||
|
||
const useAutofill = | ||
autofillParam && | ||
isValidParameterOption(parameter, autofillParam) && | ||
autofillParam.value; | ||
jaaydenh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return { | ||
name: parameter.name, | ||
value: | ||
autofillParam && | ||
isValidParameterOption(parameter, autofillParam) && | ||
autofillParam.value | ||
? autofillParam.value | ||
: validValue(parameter.value), | ||
value: useAutofill ? autofillParam.value : validValue(parameter.value), | ||
}; | ||
}); | ||
}; | ||
|
@@ -489,14 +525,41 @@ const isValidParameterOption = ( | |
previewParam: PreviewParameter, | ||
buildParam: WorkspaceBuildParameter, | ||
) => { | ||
if (previewParam.form_type === "multi-select") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this also could have been |
||
console.log("buildParam.value", buildParam.value); | ||
let values: string[] = []; | ||
try { | ||
const parsed = JSON.parse(buildParam.value); | ||
if (Array.isArray(parsed)) { | ||
values = parsed; | ||
} | ||
} catch (e) { | ||
console.error( | ||
"Error parsing parameter value with form_type multi-select", | ||
e, | ||
); | ||
jaaydenh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return false; | ||
} | ||
|
||
// If options exist, validate each value | ||
if (previewParam.options.length > 0) { | ||
const validValues = previewParam.options.map( | ||
(option) => option.value.value, | ||
); | ||
return values.every((value) => validValues.includes(value)); | ||
} | ||
return false; | ||
} | ||
// For parameters with options (dropdown, radio, etc.) | ||
if (previewParam.options.length > 0) { | ||
const validValues = previewParam.options.map( | ||
(option) => option.value.value, | ||
); | ||
return validValues.includes(buildParam.value); | ||
} | ||
|
||
return false; | ||
// For parameters without options (input, textarea, etc.) | ||
return true; | ||
}; | ||
|
||
export const useValidationSchemaForDynamicParameters = ( | ||
|
Uh oh!
There was an error while loading. Please reload this page.