Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/connect-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pipedream/connect-react",
"version": "1.6.0",
"version": "2.0.0",
"description": "Pipedream Connect library for React",
"files": [
"dist"
Expand Down Expand Up @@ -30,7 +30,7 @@
"author": "Pipedream Engineering",
"license": "MIT",
"dependencies": {
"@pipedream/sdk": "^1.8.0",
"@pipedream/sdk": "^2.0.9",
"@tanstack/react-query": "^5.59.16",
"lodash.isequal": "^4.5.0",
"react-markdown": "^9.0.1",
Expand Down
14 changes: 8 additions & 6 deletions packages/connect-react/src/components/ComponentForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
FormContextProvider, type FormContext,
} from "../hooks/form-context";
import { DynamicProps } from "../types";
import type {
Component,
ConfigurableProps,
ConfiguredProps,
V1Component,
DynamicProps,
} from "@pipedream/sdk";

import {
type FormContext,
FormContextProvider,
} from "../hooks/form-context";
import { InternalComponentForm } from "./InternalComponentForm";

export type ComponentFormProps<T extends ConfigurableProps, U = ConfiguredProps<T>> = {
Expand All @@ -18,7 +20,7 @@ export type ComponentFormProps<T extends ConfigurableProps, U = ConfiguredProps<
* @deprecated Use `externalUserId` instead.
*/
userId?: string;
component: V1Component<T>;
component: Component;
configuredProps?: U; // XXX value?
disableQueryDisabling?: boolean;
// dynamicPropsId?: string // XXX need to load this initially when passed
Expand Down
2 changes: 1 addition & 1 deletion packages/connect-react/src/components/Control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function Control<T extends ConfigurableProps, U extends ConfigurableProp>
return <RemoteOptionsContainer queryEnabled={queryDisabledIdx == null || queryDisabledIdx >= idx} />;
}

if ("options" in prop && prop.options) {
if ("options" in prop && Array.isArray(prop.options) && prop.options.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const options: LabelValueOption<any>[] = prop.options.map(sanitizeOption);
return <ControlSelect options={options} components={{
Expand Down
17 changes: 14 additions & 3 deletions packages/connect-react/src/components/ControlAny.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { useFormFieldContext } from "../hooks/form-field-context";
import { useCustomize } from "../hooks/customization-context";
import {
ConfiguredPropValueInteger,
ConfiguredPropValueObject,
ConfiguredPropValueString,
ConfiguredPropValueStringArray,
} from "@pipedream/sdk";
import type { CSSProperties } from "react";

import { useCustomize } from "../hooks/customization-context";
import { useFormFieldContext } from "../hooks/form-field-context";

export function ControlAny() {
const formFieldContext = useFormFieldContext();
const {
Expand All @@ -18,7 +25,11 @@ export function ControlAny() {
boxShadow: theme.boxShadow.input,
};

let jsonValue = value;
let jsonValue = value as
| ConfiguredPropValueInteger
| ConfiguredPropValueObject
| ConfiguredPropValueString
| ConfiguredPropValueStringArray;
if (typeof jsonValue === "object") {
jsonValue = JSON.stringify(jsonValue);
}
Expand Down
8 changes: 3 additions & 5 deletions packages/connect-react/src/components/ControlApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export function ControlApp({ app }: ControlAppProps) {
};
const selectProps = select.getProps("controlAppSelect", baseSelectProps);

const oauthAppId = oauthAppConfig?.[app.name_slug];
const oauthAppId = oauthAppConfig?.[app.nameSlug];
const {
isLoading: isLoadingAccounts,
// TODO error
Expand All @@ -86,14 +86,12 @@ export function ControlApp({ app }: ControlAppProps) {
} = useAccounts(
{
external_user_id: externalUserId,
app: app.name_slug,
app: app.nameSlug,
oauth_app_id: oauthAppId,
},
{
useQueryOpts: {
enabled: !!app,

// @ts-expect-error this seems to work (this overrides enabled so don't just set to true)
suspense: !!app,
},
},
Expand Down Expand Up @@ -161,7 +159,7 @@ export function ControlApp({ app }: ControlAppProps) {
isLoading={isLoadingAccounts}
isClearable={true}
isSearchable={true}
getOptionLabel={(a) => a.name}
getOptionLabel={(a) => a.name ?? ""}
getOptionValue={(a) => a.id}
onChange={(a) => {
if (a) {
Expand Down
18 changes: 11 additions & 7 deletions packages/connect-react/src/components/ControlInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CSSProperties } from "react";
import type { ConfigurablePropInteger } from "@pipedream/sdk";
import { useFormFieldContext } from "../hooks/form-field-context";
import { useCustomize } from "../hooks/customization-context";

Expand Down Expand Up @@ -46,20 +47,23 @@ export function ControlInput() {
autoComplete = "new-password"; // in chrome, this is better than "off" here
}

const min = prop.type === "integer"
? (prop as ConfigurablePropInteger).min
: undefined;
const max = prop.type === "integer"
? (prop as ConfigurablePropInteger).max
: undefined;

return (
<input
id={id}
type={inputType}
name={prop.name}
value={value ?? ""}
value={String(value ?? "")}
onChange={(e) => onChange(toOnChangeValue(e.target.value))}
{...getProps("controlInput", baseStyles, formFieldContextProps)}
min={"min" in prop
? prop.min
: undefined}
max={"max" in prop
? prop.max
: undefined}
min={min}
max={max}
autoComplete={autoComplete}
data-lpignore="true"
data-1p-ignore="true"
Expand Down
35 changes: 14 additions & 21 deletions packages/connect-react/src/components/ControlSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { PropOptionValue } from "@pipedream/sdk";
import {
useEffect,
useMemo,
Expand All @@ -22,7 +23,7 @@ import {
import { LoadMoreButton } from "./LoadMoreButton";

// XXX T and ConfigurableProp should be related
type ControlSelectProps<T> = {
type ControlSelectProps<T extends PropOptionValue> = {
isCreatable?: boolean;
options: LabelValueOption<T>[];
selectProps?: ReactSelectProps<LabelValueOption<T>, boolean>;
Expand All @@ -31,7 +32,7 @@ type ControlSelectProps<T> = {
components?: ReactSelectProps<LabelValueOption<T>, boolean>["components"];
};

export function ControlSelect<T>({
export function ControlSelect<T extends PropOptionValue>({
isCreatable,
options,
selectProps,
Expand Down Expand Up @@ -83,37 +84,29 @@ export function ControlSelect<T>({
return null;
}

let ret = rawValue;
if (Array.isArray(ret)) {
if (Array.isArray(rawValue)) {
// if simple, make lv (XXX combine this with other place this happens)
if (!isOptionWithLabel(ret[0])) {
return ret.map((o) =>
selectOptions.find((item) => item.value === o) || {
label: String(o),
value: o,
});
if (!isOptionWithLabel(rawValue[0])) {
return rawValue.map((o) =>
selectOptions.find((item) => item.value === o) || sanitizeOption(o as T));
}
} else if (ret && typeof ret === "object" && "__lv" in ret) {
// Extract the actual option from __lv wrapper
ret = ret.__lv;
} else if (!isOptionWithLabel(ret)) {
} else if (rawValue && typeof rawValue === "object" && "__lv" in (rawValue as Record<string, unknown>)) {
// Extract the actual option from __lv wrapper and sanitize to LV
return sanitizeOption(((rawValue as Record<string, unknown>).__lv) as T);
} else if (!isOptionWithLabel(rawValue)) {
const lvOptions = selectOptions?.[0] && isOptionWithLabel(selectOptions[0]);
if (lvOptions) {
for (const item of selectOptions) {
if (item.value === rawValue) {
ret = item;
break;
return item;
}
}
} else {
ret = {
label: String(rawValue),
value: rawValue,
}
return sanitizeOption(rawValue as T);
}
}

return ret;
return null;
}, [
rawValue,
selectOptions,
Expand Down
5 changes: 3 additions & 2 deletions packages/connect-react/src/components/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function Field<T extends ConfigurableProp>(props: FieldProps<T>) {
const app = "app" in field.extra
? field.extra.app
: undefined;
if (app && !app.auth_type) {
if (app && !app.authType) {
return null;
}

Expand All @@ -58,8 +58,9 @@ export function Field<T extends ConfigurableProp>(props: FieldProps<T>) {
// XXX rename to FieldErrors + add FormErrors (to ComponentFormInternal)
// XXX use similar pattern as app below for boolean and checkboxing DOM re-ordering?

const fieldProps = props as unknown as FieldProps<ConfigurableProp>;
return (
<div {...getProps("field", baseStyles, props as FieldProps<ConfigurableProp>)}>
<div {...getProps("field", baseStyles, fieldProps)}>
<Label text={labelText} field={field} form={form} />
<Control field={field} form={form} />
<Description markdown={prop.description} field={field} form={form} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export function InternalComponentForm() {
type: "alert",
alertType: "error",
content: `# ${e.name}\n${e.message}`,
name: e.name,
} as ConfigurablePropAlert
}))
}
Expand Down Expand Up @@ -146,7 +147,7 @@ export function InternalComponentForm() {
idx,
]) => {
if (prop.type === "alert") {
return <Alert key={prop.name} prop={prop} />;
return <Alert key={prop.name} prop={prop as ConfigurablePropAlert} />;
}
return <InternalField key={prop.name} prop={prop} idx={idx} />;
})}
Expand Down
17 changes: 11 additions & 6 deletions packages/connect-react/src/components/InternalField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ConfigurableProp } from "@pipedream/sdk";
import type {
ConfigurableProp, ConfigurablePropApp,
} from "@pipedream/sdk";
import { FormFieldContext } from "../hooks/form-field-context";
import { useFormContext } from "../hooks/form-context";
import { Field } from "./Field";
Expand All @@ -10,6 +12,10 @@ type FieldInternalProps<T extends ConfigurableProp> = {
idx: number;
};

function isConfigurablePropApp(prop: ConfigurableProp): prop is ConfigurablePropApp {
return prop.type === "app";
}

export function InternalField<T extends ConfigurableProp>({
prop, idx,
}: FieldInternalProps<T>) {
Expand All @@ -18,17 +24,16 @@ export function InternalField<T extends ConfigurableProp>({
id: formId, configuredProps, registerField, setConfiguredProp, errors, enableDebugging,
} = formCtx;

const appSlug = prop.type === "app" && "app" in prop
? prop.app
: undefined;
let appSlug: ConfigurablePropApp["app"] | undefined;
if (isConfigurablePropApp(prop)) {
appSlug = prop.app;
}
const {
// TODO error
app,
} = useApp(appSlug || "", {
useQueryOpts: {
enabled: !!appSlug,

// @ts-expect-error this seems to work (this overrides enabled so don't just set to true)
suspense: !!appSlug,
},
});
Expand Down
20 changes: 11 additions & 9 deletions packages/connect-react/src/components/RemoteOptionsContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ConfigureComponentOpts } from "@pipedream/sdk";
import type {
ConfigurePropOpts, PropOptionValue,
} from "@pipedream/sdk";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { useFormContext } from "../hooks/form-context";
Expand Down Expand Up @@ -56,8 +58,8 @@ export function RemoteOptionsContainer({ queryEnabled }: RemoteOptionsContainerP
] = useState<{
page: number;
prevContext: ConfigureComponentContext | undefined;
data: RawPropOption<string>[];
values: Set<string | number>;
data: RawPropOption[];
values: Set<PropOptionValue>;
}>({
page: 0,
prevContext: {},
Expand All @@ -70,11 +72,11 @@ export function RemoteOptionsContainer({ queryEnabled }: RemoteOptionsContainerP
const prop = configurableProps[i];
configuredPropsUpTo[prop.name] = configuredProps[prop.name];
}
const componentConfigureInput: ConfigureComponentOpts = {
const componentConfigureInput: ConfigurePropOpts = {
externalUserId,
page,
prevContext: context,
componentId: component.key,
id: component.key,
propName: prop.name,
configuredProps: configuredPropsUpTo,
dynamicPropsId: dynamicProps?.id,
Expand Down Expand Up @@ -112,7 +114,7 @@ export function RemoteOptionsContainer({ queryEnabled }: RemoteOptionsContainerP
],
queryFn: async () => {
setError(undefined);
const res = await client.configureComponent(componentConfigureInput);
const res = await client.components.configureProp(componentConfigureInput);

// XXX look at errors in response here too
const {
Expand All @@ -131,7 +133,7 @@ export function RemoteOptionsContainer({ queryEnabled }: RemoteOptionsContainerP
}
return [];
}
let _options: RawPropOption<string>[] = []
let _options: RawPropOption[] = []
if (options?.length) {
_options = options;
}
Expand All @@ -149,7 +151,7 @@ export function RemoteOptionsContainer({ queryEnabled }: RemoteOptionsContainerP
const newOptions = []
const allValues = new Set(pageable.values)
for (const o of _options || []) {
let value: string | number;
let value: PropOptionValue;
if (isString(o)) {
value = o;
} else if (o && typeof o === "object" && "value" in o && o.value != null) {
Expand All @@ -170,7 +172,7 @@ export function RemoteOptionsContainer({ queryEnabled }: RemoteOptionsContainerP
data = [
...pageable.data,
...newOptions,
] as RawPropOption<string>[]
] as RawPropOption[]
setPageable({
page: page + 1,
prevContext: res.context,
Expand Down
Loading
Loading