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
3 changes: 3 additions & 0 deletions packages/backend/src/adapters/adapters.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ export class AdaptersService {
headers: resolvedHeaders as any,
envVars: envVarsToPersist as any,
instructions: adapter.instructions || null,
// Persist the source adapter slug so the UI can resolve the brand
// logo (via resolveAdapterIcon) even after the connector is renamed.
config: { adapterSlug: slug },
},
});

Expand Down
47 changes: 47 additions & 0 deletions packages/backend/src/connectors/connector-icon.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { listAdapters, getAdapter } from '../adapters/catalog';

/**
* Resolve the adapter icon for a given Connector row.
*
* Preference order:
* 1. `connector.config.adapterSlug` (set at import time by AdaptersService)
* — survives connector renames.
* 2. Reverse lookup by `connector.name`. Works for connectors created
* before adapterSlug tracking was added, and for any future import
* that forgets to set the slug. Renaming the connector breaks this
* fallback (the UI gracefully degrades to the generic type badge).
*
* Returns the adapter's `icon` field (e.g. "wordpress", "woocommerce")
* which the frontend maps to `/logos/connectors/<icon>.svg`. Returns null
* if no match.
*/

// Built once at module load. Module-level so we don't iterate the catalog
// on every request.
const nameToIcon: Map<string, string> = (() => {
const map = new Map<string, string>();
for (const meta of listAdapters()) {
const adapter = getAdapter(meta.slug);
if (!adapter?.icon) continue;
const connName = (adapter.connector as { name?: string }).name;
if (connName && !map.has(connName)) {
map.set(connName, adapter.icon);
}
}
return map;
})();

export function resolveAdapterIcon(connector: {
name: string;
config?: unknown;
}): string | null {
// 1) Explicit slug from config (set at import time)
const cfg = connector.config as Record<string, unknown> | null | undefined;
const slugFromConfig = cfg && typeof cfg.adapterSlug === 'string' ? cfg.adapterSlug : null;
if (slugFromConfig) {
const adapter = getAdapter(slugFromConfig);
if (adapter?.icon) return adapter.icon;
}
// 2) Fallback: name match
return nameToIcon.get(connector.name) ?? null;
}
10 changes: 6 additions & 4 deletions packages/backend/src/connectors/connectors.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DatabaseEngine } from './engines/database.engine';
import { McpClientEngine } from './engines/mcp-client.engine';
import { encrypt, decrypt } from '../common/crypto/encryption.util';
import { getRequiredSecret } from '../common/secrets.util';
import { resolveAdapterIcon } from './connector-icon.util';

@Injectable()
export class ConnectorsService {
Expand Down Expand Up @@ -48,25 +49,26 @@ export class ConnectorsService {
async findByOrg(
organizationId: string,
opts?: { limit?: number; offset?: number },
): Promise<Connector[]> {
return this.prisma.connector.findMany({
): Promise<Array<Connector & { icon: string | null }>> {
const rows = await this.prisma.connector.findMany({
where: { organizationId },
include: { tools: true },
orderBy: { createdAt: 'desc' },
...(opts?.limit !== undefined ? { take: opts.limit } : {}),
...(opts?.offset !== undefined ? { skip: opts.offset } : {}),
});
return rows.map((c) => ({ ...c, icon: resolveAdapterIcon(c) }));
}

async findById(id: string): Promise<Connector> {
async findById(id: string): Promise<Connector & { icon: string | null }> {
const connector = await this.prisma.connector.findUnique({
where: { id },
include: { tools: true, resources: true, prompts: true, mcpServers: { select: { mcpServerId: true } } },
});
if (!connector) {
throw new NotFoundException(`Connector ${id} not found`);
}
return connector;
return { ...connector, icon: resolveAdapterIcon(connector) };
}

async findByIdInternal(id: string): Promise<Connector> {
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/adyen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/airtable.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/apollo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/asana.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/basecamp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions packages/frontend/public/logos/connectors/billomat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/bluesky.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/box.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/brevo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/frontend/public/logos/connectors/buffer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading