mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-06 20:13:35 +09:00
feat: add Resource type descriptions to the select box (#3091)
This should clarify that Resource is a safe for using private keys inside them. <img width="567" alt="image" src="https://github.com/webstudio-is/webstudio/assets/52824/9c530ff5-3ca2-4aff-857b-225ac7cf95dd"> ## Steps for reproduction 1. create a variable 2. hover over type options ## Code Review - [ ] hi @TrySound , I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env.example` and the `builder/env-check.js` if mandatory
This commit is contained in:
1 parent
49ac5dc032
commit
b2ef61ea0a
2 files changed
+79
-55
No files matched your search
@@ -28,7 +28,6 @@ import {
|
||||
ProBadge,
|
||||
ScrollArea,
|
||||
Select,
|
||||
SelectItem,
|
||||
Switch,
|
||||
TextArea,
|
||||
Tooltip,
|
||||
@@ -48,7 +47,6 @@ import {
|
||||
invalidateResource,
|
||||
} from "~/shared/nano-states";
|
||||
import { serverSyncStore } from "~/shared/sync";
|
||||
import { humanizeString } from "~/shared/string-utils";
|
||||
import {
|
||||
useField,
|
||||
type Field,
|
||||
@@ -390,40 +388,57 @@ const VariablePanel = forwardRef<
|
||||
}
|
||||
return "string";
|
||||
});
|
||||
const typeOptions: VariableType[] = [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"json",
|
||||
"resource",
|
||||
];
|
||||
const getTypeLabel = (value: VariableType) =>
|
||||
value === "json" ? "JSON" : humanizeString(value);
|
||||
|
||||
const typeOptions: Map<
|
||||
VariableType,
|
||||
{ label: ReactNode; description: string }
|
||||
> = new Map([
|
||||
["string", { label: "String", description: "Any alphanumeric text." }],
|
||||
[
|
||||
"number",
|
||||
{
|
||||
label: "Number",
|
||||
description: "Any number, can be used in math expressions.",
|
||||
},
|
||||
],
|
||||
[
|
||||
"boolean",
|
||||
{ label: "Boolean", description: "A boolean is a true/false switch." },
|
||||
],
|
||||
["json", { label: "JSON", description: "Any JSON value" }],
|
||||
[
|
||||
"resource",
|
||||
{
|
||||
label: (
|
||||
<Flex direction="row" gap="2" align="center">
|
||||
Resource
|
||||
{allowDynamicData === false && <ProBadge>Pro</ProBadge>}
|
||||
</Flex>
|
||||
),
|
||||
description:
|
||||
"A Resource is a configuration for secure data fetching. You can safely use secrets in any field.",
|
||||
},
|
||||
],
|
||||
]);
|
||||
const typeFieldElement = (
|
||||
<Flex direction="column" css={{ gap: theme.spacing[3] }}>
|
||||
<Flex direction="column" gap="1">
|
||||
<Label>Type</Label>
|
||||
<Select<VariableType>
|
||||
options={typeOptions}
|
||||
getLabel={getTypeLabel}
|
||||
<Select
|
||||
options={Array.from(typeOptions.keys())}
|
||||
getLabel={(option: VariableType) => typeOptions.get(option)?.label}
|
||||
getItemProps={(option) => ({
|
||||
disabled: option === "resource" && allowDynamicData === false,
|
||||
})}
|
||||
getDescription={(option) => {
|
||||
return (
|
||||
<Box css={{ width: theme.spacing[25] }}>
|
||||
{typeOptions.get(option)?.description}
|
||||
</Box>
|
||||
);
|
||||
}}
|
||||
value={type}
|
||||
onChange={setType}
|
||||
>
|
||||
{typeOptions.map((option) => (
|
||||
<SelectItem
|
||||
key={option}
|
||||
value={option}
|
||||
textValue={getTypeLabel(option)}
|
||||
disabled={option === "resource" && allowDynamicData === false}
|
||||
>
|
||||
{getTypeLabel(option)}
|
||||
{option === "resource" && allowDynamicData === false && (
|
||||
<Box css={{ display: "inline-block", ml: theme.spacing[3] }}>
|
||||
<ProBadge>Pro</ProBadge>
|
||||
</Box>
|
||||
)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
|
||||
@@ -138,13 +138,16 @@ export type SelectProps<Option = SelectOption> = {
|
||||
placeholder?: string;
|
||||
children?: ReactNode;
|
||||
getDescription?: (option: Option) => ReactNode | undefined;
|
||||
getItemProps?: (
|
||||
option: Option
|
||||
) => Omit<ComponentProps<typeof SelectItem>, "children" | "value">;
|
||||
} & (Option extends string
|
||||
? {
|
||||
getLabel?: (option: Option) => string | undefined;
|
||||
getLabel?: (option: Option) => ReactNode | undefined;
|
||||
getValue?: (option: Option) => string | undefined;
|
||||
}
|
||||
: {
|
||||
getLabel: (option: Option) => string | undefined;
|
||||
getLabel: (option: Option) => ReactNode | undefined;
|
||||
getValue: (option: Option) => string | undefined;
|
||||
}) &
|
||||
TriggerPassThroughProps;
|
||||
@@ -171,6 +174,7 @@ const SelectBase = <Option,>(
|
||||
getLabel = defaultGetValue,
|
||||
getValue = defaultGetValue,
|
||||
getDescription,
|
||||
getItemProps,
|
||||
name,
|
||||
children,
|
||||
prefix,
|
||||
@@ -225,27 +229,32 @@ const SelectBase = <Option,>(
|
||||
|
||||
<SelectViewport style={{ order: 1, maxHeight: rawTheme.spacing[34] }}>
|
||||
{children ||
|
||||
options.map((option) => (
|
||||
<SelectItem
|
||||
key={getValue(option)}
|
||||
value={getValue(option) ?? ""}
|
||||
textValue={getLabel(option)}
|
||||
onMouseEnter={() => {
|
||||
onItemHighlight?.(option);
|
||||
setHighlightedItem(option);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
onItemHighlight?.();
|
||||
setHighlightedItem(undefined);
|
||||
}}
|
||||
onFocus={() => {
|
||||
onItemHighlight?.(option);
|
||||
setHighlightedItem(option);
|
||||
}}
|
||||
>
|
||||
{getLabel(option)}
|
||||
</SelectItem>
|
||||
))}
|
||||
options.map((option, index) => {
|
||||
const value = getValue(option) ?? "";
|
||||
const { textValue, ...rest } = getItemProps?.(option) ?? {};
|
||||
return (
|
||||
<SelectItem
|
||||
key={value ?? index}
|
||||
value={value}
|
||||
textValue={textValue ?? value}
|
||||
onMouseEnter={() => {
|
||||
onItemHighlight?.(option);
|
||||
setHighlightedItem(option);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
onItemHighlight?.();
|
||||
setHighlightedItem(undefined);
|
||||
}}
|
||||
onFocus={() => {
|
||||
onItemHighlight?.(option);
|
||||
setHighlightedItem(option);
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{getLabel(option)}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</SelectViewport>
|
||||
|
||||
<SelectScrollDownButton css={{ order: 2 }}>
|
||||
|
||||
Reference in new issue
Block a user