Compare commits

...

3 Commits

Author SHA1 Message Date
Evan Lohn
b89643f28c better logs and new attempt 2025-08-08 09:58:48 -07:00
Evan Lohn
555630070b more sf logs 2025-08-07 19:18:37 -07:00
Evan Lohn
1d16c96009 fix: sf connector docs 2025-08-07 19:18:37 -07:00
4 changed files with 114 additions and 8 deletions

View File

@@ -438,7 +438,7 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnector):
) -> GenerateDocumentsOutput:
type_to_processed: dict[str, int] = {}
logger.info("_fetch_from_salesforce starting.")
logger.info("_fetch_from_salesforce starting (full sync).")
if not self._sf_client:
raise RuntimeError("self._sf_client is None!")
@@ -622,7 +622,7 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnector):
) -> GenerateDocumentsOutput:
type_to_processed: dict[str, int] = {}
logger.info("_fetch_from_salesforce starting.")
logger.info("_fetch_from_salesforce starting (delta sync).")
if not self._sf_client:
raise RuntimeError("self._sf_client is None!")
@@ -936,12 +936,23 @@ class SalesforceConnector(LoadConnector, PollConnector, SlimConnector):
child_types_all = sf_client.get_children_of_sf_type(parent_type)
logger.debug(f"Found {len(child_types_all)} child types for {parent_type}")
logger.debug(f"child types: {child_types_all}")
child_types_working = child_types_all.copy()
if associations_config is not None:
child_types_working = {
k: v for k, v in child_types_all.items() if k in associations_config
k: v for k, v in child_types_all.items() if v in associations_config
}
any_not_found = False
for k in associations_config:
if k not in child_types_working:
any_not_found = True
logger.warning(f"Association {k} not found in {parent_type}")
if any_not_found:
raise RuntimeError(
f"Associations {associations_config} not found in {parent_type} "
f"with child objects {child_types_all}"
)
parent_to_child_relationships[parent_type] = set()
parent_to_child_types[parent_type] = set()

View File

@@ -37,6 +37,7 @@ import { transformLinkUri } from "@/lib/utils";
import FileInput from "@/app/admin/connectors/[connector]/pages/ConnectorInput/FileInput";
import { DatePicker } from "./ui/datePicker";
import { Textarea, TextareaProps } from "./ui/textarea";
import { RichTextSubtext } from "./RichTextSubtext";
export function SectionHeader({
children,
@@ -85,6 +86,18 @@ export function SubLabel({ children }: { children: string | JSX.Element }) {
// Add whitespace-pre-wrap for multiline descriptions (when children is a string with newlines)
const hasNewlines = typeof children === "string" && children.includes("\n");
// If children is a string, use RichTextSubtext to parse and render links
if (typeof children === "string") {
return (
<div className="text-sm text-neutral-600 dark:text-neutral-300 mb-2">
<RichTextSubtext
text={children}
className={hasNewlines ? "whitespace-pre-wrap" : ""}
/>
</div>
);
}
return (
<div
className={`text-sm text-neutral-600 dark:text-neutral-300 mb-2 ${hasNewlines ? "whitespace-pre-wrap" : ""}`}

View File

@@ -0,0 +1,85 @@
import React from "react";
interface RichTextSubtextProps {
text: string;
className?: string;
}
/**
* Component that renders text with clickable links.
* Detects URLs in the text and converts them to clickable links.
* Also supports markdown-style links like [text](url).
*/
export function RichTextSubtext({
text,
className = "",
}: RichTextSubtextProps) {
// Function to parse text and create React elements
const parseText = (input: string): React.ReactNode[] => {
const elements: React.ReactNode[] = [];
// Regex to match markdown links [text](url) and plain URLs
const combinedRegex = /(\[([^\]]+)\]\(([^)]+)\))|(https?:\/\/[^\s]+)/g;
let lastIndex = 0;
let match;
let key = 0;
while ((match = combinedRegex.exec(input)) !== null) {
// Add text before the match
if (match.index > lastIndex) {
elements.push(
<span key={`text-${key++}`}>
{input.slice(lastIndex, match.index)}
</span>
);
}
if (match[1]) {
// Markdown-style link [text](url)
const linkText = match[2];
const url = match[3];
elements.push(
<a
key={`link-${key++}`}
href={url}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover underline"
onClick={(e) => e.stopPropagation()}
>
{linkText}
</a>
);
} else if (match[4]) {
// Plain URL
const url = match[4];
elements.push(
<a
key={`link-${key++}`}
href={url}
target="_blank"
rel="noopener noreferrer"
className="text-link hover:text-link-hover underline"
onClick={(e) => e.stopPropagation()}
>
{url}
</a>
);
}
lastIndex = match.index + match[0].length;
}
// Add remaining text after the last match
if (lastIndex < input.length) {
elements.push(
<span key={`text-${key++}`}>{input.slice(lastIndex)}</span>
);
}
return elements;
};
return <div className={className}>{parseText(text)}</div>;
}

View File

@@ -638,15 +638,12 @@ Example:
"Account": {
"fields": ["Id", "Name", "Industry"],
"associations": {
"Contact": {
"fields": ["Id", "FirstName", "LastName", "Email"],
"associations": {}
}
"Contact": ["Id", "FirstName", "LastName", "Email"]
}
}
}
See our docs for more details.`,
[See our docs](https://docs.onyx.app/connectors/salesforce) for more details.`,
},
],
},