Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
7 changes: 7 additions & 0 deletions src/messageTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,18 @@ export type LocalizedMessages = {
integrationsConfigure: string;
integrationsReconfigure: string;
integrationsReset: string;
integrationsDelete: string;
integrationsConfirmResetTitle: string;
integrationsConfirmResetMessage: string;
integrationsConfirmResetDetails: string;
integrationsConfirmDeleteTitle: string;
integrationsConfirmDeleteMessage: string;
integrationsConfirmDeleteDetails: string;
integrationsConfigureTitle: string;
integrationsCancel: string;
integrationsSave: string;
integrationsAddNewIntegration: string;
integrationsDatabase: string;
// Integration type labels
integrationsPostgresTypeLabel: string;
integrationsBigQueryTypeLabel: string;
Expand Down Expand Up @@ -442,6 +448,7 @@ export type LocalizedMessages = {
integrationsRequiredField: string;
integrationsOptionalField: string;
integrationsUnnamedIntegration: string;
integrationsDefaultName: string;
integrationsUnsupportedIntegrationType: string;
// Select input settings strings
selectInputSettingsTitle: string;
Expand Down
31 changes: 19 additions & 12 deletions src/notebooks/deepnote/integrations/integrationWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,16 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
integrationsConfigure: localize.Integrations.configure,
integrationsReconfigure: localize.Integrations.reconfigure,
integrationsReset: localize.Integrations.reset,
integrationsDelete: localize.Integrations.deleteIntegration,
integrationsConfirmResetTitle: localize.Integrations.confirmResetTitle,
integrationsConfirmResetMessage: localize.Integrations.confirmResetMessage,
integrationsConfirmResetDetails: localize.Integrations.confirmResetDetails,
integrationsConfirmDeleteTitle: localize.Integrations.confirmDeleteTitle,
integrationsConfirmDeleteMessage: localize.Integrations.confirmDeleteMessage,
integrationsConfirmDeleteDetails: localize.Integrations.confirmDeleteDetails,
integrationsConfigureTitle: localize.Integrations.configureTitle,
integrationsAddNewIntegration: localize.Integrations.addNewIntegration,
integrationsDatabase: localize.Integrations.database,
integrationsPostgresTypeLabel: localize.Integrations.postgresTypeLabel,
integrationsBigQueryTypeLabel: localize.Integrations.bigQueryTypeLabel,
integrationsSnowflakeTypeLabel: localize.Integrations.snowflakeTypeLabel,
Expand Down Expand Up @@ -373,6 +379,7 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
integrationsCaCertificateText: localize.Integrations.caCertificateText,
integrationsCaCertificateTextPlaceholder: localize.Integrations.caCertificateTextPlaceholder,
integrationsUnnamedIntegration: localize.Integrations.unnamedIntegration('{0}'),
integrationsDefaultName: localize.Integrations.defaultName('{0}'),
integrationsUnsupportedIntegrationType: localize.Integrations.unsupportedIntegrationType('{0}')
};

Expand Down Expand Up @@ -464,9 +471,20 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
// Update local state
const integration = this.integrations.get(integrationId);
if (integration) {
// Existing integration - update it
integration.config = config;
integration.status = IntegrationStatus.Connected;
integration.integrationName = config.name;
integration.integrationType = config.type;
this.integrations.set(integrationId, integration);
} else {
// New integration - add it to the map
this.integrations.set(integrationId, {
config,
status: IntegrationStatus.Connected,
integrationName: config.name,
integrationType: config.type
});
}

// Update the project's integrations list
Expand Down Expand Up @@ -590,16 +608,6 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
'index.js'
)
);
const styleUri = webview.asWebviewUri(
Uri.joinPath(
this.extensionContext.extensionUri,
'dist',
'webviews',
'webview-side',
'integrations',
'integrations.css'
)
);
const codiconUri = webview.asWebviewUri(
Uri.joinPath(
this.extensionContext.extensionUri,
Expand All @@ -617,9 +625,8 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}'; font-src ${webview.cspSource};">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${webview.cspSource} https: data:; style-src ${webview.cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}'; font-src ${webview.cspSource};">
<link rel="stylesheet" href="${codiconUri}">
<link rel="stylesheet" href="${styleUri}">
<title>Deepnote Integrations</title>
</head>
<body>
Expand Down
63 changes: 21 additions & 42 deletions src/notebooks/deepnote/sqlCellStatusBarProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ interface LocalQuickPickItem extends QuickPickItem {
id: string;
}

const integrationTypeLabels: Record<ConfigurableDatabaseIntegrationType, string> = {
alloydb: l10n.t('AlloyDB'),
athena: l10n.t('Amazon Athena'),
'big-query': l10n.t('BigQuery'),
clickhouse: l10n.t('ClickHouse'),
databricks: l10n.t('Databricks'),
dremio: l10n.t('Dremio'),
mariadb: l10n.t('MariaDB'),
materialize: l10n.t('Materialize'),
mindsdb: l10n.t('MindsDB'),
mongodb: l10n.t('MongoDB'),
mysql: l10n.t('MySQL'),
pgsql: l10n.t('PostgreSQL'),
redshift: l10n.t('Amazon Redshift'),
snowflake: l10n.t('Snowflake'),
spanner: l10n.t('Google Cloud Spanner'),
'sql-server': l10n.t('SQL Server'),
trino: l10n.t('Trino')
};

/**
* Provides status bar items for SQL cells showing the integration name and variable name
*/
Expand Down Expand Up @@ -354,7 +374,7 @@ export class SqlCellStatusBarProvider implements NotebookCellStatusBarItemProvid

const typeLabel =
integrationType && (databaseIntegrationTypes as readonly string[]).includes(integrationType)
? this.getIntegrationTypeLabel(integrationType)
? integrationTypeLabels[integrationType] ?? integrationType
: projectIntegration.type;

const item: LocalQuickPickItem = {
Expand Down Expand Up @@ -437,45 +457,4 @@ export class SqlCellStatusBarProvider implements NotebookCellStatusBarItemProvid
// Trigger status bar update
this._onDidChangeCellStatusBarItems.fire();
}

private getIntegrationTypeLabel(type: ConfigurableDatabaseIntegrationType): string {
switch (type) {
case 'alloydb':
return l10n.t('AlloyDB');
case 'athena':
return l10n.t('Amazon Athena');
case 'big-query':
return l10n.t('BigQuery');
case 'clickhouse':
return l10n.t('ClickHouse');
case 'databricks':
return l10n.t('Databricks');
case 'dremio':
return l10n.t('Dremio');
case 'mariadb':
return l10n.t('MariaDB');
case 'materialize':
return l10n.t('Materialize');
case 'mindsdb':
return l10n.t('MindsDB');
case 'mongodb':
return l10n.t('MongoDB');
case 'mysql':
return l10n.t('MySQL');
case 'pgsql':
return l10n.t('PostgreSQL');
case 'redshift':
return l10n.t('Amazon Redshift');
case 'snowflake':
return l10n.t('Snowflake');
case 'spanner':
return l10n.t('Google Cloud Spanner');
case 'sql-server':
return l10n.t('SQL Server');
case 'trino':
return l10n.t('Trino');
default:
return String(type);
}
}
}
9 changes: 9 additions & 0 deletions src/platform/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,15 +822,24 @@ export namespace Integrations {
export const configure = l10n.t('Configure');
export const reconfigure = l10n.t('Reconfigure');
export const reset = l10n.t('Reset');
export const deleteIntegration = l10n.t('Delete');
export const confirmResetTitle = l10n.t('Confirm Reset');
export const confirmResetMessage = l10n.t('Are you sure you want to reset this integration configuration?');
export const confirmResetDetails = l10n.t('This will remove the stored credentials. You can reconfigure it later.');
export const confirmDeleteTitle = l10n.t('Confirm Delete');
export const confirmDeleteMessage = l10n.t('Are you sure you want to permanently delete this integration?');
export const confirmDeleteDetails = l10n.t(
'This will permanently remove the integration from your project. This action cannot be undone.'
);
export const configureTitle = l10n.t('Configure Integration: {0}');
export const cancel = l10n.t('Cancel');
export const save = l10n.t('Save');
export const addNewIntegration = l10n.t('Add New Integration');
export const database = l10n.t('Database');
export const requiredField = l10n.t('*');
export const optionalField = l10n.t('(optional)');
export const unnamedIntegration = (id: string) => l10n.t('Unnamed Integration ({0})', id);
export const defaultName = (type: string) => l10n.t('My {0} integration', type);
export const unsupportedIntegrationType = (type: string) => l10n.t('Unsupported integration type: {0}', type);

// Integration type labels
Expand Down
7 changes: 3 additions & 4 deletions src/webviews/webview-side/integrations/AlloyDBForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';
import { format, getLocString } from '../react-common/locReactSide';
import { getLocString } from '../react-common/locReactSide';
import { DatabaseIntegrationConfig } from '@deepnote/database-integrations';
import { SshOptionsFields } from './SshOptionsFields';
import { CaCertificateFields } from './CaCertificateFields';
import { getDefaultIntegrationName } from './integrationUtils';

export interface IAlloyDBFormProps {
integrationId: string;
Expand All @@ -16,11 +17,9 @@ function createEmptyAlloyDBConfig(params: {
id: string;
name?: string;
}): Extract<DatabaseIntegrationConfig, { type: 'alloydb' }> {
const unnamedIntegration = getLocString('integrationsUnnamedIntegration', 'Unnamed Integration ({0})');

return {
id: params.id,
name: (params.name || format(unnamedIntegration, params.id)).trim(),
name: (params.name || getDefaultIntegrationName('alloydb')).trim(),
type: 'alloydb',
metadata: {
host: '',
Expand Down
7 changes: 3 additions & 4 deletions src/webviews/webview-side/integrations/AthenaForm.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import * as React from 'react';
import { format, getLocString } from '../react-common/locReactSide';
import { getLocString } from '../react-common/locReactSide';
import { DatabaseIntegrationConfig } from '@deepnote/database-integrations';
import { getDefaultIntegrationName } from './integrationUtils';

function createEmptyAthenaConfig(params: {
id: string;
name?: string;
}): Extract<DatabaseIntegrationConfig, { type: 'athena' }> {
const unnamedIntegration = getLocString('integrationsUnnamedIntegration', 'Unnamed Integration ({0})');

return {
id: params.id,
name: (params.name || format(unnamedIntegration, params.id)).trim(),
name: (params.name || getDefaultIntegrationName('athena')).trim(),
type: 'athena',
metadata: {
access_key_id: '',
Expand Down
5 changes: 2 additions & 3 deletions src/webviews/webview-side/integrations/BigQueryForm.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import * as React from 'react';
import { format, getLocString } from '../react-common/locReactSide';
import { BigQueryAuthMethods, DatabaseIntegrationConfig } from '@deepnote/database-integrations';
import { getDefaultIntegrationName } from './integrationUtils';

type BigQueryConfig = Extract<DatabaseIntegrationConfig, { type: 'big-query' }>;

function createEmptyBigQueryConfig(params: { id: string; name?: string }): BigQueryConfig {
const unnamedIntegration = getLocString('integrationsUnnamedIntegration', 'Unnamed Integration ({0})');

return {
id: params.id,
name: (params.name || format(unnamedIntegration, params.id)).trim(),
name: (params.name || getDefaultIntegrationName('big-query')).trim(),
type: 'big-query',
metadata: {
authMethod: BigQueryAuthMethods.ServiceAccount,
Expand Down
7 changes: 3 additions & 4 deletions src/webviews/webview-side/integrations/ClickHouseForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';
import { format, getLocString } from '../react-common/locReactSide';
import { getLocString } from '../react-common/locReactSide';
import { DatabaseIntegrationConfig } from '@deepnote/database-integrations';
import { SshOptionsFields } from './SshOptionsFields';
import { CaCertificateFields } from './CaCertificateFields';
import { getDefaultIntegrationName } from './integrationUtils';

export interface IClickHouseFormProps {
integrationId: string;
Expand All @@ -16,11 +17,9 @@ function createEmptyClickHouseConfig(params: {
id: string;
name?: string;
}): Extract<DatabaseIntegrationConfig, { type: 'clickhouse' }> {
const unnamedIntegration = getLocString('integrationsUnnamedIntegration', 'Unnamed Integration ({0})');

return {
id: params.id,
name: (params.name || format(unnamedIntegration, params.id)).trim(),
name: (params.name || getDefaultIntegrationName('clickhouse')).trim(),
type: 'clickhouse',
metadata: {
host: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { SpannerForm } from './SpannerForm';
import { SQLServerForm } from './SQLServerForm';
import { TrinoForm } from './TrinoForm';
import { ConfigurableDatabaseIntegrationConfig, ConfigurableDatabaseIntegrationType } from './types';
import { integrationTypeLabels } from './integrationUtils';

export interface IConfigurationFormProps {
integrationId: string;
Expand All @@ -36,10 +37,8 @@ export const ConfigurationForm: React.FC<IConfigurationFormProps> = ({
onSave,
onCancel
}) => {
const title = getLocString('integrationsConfigureTitle', 'Configure Integration: {0}').replace(
'{0}',
integrationId
);
const typeLabel = integrationTypeLabels[integrationType] || integrationType;
const title = getLocString('integrationsConfigureTitle', '{0} integration').replace('{0}', typeLabel);

return (
<div className="configuration-form-overlay">
Expand Down
7 changes: 3 additions & 4 deletions src/webviews/webview-side/integrations/DatabricksForm.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import * as React from 'react';
import { format, getLocString } from '../react-common/locReactSide';
import { getLocString } from '../react-common/locReactSide';
import { DatabaseIntegrationConfig } from '@deepnote/database-integrations';
import { SshOptionsFields } from './SshOptionsFields';
import { getDefaultIntegrationName } from './integrationUtils';

function createEmptyDatabricksConfig(params: {
id: string;
name?: string;
}): Extract<DatabaseIntegrationConfig, { type: 'databricks' }> {
const unnamedIntegration = getLocString('integrationsUnnamedIntegration', 'Unnamed Integration ({0})');

return {
id: params.id,
name: (params.name || format(unnamedIntegration, params.id)).trim(),
name: (params.name || getDefaultIntegrationName('databricks')).trim(),
type: 'databricks',
metadata: {
host: '',
Expand Down
7 changes: 3 additions & 4 deletions src/webviews/webview-side/integrations/DremioForm.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import * as React from 'react';
import { format, getLocString } from '../react-common/locReactSide';
import { getLocString } from '../react-common/locReactSide';
import { DatabaseIntegrationConfig } from '@deepnote/database-integrations';
import { SshOptionsFields } from './SshOptionsFields';
import { getDefaultIntegrationName } from './integrationUtils';

function createEmptyDremioConfig(params: {
id: string;
name?: string;
}): Extract<DatabaseIntegrationConfig, { type: 'dremio' }> {
const unnamedIntegration = getLocString('integrationsUnnamedIntegration', 'Unnamed Integration ({0})');

return {
id: params.id,
name: (params.name || format(unnamedIntegration, params.id)).trim(),
name: (params.name || getDefaultIntegrationName('dremio')).trim(),
type: 'dremio',
metadata: {
host: '',
Expand Down
16 changes: 14 additions & 2 deletions src/webviews/webview-side/integrations/IntegrationItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ConfigurableDatabaseIntegrationType, IntegrationWithStatus } from './ty
export interface IIntegrationItemProps {
integration: IntegrationWithStatus;
onConfigure: (integrationId: string) => void;
onReset: (integrationId: string) => void;
onDelete: (integrationId: string) => void;
}

Expand Down Expand Up @@ -49,7 +50,7 @@ const getIntegrationTypeLabel = (type: ConfigurableDatabaseIntegrationType): str
}
};

export const IntegrationItem: React.FC<IIntegrationItemProps> = ({ integration, onConfigure, onDelete }) => {
export const IntegrationItem: React.FC<IIntegrationItemProps> = ({ integration, onConfigure, onReset, onDelete }) => {
const statusClass = integration.status === 'connected' ? 'status-connected' : 'status-disconnected';
const statusText =
integration.status === 'connected'
Expand Down Expand Up @@ -79,10 +80,21 @@ export const IntegrationItem: React.FC<IIntegrationItemProps> = ({ integration,
{configureText}
</button>
{integration.config && (
<button type="button" className="secondary" onClick={() => onDelete(integration.id)}>
<button type="button" className="secondary" onClick={() => onReset(integration.id)}>
{getLocString('integrationsReset', 'Reset')}
</button>
)}
{integration.config && (
<button
type="button"
className="icon-button"
onClick={() => onDelete(integration.id)}
title={getLocString('integrationsDelete', 'Delete')}
aria-label={getLocString('integrationsDelete', 'Delete')}
>
<span className="codicon codicon-trash" />
</button>
)}
</div>
</div>
);
Expand Down
Loading
Loading