Skip to content

Commit

Permalink
Use a text editor to render connection code when resuming connections (
Browse files Browse the repository at this point in the history
  • Loading branch information
dfalbel authored Nov 22, 2024
1 parent 8d0c666 commit 042946e
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

import React, { PropsWithChildren } from 'react';
import React, { PropsWithChildren, useEffect, useRef } from 'react';
import { localize } from 'vs/nls';
import { ContentArea } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/contentArea';
import { PositronModalDialog } from 'vs/workbench/browser/positronComponents/positronModalDialog/positronModalDialog';
Expand All @@ -12,6 +12,10 @@ import { PositronConnectionsServices } from 'vs/workbench/contrib/positronConnec
import { PositronButton } from 'vs/base/browser/ui/positronComponents/button/positronButton';
import 'vs/css!./resumeConnectionModalDialog';
import Severity from 'vs/base/common/severity';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/codeEditorWidget';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
import { Emitter } from 'vs/base/common/event';

const RESUME_CONNECTION_MODAL_DIALOG_WIDTH = 700;
const RESUME_CONNECTION_MODAL_DIALOG_HEIGHT = 430;
Expand All @@ -25,7 +29,7 @@ export const showResumeConnectionModalDialog = (
const renderer = new PositronModalReactRenderer({
keybindingService: services.keybindingService,
layoutService: services.layoutService,
container: services.layoutService.activeContainer
container: services.layoutService.activeContainer,
});

renderer.render(
Expand All @@ -48,20 +52,58 @@ interface ResumeConnectionModalDialogProps {
const ResumeConnectionModalDialog = (props: PropsWithChildren<ResumeConnectionModalDialogProps>) => {

const { services, activeInstaceId } = props;
const activeInstace = services.connectionsService.getConnections().find(item => item.id === activeInstaceId);

if (!activeInstace) {
const activeInstance = services.connectionsService.getConnections().find(item => item.id === activeInstaceId);

const editorContainerRef = useRef<HTMLDivElement>(undefined!);
const editorRef = useRef<CodeEditorWidget>(undefined!);

const code = activeInstance?.metadata.code;
const language_id = activeInstance?.metadata.language_id;

useEffect(() => {
const disposableStore = new DisposableStore();
const editor = disposableStore.add(services.instantiationService.createInstance(
CodeEditorWidget,
editorContainerRef.current,
{
...getSimpleEditorOptions(services.configurationService),
readOnly: true,
domReadOnly: true,
cursorBlinking: 'solid',
},
getSimpleCodeEditorWidgetOptions()
));

const emitter = disposableStore.add(new Emitter<string>);
const inputModel = disposableStore.add(services.modelService.createModel(
code || '',
{ languageId: language_id || '', onDidChange: emitter.event },
undefined,
true
));

editor.setModel(inputModel);
editorRef.current = editor;

return () => {
disposableStore.dispose();
};
},
[
code, language_id,
services.instantiationService,
services.configurationService,
editorContainerRef,
services.modelService,
]);

if (!activeInstance) {
// This should never happen.
return null;
}

const code = activeInstace.metadata.code;

const copyHandler = async () => {
if (!code) {
// The button is disabled when no code is available.
return;
}
const code = editorRef.current?.getValue() || '';
await services.clipboardService.writeText(code);
props.renderer.dispose();

Expand All @@ -74,36 +116,40 @@ const ResumeConnectionModalDialog = (props: PropsWithChildren<ResumeConnectionMo
};

const editHandler = async () => {
if (!code) {
const editor = editorRef.current;

if (!editor) {
return;
}

props.renderer.dispose();
await services.editorService.openEditor({
resource: undefined,
contents: code,
languageId: activeInstace.metadata.language_id
});
editor.focus();
editor.updateOptions({ readOnly: false, domReadOnly: false, cursorBlinking: 'blink' });
editor.setScrollTop(0);
};

const resumeHandler = async () => {
if (!activeInstace.connect) {
if (!activeInstance.connect) {
return;
}

// Acquire code before disposing of the renderer
const code = editorRef.current?.getValue();

props.renderer.dispose();
const handle = services.notificationService.notify({
message: localize(
'positron.resumeConnectionModalDialog.connecting',
"Connecting to data source ({0})...",
activeInstace.metadata.name
activeInstance.metadata.name
),
severity: Severity.Info
});

try {
await activeInstace.connect();
props.setActiveInstanceId(activeInstace.id);
// Set instance code to the latest value.
activeInstance.metadata.update({ code: code });
await activeInstance.connect();
props.setActiveInstanceId(activeInstance.id);
} catch (err) {
services.notificationService.error(err);
}
Expand All @@ -128,7 +174,7 @@ const ResumeConnectionModalDialog = (props: PropsWithChildren<ResumeConnectionMo
<div className='content'>
<div className='title'>{localize('positron.resumeConnectionModalDialog.code', "Connection Code")}</div>
<div className='code'>
<code>{code}</code>
<div style={{ height: '100%' }} ref={editorContainerRef}></div>
</div>
<div className='buttons'>
<div className='top'>
Expand Down Expand Up @@ -160,7 +206,7 @@ const ResumeConnectionModalDialog = (props: PropsWithChildren<ResumeConnectionMo
<PositronButton
className='button action-bar-button default'
onPressed={resumeHandler}
disabled={!activeInstace.connect}
disabled={!activeInstance.connect}
>
{(() => localize('positron.resumeConnectionModalDialog.resume', "Resume Connection"))()}
</PositronButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

import React, { PropsWithChildren, createContext, useContext } from 'react';
import { IReactComponentContainer } from 'vs/base/browser/positronReactRenderer';
import { IModelService } from 'vs/editor/common/services/model';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { INotificationService } from 'vs/platform/notification/common/notification';
Expand All @@ -32,6 +34,8 @@ export interface PositronConnectionsServices {
readonly clipboardService: IClipboardService;
readonly notificationService: INotificationService;
readonly editorService: IEditorService;
readonly instantiationService: IInstantiationService;
readonly modelService: IModelService;
}

const PositronConnectionsContext = createContext<PositronConnectionsServices>(undefined!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IModelService } from 'vs/editor/common/services/model';

export class PositronConnectionsView
extends PositronViewPane
Expand Down Expand Up @@ -89,7 +90,8 @@ export class PositronConnectionsView
@ILayoutService private readonly layoutService: ILayoutService,
@IClipboardService private readonly clipboardService: IClipboardService,
@INotificationService private readonly notificationService: INotificationService,
@IEditorService private readonly editorService: IEditorService
@IEditorService private readonly editorService: IEditorService,
@IModelService private readonly modelService: IModelService
) {
super(
options,
Expand Down Expand Up @@ -148,6 +150,8 @@ export class PositronConnectionsView
clipboardService={this.clipboardService}
notificationService={this.notificationService}
editorService={this.editorService}
instantiationService={this.instantiationService}
modelService={this.modelService}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { Emitter, Event } from 'vs/base/common/event';
import { IPositronConnectionEntry } from 'vs/workbench/services/positronConnections/browser/positronConnectionsUtils';

export interface ConnectionMetadata {
export interface IConnectionMetadata {
name: string;
language_id: string;
host?: string;
Expand All @@ -15,6 +15,28 @@ export interface ConnectionMetadata {
icon?: string;
}

export class ConnectionMetadata implements IConnectionMetadata {
name: string;
language_id: string;
host?: string;
type?: string;
code?: string;
icon?: string;

constructor(metadata: IConnectionMetadata) {
this.name = metadata.name;
this.language_id = metadata.language_id;
this.code = metadata.code;
this.update(metadata);
}

update(values: Partial<IConnectionMetadata>): void {
console.log(values);
Object.assign(this, values);
console.log(this);
}
}

/***
* A Connection Instance represents the root of a connection to a data
* source. Children of a connection instance are tables, views, and other
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ConnectionsClientInstance } from 'vs/workbench/services/languageRuntime/common/languageRuntimeConnectionsClient';
import { ConnectionMetadata, IPositronConnectionInstance } from 'vs/workbench/services/positronConnections/browser/interfaces/positronConnectionsInstance';
import { ConnectionMetadata, IConnectionMetadata, IPositronConnectionInstance } from 'vs/workbench/services/positronConnections/browser/interfaces/positronConnectionsInstance';
import { IPositronConnectionsService, POSITRON_CONNECTIONS_VIEW_ID } from 'vs/workbench/services/positronConnections/browser/interfaces/positronConnectionsService';
import { DisconnectedPositronConnectionsInstance, PositronConnectionsInstance } from 'vs/workbench/services/positronConnections/browser/positronConnectionsInstance';
import { ILanguageRuntimeSession, IRuntimeSessionService, RuntimeClientType } from 'vs/workbench/services/runtimeSession/common/runtimeSessionService';
Expand Down Expand Up @@ -52,7 +52,7 @@ class PositronConnectionsService extends Disposable implements IPositronConnecti
this.attachRuntime(runtime);
}));

const storedConnections: ConnectionMetadata[] = JSON.parse(
const storedConnections: IConnectionMetadata[] = JSON.parse(
this.storageService.get('positron-connections', StorageScope.WORKSPACE, '[]')
);
storedConnections.forEach((metadata) => {
Expand All @@ -61,7 +61,7 @@ class PositronConnectionsService extends Disposable implements IPositronConnecti
}

const instance = new DisconnectedPositronConnectionsInstance(
metadata,
new ConnectionMetadata(metadata),
this.runtimeSessionService,
this
);
Expand Down Expand Up @@ -103,7 +103,7 @@ class PositronConnectionsService extends Disposable implements IPositronConnecti
}

const instance = await PositronConnectionsInstance.init(
message.data as ConnectionMetadata,
new ConnectionMetadata(message.data as IConnectionMetadata),
new ConnectionsClientInstance(client),
this
);
Expand All @@ -121,7 +121,7 @@ class PositronConnectionsService extends Disposable implements IPositronConnecti
const metadata = await connectionsClient.getMetadata();

const instance = await PositronConnectionsInstance.init(
metadata,
new ConnectionMetadata(metadata),
connectionsClient,
this
);
Expand Down

0 comments on commit 042946e

Please sign in to comment.