@dev-fastn-ai/react-core 2.3.6 → 2.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +465 -0
- package/dist/{react-core/src/core → core}/provider.d.ts +2 -2
- package/dist/{react-core/src/core → core}/use-configuration-form.d.ts +1 -1
- package/dist/{react-core/src/core → core}/use-configurations.d.ts +1 -1
- package/dist/core/use-connectors.d.ts +1 -0
- package/dist/{react-core/src/core → core}/use-field-options.d.ts +4 -1
- package/dist/index.cjs.js +39 -1655
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -202
- package/dist/index.esm.js +39 -1654
- package/dist/index.esm.js.map +1 -1
- package/package.json +5 -3
- package/dist/core/src/core/activate-connector.d.ts +0 -40
- package/dist/core/src/core/config.d.ts +0 -3
- package/dist/core/src/core/configuration-form.d.ts +0 -27
- package/dist/core/src/core/configurations.d.ts +0 -2
- package/dist/core/src/core/connectors.d.ts +0 -7
- package/dist/core/src/core/execute-flow.d.ts +0 -9
- package/dist/core/src/core/register-refetch-functions.d.ts +0 -4
- package/dist/core/src/index.d.ts +0 -13
- package/dist/core/src/services/apis.d.ts +0 -86
- package/dist/core/src/types/config.d.ts +0 -10
- package/dist/core/src/types/index.d.ts +0 -272
- package/dist/core/src/utils/constants.d.ts +0 -12
- package/dist/core/src/utils/errors.d.ts +0 -22
- package/dist/core/src/utils/event-bus.d.ts +0 -6
- package/dist/core/src/utils/google-files-picker.d.ts +0 -13
- package/dist/core/src/utils/misc.d.ts +0 -40
- package/dist/react-core/src/core/use-connectors.d.ts +0 -1
- package/dist/react-core/src/index.d.ts +0 -7
package/README.md
CHANGED
|
@@ -257,6 +257,22 @@ interface ConnectorField {
|
|
|
257
257
|
| Primitive
|
|
258
258
|
| Primitive[];
|
|
259
259
|
readonly optionsSource?: SelectOptionSource;
|
|
260
|
+
readonly configs?: {
|
|
261
|
+
selection?: {
|
|
262
|
+
enable?: boolean;
|
|
263
|
+
type?: "MAPPING" | string;
|
|
264
|
+
isAddFields?: boolean;
|
|
265
|
+
isEditKeys?: boolean;
|
|
266
|
+
source?: {
|
|
267
|
+
flowId: string;
|
|
268
|
+
isSameProject: boolean;
|
|
269
|
+
};
|
|
270
|
+
destination?: {
|
|
271
|
+
flowId: string;
|
|
272
|
+
isSameProject: boolean;
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
};
|
|
260
276
|
}
|
|
261
277
|
```
|
|
262
278
|
|
|
@@ -561,6 +577,7 @@ The form fields handle different value types based on the field type:
|
|
|
561
577
|
- **Select fields**: Always return `{ label: string, value: string }` objects
|
|
562
578
|
- **Multi-select fields**: Always return `{ label: string, value: string }[]` arrays
|
|
563
579
|
- **Google Drive picker fields**: Always return `{ label: string, value: string }` objects or arrays
|
|
580
|
+
- **Mapping fields**: Always return `{ label: string, value: string }[]` arrays where `label` is the source field and `value` is the destination field
|
|
564
581
|
- **Other fields**: Return primitive values (string, number, boolean)
|
|
565
582
|
|
|
566
583
|
```tsx
|
|
@@ -584,6 +601,13 @@ const formData = {
|
|
|
584
601
|
{ label: "document2.pdf", value: "file_id_2" }
|
|
585
602
|
],
|
|
586
603
|
|
|
604
|
+
// Mapping field - array of mapping objects
|
|
605
|
+
fieldMappings: [
|
|
606
|
+
{ label: "First Name", value: "user_first_name" },
|
|
607
|
+
{ label: "Email Address", value: "user_email" },
|
|
608
|
+
{ label: "Phone Number", value: "user_phone" }
|
|
609
|
+
],
|
|
610
|
+
|
|
587
611
|
// Text field - primitive
|
|
588
612
|
webhookUrl: "https://hooks.slack.com/...",
|
|
589
613
|
|
|
@@ -781,6 +805,438 @@ function GoogleFilesPickerField({ field, value, onChange, isMulti = false }) {
|
|
|
781
805
|
}
|
|
782
806
|
```
|
|
783
807
|
|
|
808
|
+
### **Mapping Fields**
|
|
809
|
+
|
|
810
|
+
Mapping fields allow users to create relationships between source fields and destination fields. They are commonly used for data transformation scenarios where you need to map fields from one system to another (e.g., mapping CSV columns to database fields, or API response fields to form inputs).
|
|
811
|
+
|
|
812
|
+
#### **Field Type and Value Structure**
|
|
813
|
+
|
|
814
|
+
Mapping fields use the `ConnectorFieldType.MAPPING` type and always work with arrays of mapping objects:
|
|
815
|
+
|
|
816
|
+
```tsx
|
|
817
|
+
// Mapping field value structure
|
|
818
|
+
const mappingValue = [
|
|
819
|
+
{
|
|
820
|
+
label: "Source Field Name", // The source field identifier
|
|
821
|
+
value: "destination_value" // The selected destination field value
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
label: "Email Address",
|
|
825
|
+
value: "user_email"
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
label: "Full Name",
|
|
829
|
+
value: "display_name"
|
|
830
|
+
}
|
|
831
|
+
];
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
#### **Field Configuration**
|
|
835
|
+
|
|
836
|
+
Mapping fields require specific configuration in the `ConnectorField`:
|
|
837
|
+
|
|
838
|
+
```tsx
|
|
839
|
+
interface MappingFieldConfig {
|
|
840
|
+
// Field type must be "mapping"
|
|
841
|
+
type: "mapping";
|
|
842
|
+
|
|
843
|
+
// Configuration for source and destination options
|
|
844
|
+
configs: {
|
|
845
|
+
selection: {
|
|
846
|
+
// Enable mapping functionality
|
|
847
|
+
enable: true;
|
|
848
|
+
type: "MAPPING";
|
|
849
|
+
|
|
850
|
+
// Configuration for adding/editing fields
|
|
851
|
+
isAddFields?: boolean; // Allow users to add new source fields
|
|
852
|
+
isEditKeys?: boolean; // Allow users to edit source field names
|
|
853
|
+
|
|
854
|
+
// Source options configuration
|
|
855
|
+
source: {
|
|
856
|
+
flowId: string; // ID of the flow providing source options
|
|
857
|
+
isSameProject: boolean; // Whether source is in same project
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
// Destination options configuration
|
|
861
|
+
destination: {
|
|
862
|
+
flowId: string; // ID of the flow providing destination options
|
|
863
|
+
isSameProject: boolean; // Whether destination is in same project
|
|
864
|
+
};
|
|
865
|
+
};
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
// Options source for dynamic loading
|
|
869
|
+
optionsSource: {
|
|
870
|
+
getOptions: (pagination, context, searchQuery) => Promise<OptionsResult>;
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
#### **Complete Mapping Field Component**
|
|
876
|
+
|
|
877
|
+
Here's a full implementation of a mapping field component using the `useFieldOptions` hook:
|
|
878
|
+
|
|
879
|
+
```tsx
|
|
880
|
+
import { useCallback, useState, useEffect } from "react";
|
|
881
|
+
import { useFieldOptions } from "@fastn-ai/react-core";
|
|
882
|
+
import Select from "react-select";
|
|
883
|
+
|
|
884
|
+
interface MappingFieldProps {
|
|
885
|
+
field: ConnectorField;
|
|
886
|
+
value: MappingValue[];
|
|
887
|
+
onChange: (value: MappingValue[]) => void;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
interface MappingValue {
|
|
891
|
+
label: string; // Source field name
|
|
892
|
+
value: string; // Destination field value
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
function MappingField({ field, value, onChange }: MappingFieldProps) {
|
|
896
|
+
// Get mapping-specific functions from useFieldOptions
|
|
897
|
+
const {
|
|
898
|
+
selectionConfig,
|
|
899
|
+
getSourceOptions,
|
|
900
|
+
getDestinationOptions,
|
|
901
|
+
} = useFieldOptions(field);
|
|
902
|
+
|
|
903
|
+
const mappingValue = Array.isArray(value) ? value : [];
|
|
904
|
+
|
|
905
|
+
// State for source and destination options
|
|
906
|
+
const [sourceOptions, setSourceOptions] = useState<SelectOption[]>([]);
|
|
907
|
+
const [destinationOptions, setDestinationOptions] = useState<SelectOption[]>([]);
|
|
908
|
+
const [sourceLoading, setSourceLoading] = useState(false);
|
|
909
|
+
const [destinationLoading, setDestinationLoading] = useState(false);
|
|
910
|
+
|
|
911
|
+
// Initialize source options from existing mappings
|
|
912
|
+
const initialSourceOptions = mappingValue.length > 0
|
|
913
|
+
? mappingValue.map((item) => ({
|
|
914
|
+
label: item.label,
|
|
915
|
+
value: item.label,
|
|
916
|
+
}))
|
|
917
|
+
: [];
|
|
918
|
+
|
|
919
|
+
// Load source options
|
|
920
|
+
const loadSourceOptions = useCallback(async () => {
|
|
921
|
+
setSourceLoading(true);
|
|
922
|
+
try {
|
|
923
|
+
const result = await getSourceOptions({ id: "configurationId" });
|
|
924
|
+
const rawOptions = result?.options || [];
|
|
925
|
+
|
|
926
|
+
const newSourceOptions = Array.isArray(rawOptions)
|
|
927
|
+
? rawOptions.map((option) =>
|
|
928
|
+
typeof option === "string"
|
|
929
|
+
? { label: option, value: option }
|
|
930
|
+
: option
|
|
931
|
+
)
|
|
932
|
+
: [];
|
|
933
|
+
setSourceOptions(newSourceOptions);
|
|
934
|
+
} catch (err) {
|
|
935
|
+
console.error("Error loading source options:", err);
|
|
936
|
+
} finally {
|
|
937
|
+
setSourceLoading(false);
|
|
938
|
+
}
|
|
939
|
+
}, [getSourceOptions]);
|
|
940
|
+
|
|
941
|
+
// Load destination options
|
|
942
|
+
const loadDestinationOptions = useCallback(async () => {
|
|
943
|
+
setDestinationLoading(true);
|
|
944
|
+
try {
|
|
945
|
+
const result = await getDestinationOptions({ id: "configurationId" });
|
|
946
|
+
const rawOptions = result?.options || [];
|
|
947
|
+
|
|
948
|
+
const newDestinationOptions = Array.isArray(rawOptions)
|
|
949
|
+
? rawOptions.map((option) =>
|
|
950
|
+
typeof option === "string"
|
|
951
|
+
? { label: option, value: option }
|
|
952
|
+
: option
|
|
953
|
+
)
|
|
954
|
+
: [];
|
|
955
|
+
setDestinationOptions(newDestinationOptions);
|
|
956
|
+
} catch (err) {
|
|
957
|
+
console.error("Error loading destination options:", err);
|
|
958
|
+
} finally {
|
|
959
|
+
setDestinationLoading(false);
|
|
960
|
+
}
|
|
961
|
+
}, [getDestinationOptions]);
|
|
962
|
+
|
|
963
|
+
// Load options on mount
|
|
964
|
+
useEffect(() => {
|
|
965
|
+
// Load source options only if no existing mappings
|
|
966
|
+
if (mappingValue.length === 0) {
|
|
967
|
+
loadSourceOptions();
|
|
968
|
+
} else {
|
|
969
|
+
setSourceOptions(initialSourceOptions);
|
|
970
|
+
}
|
|
971
|
+
loadDestinationOptions();
|
|
972
|
+
}, []);
|
|
973
|
+
|
|
974
|
+
// Add new mapping field
|
|
975
|
+
const handleAddField = () => {
|
|
976
|
+
const newFieldLabel = `Field ${sourceOptions.length + 1}`;
|
|
977
|
+
const newSourceOption = {
|
|
978
|
+
label: newFieldLabel,
|
|
979
|
+
value: newFieldLabel,
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
setSourceOptions([...sourceOptions, newSourceOption]);
|
|
983
|
+
|
|
984
|
+
const newMappingValue = [
|
|
985
|
+
...mappingValue,
|
|
986
|
+
{
|
|
987
|
+
label: newFieldLabel,
|
|
988
|
+
value: "",
|
|
989
|
+
},
|
|
990
|
+
];
|
|
991
|
+
onChange(newMappingValue);
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
// Remove mapping field
|
|
995
|
+
const handleRemoveField = (sourceOption: SelectOption, index: number) => {
|
|
996
|
+
const newSourceOptions = sourceOptions.filter((_, i) => i !== index);
|
|
997
|
+
setSourceOptions(newSourceOptions);
|
|
998
|
+
|
|
999
|
+
const newMappingValue = mappingValue.filter(
|
|
1000
|
+
(mapping) => mapping.label !== sourceOption.label
|
|
1001
|
+
);
|
|
1002
|
+
onChange(newMappingValue);
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
// Update source field label
|
|
1006
|
+
const handleSourceLabelChange = (index: number, sourceOption: SelectOption, newLabel: string) => {
|
|
1007
|
+
const newSourceOptions = [...sourceOptions];
|
|
1008
|
+
newSourceOptions[index] = {
|
|
1009
|
+
...sourceOption,
|
|
1010
|
+
label: newLabel,
|
|
1011
|
+
};
|
|
1012
|
+
setSourceOptions(newSourceOptions);
|
|
1013
|
+
|
|
1014
|
+
const existingIndex = mappingValue.findIndex(
|
|
1015
|
+
(mapping) => mapping.label === sourceOption.label
|
|
1016
|
+
);
|
|
1017
|
+
if (existingIndex >= 0) {
|
|
1018
|
+
const newMappingValue = [...mappingValue];
|
|
1019
|
+
newMappingValue[existingIndex] = {
|
|
1020
|
+
label: newLabel,
|
|
1021
|
+
value: newMappingValue[existingIndex].value,
|
|
1022
|
+
};
|
|
1023
|
+
onChange(newMappingValue);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
// Update destination mapping
|
|
1028
|
+
const handleDestinationChange = (sourceOption: SelectOption, selected: SelectOption | null) => {
|
|
1029
|
+
const existingIndex = mappingValue.findIndex(
|
|
1030
|
+
(mapping) => mapping.label === sourceOption.label
|
|
1031
|
+
);
|
|
1032
|
+
|
|
1033
|
+
let newValue;
|
|
1034
|
+
if (existingIndex >= 0) {
|
|
1035
|
+
// Update existing mapping
|
|
1036
|
+
newValue = [...mappingValue];
|
|
1037
|
+
newValue[existingIndex] = {
|
|
1038
|
+
label: sourceOption.label,
|
|
1039
|
+
value: selected?.value || "",
|
|
1040
|
+
};
|
|
1041
|
+
} else {
|
|
1042
|
+
// Add new mapping
|
|
1043
|
+
newValue = [
|
|
1044
|
+
...mappingValue,
|
|
1045
|
+
{
|
|
1046
|
+
label: sourceOption.label,
|
|
1047
|
+
value: selected?.value || "",
|
|
1048
|
+
},
|
|
1049
|
+
];
|
|
1050
|
+
}
|
|
1051
|
+
onChange(newValue);
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
return (
|
|
1055
|
+
<div className="mapping-field-container">
|
|
1056
|
+
{/* Field label and add button */}
|
|
1057
|
+
<div className="mapping-field-header">
|
|
1058
|
+
<label className="field-label">
|
|
1059
|
+
{field.label}
|
|
1060
|
+
{field.required && <span className="required"> *</span>}
|
|
1061
|
+
</label>
|
|
1062
|
+
|
|
1063
|
+
{selectionConfig?.isAddFields && (
|
|
1064
|
+
<button
|
|
1065
|
+
type="button"
|
|
1066
|
+
onClick={handleAddField}
|
|
1067
|
+
className="add-field-btn"
|
|
1068
|
+
>
|
|
1069
|
+
+ Add Field
|
|
1070
|
+
</button>
|
|
1071
|
+
)}
|
|
1072
|
+
</div>
|
|
1073
|
+
|
|
1074
|
+
{/* Loading state */}
|
|
1075
|
+
{sourceLoading ? (
|
|
1076
|
+
<div className="loading-message">Loading source options...</div>
|
|
1077
|
+
) : sourceOptions.length > 0 ? (
|
|
1078
|
+
/* Mapping rows */
|
|
1079
|
+
sourceOptions.map((sourceOption, index) => (
|
|
1080
|
+
<div key={index} className="mapping-row">
|
|
1081
|
+
{/* Source field (editable if configured) */}
|
|
1082
|
+
<div className="source-field">
|
|
1083
|
+
{selectionConfig?.isEditKeys ? (
|
|
1084
|
+
<EditableLabel
|
|
1085
|
+
value={sourceOption.label}
|
|
1086
|
+
onSave={(newLabel) =>
|
|
1087
|
+
handleSourceLabelChange(index, sourceOption, newLabel)
|
|
1088
|
+
}
|
|
1089
|
+
/>
|
|
1090
|
+
) : (
|
|
1091
|
+
<span className="source-label">{sourceOption.label}</span>
|
|
1092
|
+
)}
|
|
1093
|
+
</div>
|
|
1094
|
+
|
|
1095
|
+
{/* Arrow separator */}
|
|
1096
|
+
<div className="mapping-arrow">→</div>
|
|
1097
|
+
|
|
1098
|
+
{/* Destination field selector */}
|
|
1099
|
+
<div className="destination-field">
|
|
1100
|
+
<Select
|
|
1101
|
+
value={(() => {
|
|
1102
|
+
const mapping = mappingValue.find(
|
|
1103
|
+
(mapping) => mapping.label === sourceOption.label
|
|
1104
|
+
);
|
|
1105
|
+
return mapping
|
|
1106
|
+
? destinationOptions.find(
|
|
1107
|
+
(option) => option.value === mapping.value
|
|
1108
|
+
) || null
|
|
1109
|
+
: null;
|
|
1110
|
+
})()}
|
|
1111
|
+
onChange={(selected) =>
|
|
1112
|
+
handleDestinationChange(sourceOption, selected)
|
|
1113
|
+
}
|
|
1114
|
+
options={destinationOptions}
|
|
1115
|
+
isLoading={destinationLoading}
|
|
1116
|
+
placeholder="Select destination..."
|
|
1117
|
+
className="destination-select"
|
|
1118
|
+
noOptionsMessage={() =>
|
|
1119
|
+
destinationLoading
|
|
1120
|
+
? "Loading destination options..."
|
|
1121
|
+
: "No destination options found"
|
|
1122
|
+
}
|
|
1123
|
+
/>
|
|
1124
|
+
</div>
|
|
1125
|
+
|
|
1126
|
+
{/* Remove field button */}
|
|
1127
|
+
{selectionConfig?.isAddFields && (
|
|
1128
|
+
<button
|
|
1129
|
+
type="button"
|
|
1130
|
+
onClick={() => handleRemoveField(sourceOption, index)}
|
|
1131
|
+
className="remove-field-btn"
|
|
1132
|
+
>
|
|
1133
|
+
🗑️
|
|
1134
|
+
</button>
|
|
1135
|
+
)}
|
|
1136
|
+
</div>
|
|
1137
|
+
))
|
|
1138
|
+
) : (
|
|
1139
|
+
<div className="no-options-message">No source options available</div>
|
|
1140
|
+
)}
|
|
1141
|
+
|
|
1142
|
+
{field.description && (
|
|
1143
|
+
<div className="field-description">{field.description}</div>
|
|
1144
|
+
)}
|
|
1145
|
+
</div>
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
#### **useFieldOptions Hook for Mapping Fields**
|
|
1151
|
+
|
|
1152
|
+
The `useFieldOptions` hook provides specialized functions for mapping fields:
|
|
1153
|
+
|
|
1154
|
+
```tsx
|
|
1155
|
+
const {
|
|
1156
|
+
// Configuration from field.configs.selection
|
|
1157
|
+
selectionConfig: {
|
|
1158
|
+
isAddFields: boolean; // Allow adding new source fields
|
|
1159
|
+
isEditKeys: boolean; // Allow editing source field names
|
|
1160
|
+
source: { // Source options configuration
|
|
1161
|
+
flowId: string;
|
|
1162
|
+
isSameProject: boolean;
|
|
1163
|
+
};
|
|
1164
|
+
destination: { // Destination options configuration
|
|
1165
|
+
flowId: string;
|
|
1166
|
+
isSameProject: boolean;
|
|
1167
|
+
};
|
|
1168
|
+
},
|
|
1169
|
+
|
|
1170
|
+
// Function to load source options
|
|
1171
|
+
getSourceOptions: (context: any) => Promise<OptionsResult>;
|
|
1172
|
+
|
|
1173
|
+
// Function to load destination options
|
|
1174
|
+
getDestinationOptions: (context: any) => Promise<OptionsResult>;
|
|
1175
|
+
|
|
1176
|
+
// Standard field options (for non-mapping fields)
|
|
1177
|
+
options: SelectOption[];
|
|
1178
|
+
loading: boolean;
|
|
1179
|
+
// ... other standard options
|
|
1180
|
+
} = useFieldOptions(field);
|
|
1181
|
+
```
|
|
1182
|
+
|
|
1183
|
+
#### **Mapping Field Usage Example**
|
|
1184
|
+
|
|
1185
|
+
```tsx
|
|
1186
|
+
function ConfigurationForm({ configurationId }) {
|
|
1187
|
+
const { data: configurationForm } = useConfigurationForm({ configurationId });
|
|
1188
|
+
const [formData, setFormData] = useState({});
|
|
1189
|
+
|
|
1190
|
+
return (
|
|
1191
|
+
<form>
|
|
1192
|
+
{configurationForm?.fields.map((field) => {
|
|
1193
|
+
if (field.type === "mapping") {
|
|
1194
|
+
return (
|
|
1195
|
+
<MappingField
|
|
1196
|
+
key={field.key}
|
|
1197
|
+
field={field}
|
|
1198
|
+
value={formData[field.key] || []}
|
|
1199
|
+
onChange={(value) =>
|
|
1200
|
+
setFormData((prev) => ({ ...prev, [field.key]: value }))
|
|
1201
|
+
}
|
|
1202
|
+
/>
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// Handle other field types...
|
|
1207
|
+
return <FormField key={field.key} field={field} />;
|
|
1208
|
+
})}
|
|
1209
|
+
</form>
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
#### **Common Mapping Field Use Cases**
|
|
1215
|
+
|
|
1216
|
+
1. **CSV Column Mapping**: Map CSV headers to database fields
|
|
1217
|
+
2. **API Response Mapping**: Map API response fields to form inputs
|
|
1218
|
+
3. **Data Transformation**: Map source data fields to destination schema
|
|
1219
|
+
4. **Integration Field Mapping**: Map fields between different systems (CRM to Email Marketing, etc.)
|
|
1220
|
+
|
|
1221
|
+
```tsx
|
|
1222
|
+
// Example mapping values for different use cases
|
|
1223
|
+
|
|
1224
|
+
// CSV to Database mapping
|
|
1225
|
+
const csvMappingValue = [
|
|
1226
|
+
{ label: "First Name", value: "user_first_name" },
|
|
1227
|
+
{ label: "Last Name", value: "user_last_name" },
|
|
1228
|
+
{ label: "Email", value: "user_email" },
|
|
1229
|
+
{ label: "Phone", value: "user_phone" }
|
|
1230
|
+
];
|
|
1231
|
+
|
|
1232
|
+
// API Response to Form mapping
|
|
1233
|
+
const apiMappingValue = [
|
|
1234
|
+
{ label: "api_user_id", value: "userId" },
|
|
1235
|
+
{ label: "api_user_email", value: "email" },
|
|
1236
|
+
{ label: "api_user_profile", value: "profile" }
|
|
1237
|
+
];
|
|
1238
|
+
```
|
|
1239
|
+
|
|
784
1240
|
### **Generic Form Field Component**
|
|
785
1241
|
|
|
786
1242
|
Create a reusable component that handles different field types with proper value handling:
|
|
@@ -872,6 +1328,15 @@ function FormField({ field, value, onChange }) {
|
|
|
872
1328
|
/>
|
|
873
1329
|
);
|
|
874
1330
|
|
|
1331
|
+
case "mapping":
|
|
1332
|
+
return (
|
|
1333
|
+
<MappingField
|
|
1334
|
+
field={field}
|
|
1335
|
+
value={value || []}
|
|
1336
|
+
onChange={onChange}
|
|
1337
|
+
/>
|
|
1338
|
+
);
|
|
1339
|
+
|
|
875
1340
|
default:
|
|
876
1341
|
return (
|
|
877
1342
|
<div className="field-container">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
-
import { Fastn } from "
|
|
3
|
-
import type { FastnConfig } from "
|
|
2
|
+
import { Fastn } from "@dev-fastn-ai/core";
|
|
3
|
+
import type { FastnConfig } from "@dev-fastn-ai/core";
|
|
4
4
|
export declare const FastnProvider: ({ children, config, queryClient, }: {
|
|
5
5
|
children: React.ReactNode;
|
|
6
6
|
config: FastnConfig;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { GetConfigurationFormInput } from "@dev-fastn-ai/core";
|
|
2
|
-
export declare const useConfigurationForm: (input: GetConfigurationFormInput) => import("@tanstack/react-query").UseQueryResult<import("
|
|
2
|
+
export declare const useConfigurationForm: (input: GetConfigurationFormInput) => import("@tanstack/react-query").UseQueryResult<import("@dev-fastn-ai/core").ConfigurationForm, Error>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { GetConfigurationsInput } from "@dev-fastn-ai/core";
|
|
2
|
-
export declare const useConfigurations: (input: GetConfigurationsInput) => import("@tanstack/react-query").UseQueryResult<import("
|
|
2
|
+
export declare const useConfigurations: (input: GetConfigurationsInput) => import("@tanstack/react-query").UseQueryResult<import("@dev-fastn-ai/core").Configuration[], Error>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useConnectors: () => import("@tanstack/react-query").UseQueryResult<import("@dev-fastn-ai/core").Connector[], Error>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConnectorField, SelectOption } from "@dev-fastn-ai/core";
|
|
1
|
+
import type { ConnectorField, SelectOption, OptionsResult } from "@dev-fastn-ai/core";
|
|
2
2
|
/**
|
|
3
3
|
* Custom hook to manage async select field options with search, pagination, and error handling using React Query.
|
|
4
4
|
*
|
|
@@ -23,6 +23,9 @@ import type { ConnectorField, SelectOption } from "@dev-fastn-ai/core";
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
export declare function useFieldOptions(field: ConnectorField): {
|
|
26
|
+
getSourceOptions: (context: any) => Promise<OptionsResult | null>;
|
|
27
|
+
getDestinationOptions: (context: any) => Promise<OptionsResult | null>;
|
|
28
|
+
selectionConfig: any;
|
|
26
29
|
options: SelectOption[];
|
|
27
30
|
loading: boolean;
|
|
28
31
|
loadingMore: boolean;
|