Skip to content

Commit

Permalink
feat(pipeline-builder): implement the layered flow of smart hint (#934)
Browse files Browse the repository at this point in the history
Because

- We envision a better smart hint flow to reduce the overwhelmed feeling
when building the pipeline

This commit

- implement the layered flow of smart hint
  • Loading branch information
EiffelFly committed Feb 5, 2024
1 parent 3bcd905 commit 69dc912
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 140 deletions.
Original file line number Diff line number Diff line change
@@ -1,102 +1,37 @@
import cn from "clsx";
import { FieldError } from "react-hook-form";
import { Nullable } from "../../../type";
import { Icons, Tag } from "@instill-ai/design-system";
import { Tag } from "@instill-ai/design-system";
import { SmartHintWarning } from "../../type";
import { SmartHint } from "../../../use-smart-hint";

export const SmartHintInfoCard = ({
fieldKey,
instillAcceptFormats,
className,
error,
supportReference,
supportTemplate,
smartHintWarning,
highlightedHint,
enableSmartHints,
}: {
fieldKey: Nullable<string>;
instillAcceptFormats: string[];
supportReference: boolean;
supportTemplate: boolean;
className?: string;
error?: FieldError;
smartHintWarning: Nullable<SmartHintWarning>;
highlightedHint: Nullable<SmartHint>;
enableSmartHints: boolean;
}) => {
if (!enableSmartHints) {
return;
}

if (!highlightedHint && !error && !smartHintWarning) {
return;
}

return (
<div className={cn("flex w-full flex-col", className)}>
<div className={cn("flex min-h-8 w-full flex-col", className)}>
<div className="flex flex-col gap-y-4 p-2">
{instillAcceptFormats.length > 0 ? (
<div className="flex flex-row gap-x-2">
<div className="pt-0.5">
<Icons.HelpCircle className="mb-auto h-4 w-4 stroke-semantic-fg-secondary" />
</div>
<div className="flex flex-col gap-y-1">
<p className="text-semantic-fg-secondary product-body-text-3-semibold">
This field accept following formats:
</p>
<div className="flex flex-row flex-wrap gap-x-2">
{instillAcceptFormats.map((format) => (
<Tag
key={format}
variant="lightBlue"
size="sm"
className="!rounded !px-2 !py-0.5"
>
{format}
</Tag>
))}
</div>
</div>
</div>
) : null}

{supportReference ? (
<div className="flex flex-row gap-x-2">
<div className="pt-0.5">
<Icons.InfoCircle className="mb-auto h-4 w-4 stroke-semantic-fg-secondary" />
</div>
<div className="flex flex-col gap-y-2">
<p className="m-auto text-semantic-fg-secondary product-body-text-3-semibold">
This field support reference, you can use{" "}
<Tag
variant="lightBlue"
size="sm"
className="!rounded !px-2 !py-0.5"
>
${`{}`}
</Tag>{" "}
to reference other value. For example:
</p>
<p className="rounded border border-semantic-bg-line bg-semantic-bg-base-bg px-2 py-1 text-semantic-fg-secondary product-body-text-3-regular">
${`{start.${fieldKey}}`}
</p>
</div>
</div>
) : null}
{supportTemplate ? (
<div className="flex flex-row gap-x-2">
<div className="pt-0.5">
<Icons.InfoCircle className="mb-auto h-4 w-4 stroke-semantic-fg-secondary" />
</div>
<div className="flex flex-col gap-y-2">
<p className="m-auto text-semantic-fg-secondary product-body-text-3-semibold">
This field support multiple references, you can use multiple{" "}
{` `}
<Tag
variant="lightBlue"
size="sm"
className="!rounded !px-2 !py-0.5"
>
${`{}`}
</Tag>{" "}
to compose your value. For example:
</p>
<p className="rounded border border-semantic-bg-line bg-semantic-bg-base-bg px-2 py-1 text-semantic-fg-secondary product-body-text-3-regular">
{`This is a value with multiple references, `} $
{`{start.${fieldKey}}`} {`and`} ${`{start.${fieldKey}}`}
</p>
</div>
</div>
) : null}
<p className="text-semantic-fg-secondary product-body-text-3-semibold">
{highlightedHint ? ` type:${highlightedHint.instillFormat}` : null}
</p>
</div>
{error ? (
<div className="flex w-full flex-col gap-y-1 bg-semantic-error-bg p-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SmartHint } from "../../../use-smart-hint";
import { onClickSmartHint } from "./onClickSmartHint";
import { ControllerRenderProps } from "react-hook-form";
import { GeneralUseFormReturn, Nullable } from "../../../type";
import { transformInstillFormatToHumanReadableFormat } from "../../transform";

export const SmartHintList = ({
form,
Expand All @@ -19,6 +20,7 @@ export const SmartHintList = ({
inputRef,
smartHintEnabledPos,
instillUpstreamTypes,
instillAcceptFormats,
}: {
field: ControllerRenderProps<
{
Expand All @@ -37,17 +39,37 @@ export const SmartHintList = ({
inputRef: React.RefObject<HTMLInputElement | HTMLTextAreaElement>;
smartHintEnabledPos: Nullable<number>;
instillUpstreamTypes: string[];
instillAcceptFormats: string[];
}) => {
const humanReadableAcceptFormatString = React.useMemo(() => {
const formats = instillAcceptFormats.map((format) => {
return transformInstillFormatToHumanReadableFormat(format);
});

const arrayFormats = formats.filter((f) => f.isArray);
const nonArrayFormats = formats.filter((f) => !f.isArray);

const arrayString =
arrayFormats.length > 0
? `Array [${arrayFormats.map((e) => e.format).join(", ")}]`
: null;
const nonArrayString =
nonArrayFormats.length > 0
? nonArrayFormats.map((e) => e.format).join(", ")
: null;

if (arrayString && nonArrayString) {
return `${arrayString}, ${nonArrayString}`;
}

return arrayString || nonArrayString;
}, [instillAcceptFormats]);

return (
<ScrollArea.Root viewPortRef={smartHintsScrollAreaViewportRef}>
<div
className={cn(
"flex !max-h-[224px] flex-col gap-y-2",
enableSmartHints ? "h-[224px]" : "p-4"
)}
>
{enableSmartHints ? (
filteredHints.length > 0 ? (
{enableSmartHints ? (
<div className="flex h-[224px] flex-col gap-y-2 rounded">
{filteredHints.length > 0 ? (
filteredHints.map((hint, index) => {
return (
<button
Expand Down Expand Up @@ -83,23 +105,15 @@ export const SmartHintList = ({
<p className="m-auto text-semantic-fg-secondary product-body-text-3-semibold">
No available hints
</p>
)
) : (
<p className="m-auto text-semantic-fg-secondary product-body-text-3-semibold">
You can use{" "}
{instillUpstreamTypes.includes("reference") ? (
<Tag
variant="lightBlue"
size="sm"
className="!rounded !px-2 !py-0.5"
>
${`{}`}
</Tag>
) : null}{" "}
to reference other field&apos;s value
)}
</div>
) : (
<div className="flex flex-col rounded border border-semantic-accent-default bg-[#F0F5FF] p-2">
<p className="text-semantic-accent-default product-body-text-3-semibold">
{humanReadableAcceptFormatString}
</p>
)}
</div>
</div>
)}
</ScrollArea.Root>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { onInputKeydown } from "./onInputKeydown";
import { SmartHintList } from "./SmartHintList";
import { AutoFormFieldBaseProps, SmartHintWarning } from "../../type";
import { useValidateReferenceAndTemplate } from "./useValidateReferenceAndTemplate";
import { getFieldPlaceholder } from "./getFieldPlaceholder";

export const TextArea = ({
form,
Expand Down Expand Up @@ -89,14 +90,22 @@ export const TextArea = ({
const supportTemplate = instillUpstreamTypes.includes("template");
const supportReference = instillUpstreamTypes.includes("reference");

const placeholder = React.useMemo(() => {
return getFieldPlaceholder(instillUpstreamTypes);
}, [instillUpstreamTypes]);

const highlightedHint = React.useMemo(() => {
return filteredHints[highlightedHintIndex];
}, [filteredHints, highlightedHintIndex]);

return isHidden ? null : (
<Form.Field
key={path}
control={form.control}
name={path}
render={({ field }) => {
return (
<Form.Item className="w-full">
<Form.Item className="group w-full">
<div className="flex flex-row gap-x-2">
<Form.Label
className={size === "sm" ? "!product-body-text-4-semibold" : ""}
Expand Down Expand Up @@ -150,7 +159,7 @@ export const TextArea = ({
<Textarea
{...field}
className={cn(
"nodrag",
"nodrag placeholder:text-semantic-fg-disabled",
size === "sm" ? "!product-body-text-4-regular" : ""
)}
ref={inputRef}
Expand All @@ -170,6 +179,7 @@ export const TextArea = ({
setSmartHintsPopoverIsOpen,
});
}}
placeholder={placeholder}
onFocus={() => {
setSmartHintsPopoverIsOpen(true);
}}
Expand Down Expand Up @@ -210,13 +220,11 @@ export const TextArea = ({
{supportReference || supportTemplate ? (
<React.Fragment>
<SmartHintInfoCard
fieldKey={fieldKey}
instillAcceptFormats={instillAcceptFormats}
className="absolute left-0 top-0 w-[var(--radix-popover-trigger-width)] -translate-x-[calc(var(--radix-popover-trigger-width)+10px)] rounded border border-semantic-bg-line bg-semantic-bg-primary shadow-md"
error={error}
supportReference={supportReference}
supportTemplate={supportTemplate}
smartHintWarning={smartHintWarning}
highlightedHint={highlightedHint}
enableSmartHints={enableSmartHints}
/>
<SmartHintList
form={form}
Expand All @@ -233,18 +241,10 @@ export const TextArea = ({
inputRef={inputRef}
smartHintEnabledPos={smartHintEnabledPos}
instillUpstreamTypes={instillUpstreamTypes}
instillAcceptFormats={instillAcceptFormats}
/>
</React.Fragment>
) : (
<SmartHintInfoCard
fieldKey={fieldKey}
instillAcceptFormats={instillAcceptFormats}
error={error}
supportReference={supportReference}
supportTemplate={supportTemplate}
smartHintWarning={smartHintWarning}
/>
)}
) : null}
</Popover.Content>
</Popover.Root>
<Form.Description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { onInputKeydown } from "./onInputKeydown";
import { SmartHintList } from "./SmartHintList";
import { AutoFormFieldBaseProps, SmartHintWarning } from "../../type";
import { useValidateReferenceAndTemplate } from "./useValidateReferenceAndTemplate";
import { getFieldPlaceholder } from "./getFieldPlaceholder";

export const TextField = ({
fieldKey,
Expand Down Expand Up @@ -88,14 +89,22 @@ export const TextField = ({
const supportTemplate = instillUpstreamTypes.includes("template");
const supportReference = instillUpstreamTypes.includes("reference");

const placeholder = React.useMemo(() => {
return getFieldPlaceholder(instillUpstreamTypes);
}, [instillUpstreamTypes]);

const highlightedHint = React.useMemo(() => {
return filteredHints[highlightedHintIndex];
}, [filteredHints, highlightedHintIndex]);

return isHidden ? null : (
<Form.Field
key={path}
control={form.control}
name={path}
render={({ field }) => {
return (
<Form.Item className="w-full">
<Form.Item className="group w-full">
{title || shortDescription ? (
<div className="flex flex-row gap-x-2">
<Form.Label
Expand Down Expand Up @@ -161,9 +170,10 @@ export const TextField = ({
typeof field.value === "object" ? "" : field.value ?? ""
}
className={cn(
"nodrag",
"nodrag placeholder:text-semantic-fg-disabled",
size === "sm" ? "!product-body-text-4-regular" : ""
)}
placeholder={placeholder}
autoComplete="off"
onChange={(e) => {
onInputChange({
Expand Down Expand Up @@ -218,13 +228,11 @@ export const TextField = ({
{supportReference || supportTemplate ? (
<React.Fragment>
<SmartHintInfoCard
fieldKey={fieldKey}
instillAcceptFormats={instillAcceptFormats}
className="absolute left-0 top-0 w-[var(--radix-popover-trigger-width)] -translate-x-[calc(var(--radix-popover-trigger-width)+10px)] rounded border border-semantic-bg-line bg-semantic-bg-primary shadow-md"
className="absolute right-0 top-0 w-[var(--radix-popover-trigger-width)] translate-x-[calc(var(--radix-popover-trigger-width)+10px)] rounded border border-semantic-bg-line bg-semantic-bg-primary shadow-md"
error={error}
supportReference={supportReference}
supportTemplate={supportTemplate}
smartHintWarning={smartHintWarning}
highlightedHint={highlightedHint}
enableSmartHints={enableSmartHints}
/>
<SmartHintList
field={field}
Expand All @@ -241,18 +249,10 @@ export const TextField = ({
inputRef={inputRef}
smartHintEnabledPos={smartHintEnabledPos}
instillUpstreamTypes={instillUpstreamTypes}
instillAcceptFormats={instillAcceptFormats}
/>
</React.Fragment>
) : (
<SmartHintInfoCard
fieldKey={fieldKey}
instillAcceptFormats={instillAcceptFormats}
error={error}
supportReference={supportReference}
supportTemplate={supportTemplate}
smartHintWarning={smartHintWarning}
/>
)}
) : null}
</Popover.Content>
</Popover.Root>
<Form.Description
Expand Down
Loading

0 comments on commit 69dc912

Please sign in to comment.