Skip to content

Commit 6ce699c

Browse files
committed
refactor: extract shared integration scanning logic to utility function
1 parent b85e70a commit 6ce699c

File tree

3 files changed

+79
-58
lines changed

3 files changed

+79
-58
lines changed

src/notebooks/deepnote/integrations/integrationDetector.ts

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { inject, injectable } from 'inversify';
22

33
import { logger } from '../../../platform/logging';
44
import { IDeepnoteNotebookManager } from '../../types';
5-
import { DATAFRAME_SQL_INTEGRATION_ID, IntegrationStatus, IntegrationWithStatus } from './integrationTypes';
5+
import { IntegrationStatus, IntegrationWithStatus } from './integrationTypes';
66
import { IIntegrationDetector, IIntegrationStorage } from './types';
7+
import { BlockWithIntegration, scanBlocksForIntegrations } from './integrationUtils';
78

89
/**
910
* Service for detecting integrations used in Deepnote notebooks
@@ -19,55 +20,31 @@ export class IntegrationDetector implements IIntegrationDetector {
1920
* Detect all integrations used in the given project
2021
*/
2122
async detectIntegrations(projectId: string): Promise<Map<string, IntegrationWithStatus>> {
22-
const integrations = new Map<string, IntegrationWithStatus>();
23-
2423
// Get the project
2524
const project = this.notebookManager.getOriginalProject(projectId);
2625
if (!project) {
2726
logger.warn(
2827
`IntegrationDetector: No project found for ID: ${projectId}. The project may not have been loaded yet.`
2928
);
30-
return integrations;
29+
return new Map();
3130
}
3231

3332
logger.debug(
3433
`IntegrationDetector: Scanning project ${projectId} with ${project.project.notebooks.length} notebooks`
3534
);
3635

37-
// Scan all notebooks in the project
36+
// Collect all blocks with SQL integration metadata from all notebooks
37+
const blocksWithIntegrations: BlockWithIntegration[] = [];
3838
for (const notebook of project.project.notebooks) {
3939
logger.trace(`IntegrationDetector: Scanning notebook ${notebook.id} with ${notebook.blocks.length} blocks`);
4040

41-
// Scan all blocks in the notebook
4241
for (const block of notebook.blocks) {
4342
// Check if this is a code block with SQL integration metadata
4443
if (block.type === 'code' && block.metadata?.sql_integration_id) {
45-
const integrationId = block.metadata.sql_integration_id;
46-
47-
// Skip excluded integrations (e.g., internal DuckDB integration)
48-
if (integrationId === DATAFRAME_SQL_INTEGRATION_ID) {
49-
logger.trace(
50-
`IntegrationDetector: Skipping excluded integration: ${integrationId} in block ${block.id}`
51-
);
52-
continue;
53-
}
54-
55-
logger.debug(`IntegrationDetector: Found integration: ${integrationId} in block ${block.id}`);
56-
57-
// Skip if we've already detected this integration
58-
if (integrations.has(integrationId)) {
59-
continue;
60-
}
61-
62-
// Check if the integration is configured
63-
const config = await this.integrationStorage.get(integrationId);
64-
65-
const status: IntegrationWithStatus = {
66-
config: config || null,
67-
status: config ? IntegrationStatus.Connected : IntegrationStatus.Disconnected
68-
};
69-
70-
integrations.set(integrationId, status);
44+
blocksWithIntegrations.push({
45+
id: block.id,
46+
sql_integration_id: block.metadata.sql_integration_id
47+
});
7148
} else if (block.type === 'code') {
7249
logger.trace(
7350
`IntegrationDetector: Block ${block.id} has no sql_integration_id. Metadata:`,
@@ -77,8 +54,8 @@ export class IntegrationDetector implements IIntegrationDetector {
7754
}
7855
}
7956

80-
logger.debug(`IntegrationDetector: Found ${integrations.size} integrations`);
81-
return integrations;
57+
// Use the shared utility to scan blocks and build the status map
58+
return scanBlocksForIntegrations(blocksWithIntegrations, this.integrationStorage, 'IntegrationDetector');
8259
}
8360

8461
/**

src/notebooks/deepnote/integrations/integrationManager.ts

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { Commands } from '../../../platform/common/constants';
66
import { logger } from '../../../platform/logging';
77
import { IntegrationWebviewProvider } from './integrationWebview';
88
import { IIntegrationDetector, IIntegrationStorage } from './types';
9-
import { DATAFRAME_SQL_INTEGRATION_ID, IntegrationStatus, IntegrationWithStatus } from './integrationTypes';
9+
import { IntegrationStatus, IntegrationWithStatus } from './integrationTypes';
10+
import { BlockWithIntegration, scanBlocksForIntegrations } from './integrationUtils';
1011

1112
/**
1213
* Manages integration UI and commands for Deepnote notebooks
@@ -139,38 +140,22 @@ export class IntegrationManager {
139140
* This is used when the project isn't stored in the notebook manager
140141
*/
141142
private async detectIntegrationsFromCells(notebook: NotebookDocument): Promise<Map<string, IntegrationWithStatus>> {
142-
const integrations = new Map<string, IntegrationWithStatus>();
143+
// Collect all cells with SQL integration metadata
144+
const blocksWithIntegrations: BlockWithIntegration[] = [];
143145

144146
for (const cell of notebook.getCells()) {
145147
const deepnoteMetadata = cell.metadata?.deepnoteMetadata;
146148
logger.trace(`IntegrationManager: Cell ${cell.index} metadata:`, deepnoteMetadata);
147149

148150
if (deepnoteMetadata?.sql_integration_id) {
149-
const integrationId = deepnoteMetadata.sql_integration_id;
150-
151-
// Skip excluded integrations (e.g., internal DuckDB integration)
152-
if (integrationId === DATAFRAME_SQL_INTEGRATION_ID) {
153-
logger.trace(`IntegrationManager: Skipping excluded integration: ${integrationId}`);
154-
continue;
155-
}
156-
157-
// Skip if we've already detected this integration
158-
if (integrations.has(integrationId)) {
159-
continue;
160-
}
161-
162-
// Check if the integration is configured
163-
const config = await this.integrationStorage.get(integrationId);
164-
165-
integrations.set(integrationId, {
166-
config: config || null,
167-
status: config ? IntegrationStatus.Connected : IntegrationStatus.Disconnected
151+
blocksWithIntegrations.push({
152+
id: `cell-${cell.index}`,
153+
sql_integration_id: deepnoteMetadata.sql_integration_id
168154
});
169-
170-
logger.debug(`IntegrationManager: Found integration in cell: ${integrationId}`);
171155
}
172156
}
173157

174-
return integrations;
158+
// Use the shared utility to scan blocks and build the status map
159+
return scanBlocksForIntegrations(blocksWithIntegrations, this.integrationStorage, 'IntegrationManager');
175160
}
176161
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { logger } from '../../../platform/logging';
2+
import { IIntegrationStorage } from './types';
3+
import { DATAFRAME_SQL_INTEGRATION_ID, IntegrationStatus, IntegrationWithStatus } from './integrationTypes';
4+
5+
/**
6+
* Represents a block with SQL integration metadata
7+
*/
8+
export interface BlockWithIntegration {
9+
id: string;
10+
sql_integration_id: string;
11+
}
12+
13+
/**
14+
* Scans blocks for SQL integrations and builds a status map.
15+
* This is the core logic shared between IntegrationDetector and IntegrationManager.
16+
*
17+
* @param blocks - Iterator of blocks to scan (can be from Deepnote project or VSCode notebook cells)
18+
* @param integrationStorage - Storage service to check configuration status
19+
* @param logContext - Context string for logging (e.g., "IntegrationDetector", "IntegrationManager")
20+
* @returns Map of integration IDs to their status
21+
*/
22+
export async function scanBlocksForIntegrations(
23+
blocks: Iterable<BlockWithIntegration>,
24+
integrationStorage: IIntegrationStorage,
25+
logContext: string
26+
): Promise<Map<string, IntegrationWithStatus>> {
27+
const integrations = new Map<string, IntegrationWithStatus>();
28+
29+
for (const block of blocks) {
30+
const integrationId = block.sql_integration_id;
31+
32+
// Skip excluded integrations (e.g., internal DuckDB integration)
33+
if (integrationId === DATAFRAME_SQL_INTEGRATION_ID) {
34+
logger.trace(`${logContext}: Skipping excluded integration: ${integrationId} in block ${block.id}`);
35+
continue;
36+
}
37+
38+
// Skip if we've already detected this integration
39+
if (integrations.has(integrationId)) {
40+
continue;
41+
}
42+
43+
logger.debug(`${logContext}: Found integration: ${integrationId} in block ${block.id}`);
44+
45+
// Check if the integration is configured
46+
const config = await integrationStorage.get(integrationId);
47+
48+
const status: IntegrationWithStatus = {
49+
config: config || null,
50+
status: config ? IntegrationStatus.Connected : IntegrationStatus.Disconnected
51+
};
52+
53+
integrations.set(integrationId, status);
54+
}
55+
56+
logger.debug(`${logContext}: Found ${integrations.size} integrations`);
57+
return integrations;
58+
}
59+

0 commit comments

Comments
 (0)