Skip to content

Commit

Permalink
feat(ai-assist): add header modal (#13639)
Browse files Browse the repository at this point in the history
Co-authored-by: lmossman <lake@airbyte.io>
  • Loading branch information
bnchrch and lmossman committed Aug 27, 2024
1 parent 4991e91 commit a8a7094
Show file tree
Hide file tree
Showing 19 changed files with 175 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import { Action, Namespace, useAnalyticsService } from "core/services/analytics"
import { useConnectorBuilderFormState } from "services/connectorBuilder/ConnectorBuilderStateService";

import styles from "./AddStreamButton.module.scss";
import { AssistWaiting } from "./AssistWaiting";
import { convertToAssistFormValuesSync } from "./Assist/assist";
import { AssistWaiting } from "./Assist/AssistWaiting";
import { BuilderField } from "./BuilderField";
import { BuilderFieldWithInputs } from "./BuilderFieldWithInputs";
import { convertToAssistFormValuesSync } from "../assist";
import { AssistData, BuilderStream, DEFAULT_BUILDER_STREAM_VALUES, DEFAULT_SCHEMA, useBuilderWatch } from "../types";

interface AddStreamResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import {
import { KnownExceptionInfo } from "core/api/types/AirbyteClient";
import { useConnectorBuilderFormState } from "services/connectorBuilder/ConnectorBuilderStateService";

import { AssistKey, convertToAssistFormValuesSync } from "../assist";
import { AssistData, BuilderFormInput, BuilderFormValues, useBuilderWatch } from "../types";
import { AssistKey, convertToAssistFormValuesSync } from "./assist";
import { AssistData, BuilderFormInput, BuilderFormValues, useBuilderWatch } from "../../types";

/**
* HELPERS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@use "scss/variables";
@use "scss/colors";
@use "scss/z-indices";

.popoverPanel {
background-color: colors.$foreground;
z-index: z-indices.$modal;
border-radius: variables.$border-radius-md;
box-shadow: variables.$box-shadow-popup;
border: 1px solid colors.$yellow-600;
}

.assistConfigPanel {
width: variables.$width-modal-md;
max-width: 100%;
padding: variables.$spacing-xl;
}

.assistForm {
margin-top: variables.$spacing-md;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useFloating, offset, flip, autoUpdate } from "@floating-ui/react-dom";
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
import { useIntl } from "react-intl";

import { Button, ButtonProps } from "components/ui/Button";
import { FlexContainer } from "components/ui/Flex";
import { Switch } from "components/ui/Switch";
import { Text } from "components/ui/Text";

import { useExperiment } from "hooks/services/Experiment";
import { useConnectorBuilderFormState } from "services/connectorBuilder/ConnectorBuilderStateService";

import styles from "./AssistConfigButton.module.scss";
import { BuilderField } from "../BuilderField";

type ChangeEventFunction = (e: React.ChangeEvent<HTMLInputElement>) => void;

export const AssistForm: React.FC = () => {
const { formatMessage } = useIntl();

return (
<FlexContainer direction="column" gap="lg" className={styles.assistForm}>
<BuilderField
type="string"
optional
label={formatMessage({ id: "connectorBuilder.globalConfiguration.assist.docsUrl" })}
placeholder={formatMessage({ id: "connectorBuilder.globalConfiguration.assist.docsUrl.placeholder" })}
manifestPath="metadata.assist.docsUrl"
path="formValues.assist.docsUrl"
/>
<BuilderField
type="string"
optional
label={formatMessage({ id: "connectorBuilder.globalConfiguration.assist.openApiSpecUrl" })}
placeholder={formatMessage({ id: "connectorBuilder.globalConfiguration.assist.openApiSpecUrl.placeholder" })}
manifestPath="metadata.assist.openApiSpecUrl"
path="formValues.assist.openApiSpecUrl"
/>
</FlexContainer>
);
};

const AssistSwitch: React.FC = () => {
const { assistEnabled, setAssistEnabled } = useConnectorBuilderFormState();
const onChange: ChangeEventFunction = (e) => {
setAssistEnabled(e.currentTarget.checked);
};

return <Switch checked={assistEnabled} onChange={onChange} />;
};

const AssistConfigPanel = () => {
const { formatMessage } = useIntl();
const { setAssistEnabled, assistEnabled } = useConnectorBuilderFormState();

return (
<FlexContainer direction="column" gap="lg" className={styles.assistConfigPanel}>
<FlexContainer direction="row" justifyContent="space-between" alignItems="center">
<AIButton onClick={() => setAssistEnabled(!assistEnabled)} />
<AssistSwitch />
</FlexContainer>
<Text as="span" color="grey400" size="sm">
{formatMessage({ id: "connectorBuilder.assist.configModal.description" })}
</Text>
<AssistForm />
</FlexContainer>
);
};

const AIButton = (props: ButtonProps) => {
const { formatMessage } = useIntl();
const { assistEnabled } = useConnectorBuilderFormState();

const variant = assistEnabled ? "highlight" : "secondary";

return (
<Button variant={variant} icon="aiStars" {...props}>
{formatMessage({ id: "connectorBuilder.assist.configModal.button" })}
</Button>
);
};

const AssistConfigButton = () => {
const isAIEnabled = useExperiment("connectorBuilder.aiAssist.enabled", false);

const { x, y, reference, floating, strategy } = useFloating({
middleware: [offset(5), flip()],
whileElementsMounted: autoUpdate,
placement: "bottom",
});

if (!isAIEnabled) {
return null;
}

return (
<Popover>
{({ open }) => (
<>
<PopoverButton ref={reference} as="div">
<AIButton />
</PopoverButton>
{open && (
<PopoverPanel
ref={floating}
className={styles.popoverPanel}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
}}
>
<AssistConfigPanel />
</PopoverPanel>
)}
</>
)}
</Popover>
);
};

export default AssistConfigButton;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { BuilderAssistManifestResponse } from "core/api";
import { DeclarativeComponentSchema } from "core/api/types/ConnectorManifest";

import { convertToBuilderFormValuesSync } from "./convertManifestToBuilderForm";
import { BuilderFormValues } from "./types";
import { convertToBuilderFormValuesSync } from "../../convertManifestToBuilderForm";
import { BuilderFormValues } from "../../types";

export type AssistKey = "urlbase" | "auth" | "metadata" | "record_selector" | "paginator";

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCallback } from "react";
import { useFormContext } from "react-hook-form";
import { useIntl } from "react-intl";

import { AssistButton } from "components/connectorBuilder/Builder/Assist/AssistButton";
import GroupControls from "components/GroupControls";
import { ControlLabels } from "components/LabeledControl";

Expand All @@ -12,7 +13,6 @@ import {
import { Action, Namespace, useAnalyticsService } from "core/services/analytics";
import { links } from "core/utils/links";

import { AssistButton } from "./AssistButton";
import { BuilderCard } from "./BuilderCard";
import { BuilderField } from "./BuilderField";
import { BuilderFieldWithInputs } from "./BuilderFieldWithInputs";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export type BuilderFieldProps = BaseFieldProps &
onBlur?: (value: string) => void;
step?: number;
min?: number;
placeholder?: string;
}
| { type: "date" | "date-time"; onChange?: (newValue: string) => void }
| { type: "boolean"; onChange?: (newValue: boolean) => void; disabledTooltip?: string }
Expand Down Expand Up @@ -220,6 +221,7 @@ const InnerBuilderField: React.FC<BuilderFieldProps> = ({
onChange={(e) => {
setValue(e.target.value);
}}
placeholder={props.placeholder}
className={props.className}
type={props.type}
value={(fieldValue as string | number | undefined) ?? ""}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useIntl } from "react-intl";

import { AssistButton } from "components/connectorBuilder/Builder/AssistButton";
import { AssistButton } from "components/connectorBuilder/Builder/Assist/AssistButton";

import { Action, Namespace, useAnalyticsService } from "core/services/analytics";
import { useConnectorBuilderFormState } from "services/connectorBuilder/ConnectorBuilderStateService";

import { AssistSection } from "./AssistSection";
import { AuthenticationSection } from "./AuthenticationSection";
import { BuilderCard } from "./BuilderCard";
import { BuilderConfigView } from "./BuilderConfigView";
Expand All @@ -20,7 +19,6 @@ export const GlobalConfigView: React.FC = () => {
return (
<fieldset className={styles.fieldset} disabled={permission === "readOnly"}>
<BuilderConfigView heading={formatMessage({ id: "connectorBuilder.globalConfiguration" })}>
<AssistSection />
<BuilderCard>
<BuilderFieldWithInputs
type="string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import lowerCase from "lodash/lowerCase";
import { useFormContext } from "react-hook-form";
import { useIntl } from "react-intl";

import { AssistButton } from "components/connectorBuilder/Builder/Assist/AssistButton";
import { LabelInfo } from "components/Label";

import { RequestOption } from "core/api/types/ConnectorManifest";
import { links } from "core/utils/links";

import { AssistButton } from "./AssistButton";
import { BuilderCard } from "./BuilderCard";
import { BuilderField } from "./BuilderField";
import { BuilderFieldWithInputs } from "./BuilderFieldWithInputs";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useIntl } from "react-intl";

import { AssistButton } from "components/connectorBuilder/Builder/Assist/AssistButton";

import { links } from "core/utils/links";

import { AssistButton } from "./AssistButton";
import { BuilderCard } from "./BuilderCard";
import { BuilderField } from "./BuilderField";
import { getDescriptionByManifest, getLabelByManifest } from "./manifestHelpers";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { useCallback, useMemo, useState } from "react";
import { get, useFormContext, useFormState } from "react-hook-form";
import { FormattedMessage, useIntl } from "react-intl";

import { AssistButton } from "components/connectorBuilder/Builder/Assist/AssistButton";
import Indicator from "components/Indicator";
import { Button } from "components/ui/Button";
import { CodeEditor } from "components/ui/CodeEditor";
Expand All @@ -19,7 +20,6 @@ import {
} from "services/connectorBuilder/ConnectorBuilderStateService";

import { AddStreamButton } from "./AddStreamButton";
import { AssistButton } from "./AssistButton";
import { BuilderCard } from "./BuilderCard";
import { BuilderConfigView } from "./BuilderConfigView";
import { BuilderField } from "./BuilderField";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
color: colors.$grey-500;
}

.leftSide {
flex-grow: 1;
min-width: 0;
}

.rightSide {
flex-grow: 0;
flex-shrink: 0;
Expand Down
14 changes: 12 additions & 2 deletions airbyte-webapp/src/components/connectorBuilder/MenuBar/MenuBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { HelpDropdown } from "views/layout/SideBar/components/HelpDropdown";
import { DownloadYamlButton } from "./DownloadYamlButton";
import styles from "./MenuBar.module.scss";
import { PublishButton } from "./PublishButton";
import AssistConfigButton from "../Builder/Assist/AssistConfigButton";
import { HotkeyLabel, getCtrlOrCmdKey } from "../HotkeyLabel";
import { NameInput } from "../NameInput";
import { useBuilderWatch } from "../types";
Expand Down Expand Up @@ -47,8 +48,14 @@ export const MenuBar: React.FC = () => {
);

return (
<FlexContainer direction="row" alignItems="center" gap="2xl" className={styles.container}>
<FlexContainer direction="row" alignItems="center" className={styles.leftSide} gap="lg">
<FlexContainer
direction="row"
alignItems="center"
justifyContent="space-between"
gap="xl"
className={styles.container}
>
<FlexContainer direction="row" alignItems="center" gap="lg">
<FlexContainer direction="row" alignItems="center" gap="md" className={styles.exitAndName}>
<Link to={RoutePaths.ConnectorBuilder}>
<Button
Expand Down Expand Up @@ -111,6 +118,9 @@ export const MenuBar: React.FC = () => {
</FlexContainer>
)}
</FlexContainer>
<FlexContainer direction="row" alignItems="center">
<AssistConfigButton />
</FlexContainer>
<FlexContainer direction="row" alignItems="center" className={styles.rightSide}>
{isCloudApp() ? (
<CloudHelpDropdown className={styles.helpButton} hideLabel placement="bottom" />
Expand Down
Loading

0 comments on commit a8a7094

Please sign in to comment.