Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 18 additions & 2 deletions backend/onyx/connectors/salesforce/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ def _full_sync(
) -> 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!")

Expand Down Expand Up @@ -622,7 +622,7 @@ def _delta_sync(
) -> 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!")

Expand Down Expand Up @@ -936,12 +936,28 @@ def _make_context(

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
}
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:
queryable_fields = sf_client.get_queryable_fields_by_type(
parent_type
)
raise RuntimeError(
f"Associations {associations_config} not found in {parent_type} "
"make sure your parent-child associations are in the right order"
# f"with child objects {child_types_all}"
# f" and fields {queryable_fields}"
)

parent_to_child_relationships[parent_type] = set()
parent_to_child_types[parent_type] = set()
Expand Down
13 changes: 13 additions & 0 deletions web/src/components/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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";
import {
TypedFile,
createTypedFile,
Expand Down Expand Up @@ -92,6 +93,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" : ""}`}
Expand Down
85 changes: 85 additions & 0 deletions web/src/components/RichTextSubtext.tsx
Original file line number Diff line number Diff line change
@@ -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>;
}
7 changes: 2 additions & 5 deletions web/src/lib/connectors/connectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.`,
},
],
},
Expand Down
Loading