Skip to content

Commit b947ef1

Browse files
author
DK09876
committed
Refactor selection.ts
1 parent 68e4d1b commit b947ef1

File tree

3 files changed

+173
-97
lines changed

3 files changed

+173
-97
lines changed

src/baseOAuth/core/selection.ts

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { OAuthConfig, OAuthError, OAuthResponse } from '../types';
2+
import { validateConfig } from '../utils/validation';
3+
4+
/**
5+
* Abstract base class for file selection functionality
6+
* Can be extended by connector-specific implementations
7+
*/
8+
export abstract class BaseSelection {
9+
/**
10+
* Creates a popup window for file selection
11+
*
12+
* @param width Width of the popup window
13+
* @param height Height of the popup window
14+
* @param title Title of the popup window
15+
* @returns The created popup window or null if creation failed
16+
*/
17+
protected static createPopupWindow(
18+
width: number = 1200,
19+
height: number = 800,
20+
title: string = 'File Selection'
21+
): Window | null {
22+
const left = window.screenX + (window.outerWidth - width) / 2;
23+
const top = window.screenY + (window.outerHeight - height) / 2;
24+
25+
const popup = window.open(
26+
'about:blank',
27+
title,
28+
`width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`
29+
);
30+
31+
if (!popup) {
32+
throw new OAuthError(
33+
'Failed to open popup window. Please check if popups are blocked.',
34+
'POPUP_BLOCKED'
35+
);
36+
}
37+
38+
return popup;
39+
}
40+
41+
/**
42+
* Sets up the OAuth handler in the window object
43+
*
44+
* @param config OAuth configuration with success and error callbacks
45+
*/
46+
protected static setupOAuthHandler(config: OAuthConfig): void {
47+
const { onSuccess, onError } = config;
48+
49+
// Store configuration for the callback to access
50+
(window as any).__oauthHandler = {
51+
onSuccess,
52+
onError: (error: string | OAuthError) => {
53+
if (typeof error === 'string') {
54+
error = new OAuthError(error, 'UNKNOWN_ERROR');
55+
}
56+
onError?.(error);
57+
},
58+
OAuthError // Make error constructor available to popup
59+
};
60+
}
61+
62+
/**
63+
* Monitors a popup window and cleans up when it's closed
64+
*
65+
* @param popup The popup window to monitor
66+
*/
67+
protected static monitorPopup(popup: Window | null): void {
68+
if (!popup) {
69+
return; // Nothing to monitor
70+
}
71+
72+
const checkPopup = setInterval(() => {
73+
if (popup.closed) {
74+
clearInterval(checkPopup);
75+
delete (window as any).__oauthHandler;
76+
}
77+
}, 500);
78+
}
79+
80+
/**
81+
* Writes content to a popup window
82+
*
83+
* @param popup The popup window to write to
84+
* @param content The HTML content to write
85+
*/
86+
protected static writeToPopup(popup: Window | null, content: string): void {
87+
if (!popup) {
88+
throw new OAuthError('Cannot write to null popup', 'INVALID_POPUP');
89+
}
90+
91+
popup.document.open();
92+
popup.document.write(content);
93+
popup.document.close();
94+
}
95+
96+
/**
97+
* Abstract method to be implemented by connector-specific classes
98+
* This is the main entry point for file selection
99+
*/
100+
abstract startFileSelection(
101+
config: OAuthConfig,
102+
refreshToken: string,
103+
selectedFiles?: Record<string, { name: string; mimeType: string }>,
104+
targetWindow?: Window
105+
): Promise<Window | null>;
106+
}
+66-97
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,82 @@
1-
import { OAuthConfig, OAuthError, TokenError } from '../types';
2-
import { validateConfig } from '../utils/validation';
3-
import { refreshGDriveAccessToken } from '../utils/token';
1+
import { OAuthError, TokenError } from '../../baseOAuth/types';
2+
import { BaseSelection } from '../../baseOAuth/core/selection';
3+
import { validateConfig } from '../../baseOAuth/utils/validation';
4+
import { refreshGDriveToken } from '../utils/token';
45
import { GoogleDrivePicker } from '../ui/picker';
6+
import { GoogleDriveOAuthConfig } from '../types';
57

68
/**
7-
* Creates a popup for file selection using an existing refresh token
8-
* @param config The OAuth configuration
9-
* @param refreshToken An existing refresh token to use
10-
* @param selectedFiles Optional map of files to initialize as selected
11-
* @param targetWindow Optional window to use instead of creating a new popup
12-
* @returns The popup window instance or null if creation failed
9+
* Google Drive implementation of file selection functionality
1310
*/
14-
export async function startGDriveFileSelection(
15-
config: OAuthConfig,
16-
refreshToken: string,
17-
selectedFiles?: Record<string, { name: string; mimeType: string }>,
18-
targetWindow?: Window
19-
): Promise<Window | null> {
20-
try {
21-
validateConfig(config);
22-
23-
const {
24-
clientId,
25-
clientSecret,
26-
apiKey,
27-
onSuccess,
28-
onError,
29-
} = config;
30-
31-
// Store configuration for the callback to access
32-
(window as any).__oauthHandler = {
33-
onSuccess,
34-
onError: (error: string | OAuthError) => {
35-
if (typeof error === 'string') {
36-
error = new OAuthError(error, 'UNKNOWN_ERROR');
37-
}
38-
onError?.(error);
39-
},
40-
OAuthError // Make error constructor available to popup
41-
};
42-
11+
export class GoogleDriveSelection extends BaseSelection {
12+
/**
13+
* Creates a popup for Google Drive file selection using an existing refresh token
14+
*
15+
* @param config The Google Drive OAuth configuration
16+
* @param refreshToken An existing refresh token to use
17+
* @param selectedFiles Optional map of files to initialize as selected
18+
* @param targetWindow Optional window to use instead of creating a new popup
19+
* @returns The popup window instance or null if creation failed
20+
*/
21+
async startFileSelection(
22+
config: GoogleDriveOAuthConfig,
23+
refreshToken: string,
24+
selectedFiles?: Record<string, { name: string; mimeType: string }>,
25+
targetWindow?: Window
26+
): Promise<Window | null> {
4327
try {
44-
// Refresh the token first
45-
const tokens = await refreshGDriveAccessToken(clientId, clientSecret, refreshToken);
46-
47-
let popup: Window;
48-
49-
if (targetWindow) {
50-
// Use the provided window
51-
popup = targetWindow;
52-
} else {
53-
// Create a blank popup window
54-
const width = 1200;
55-
const height = 800;
56-
const left = window.screenX + (window.outerWidth - width) / 2;
57-
const top = window.screenY + (window.outerHeight - height) / 2;
28+
validateConfig(config);
5829

59-
const newPopup = window.open(
60-
'about:blank',
61-
'File Selection',
62-
`width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`
63-
);
30+
// Set up handler for callbacks
31+
GoogleDriveSelection.setupOAuthHandler(config);
6432

65-
if (!newPopup) {
66-
throw new OAuthError('Failed to open popup window. Please check if popups are blocked.', 'POPUP_BLOCKED');
67-
}
33+
try {
34+
// Refresh the token first
35+
const tokens = await refreshGDriveToken(refreshToken, config.clientId, config.clientSecret);
6836

69-
popup = newPopup;
70-
}
71-
72-
// Generate the file picker content using the central module
73-
// Pass the selectedFiles parameter to createPickerHTML
74-
const content = GoogleDrivePicker.createPickerHTML(tokens, config, refreshToken, selectedFiles);
75-
76-
// Write the HTML content to the popup
77-
popup.document.open();
78-
popup.document.write(content);
79-
popup.document.close();
37+
// Use provided window or create a new popup
38+
const popup = targetWindow || GoogleDriveSelection.createPopupWindow(1200, 800, 'Google Drive File Selection');
39+
40+
// Generate the Google Drive file picker content
41+
const content = GoogleDrivePicker.createPickerHTML(
42+
{
43+
access_token: tokens.access_token,
44+
refresh_token: refreshToken,
45+
expires_in: tokens.expires_in,
46+
token_type: tokens.token_type
47+
},
48+
config,
49+
refreshToken,
50+
selectedFiles
51+
);
52+
53+
// Write content to the popup
54+
GoogleDriveSelection.writeToPopup(popup, content);
8055

81-
// Monitor popup and cleanup
82-
const checkPopup = setInterval(() => {
83-
if (popup.closed) {
84-
clearInterval(checkPopup);
85-
delete (window as any).__oauthHandler;
86-
}
87-
}, 500);
56+
// Monitor the popup
57+
GoogleDriveSelection.monitorPopup(popup);
8858

89-
return popup;
59+
return popup;
60+
} catch (error) {
61+
if (error instanceof OAuthError) {
62+
throw error;
63+
}
64+
throw new TokenError(
65+
error instanceof Error ? error.message : 'Failed to refresh token or create selection popup',
66+
error
67+
);
68+
}
9069
} catch (error) {
9170
if (error instanceof OAuthError) {
92-
throw error;
71+
config.onError?.(error);
72+
} else {
73+
config.onError?.(new OAuthError(
74+
error instanceof Error ? error.message : 'An unknown error occurred',
75+
'UNKNOWN_ERROR',
76+
error
77+
));
9378
}
94-
throw new TokenError(
95-
error instanceof Error ? error.message : 'Failed to refresh token or create selection popup',
96-
{
97-
originalError: error
98-
}
99-
);
100-
}
101-
} catch (error) {
102-
if (error instanceof OAuthError) {
103-
config.onError?.(error);
104-
} else {
105-
config.onError?.(new OAuthError(
106-
error instanceof Error ? error.message : 'An unknown error occurred',
107-
'UNKNOWN_ERROR',
108-
error
109-
));
79+
return null;
11080
}
111-
return null;
11281
}
11382
}

src/googleDriveOAuth/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from './types';
55
export * from './core/apiFunctions';
66
export * from './core/oauth';
77
export * from './utils/token';
8+
export * from './core/selection';
89

910
// Re-export base types and functions that are useful for consumers
1011
export { BaseOAuth } from '../baseOAuth'; // Value (class) export

0 commit comments

Comments
 (0)