Skip to content

data explorer: create "Copy as Code" modal #8537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 66 commits into from
Jul 23, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
02a2c28
make action and button
isabelizimm Jul 2, 2025
dc9ef57
Merge branch 'main' into export-to-code
isabelizimm Jul 8, 2025
6f502e0
plumb through comms
isabelizimm Jul 9, 2025
dcf380b
export -> copy
isabelizimm Jul 10, 2025
32eb2c0
add modal on filter bar
isabelizimm Jul 11, 2025
f9a2c01
ui updates
isabelizimm Jul 14, 2025
2b9f962
make calls from modal
isabelizimm Jul 15, 2025
5083889
clean up comms
isabelizimm Jul 15, 2025
5be588b
clean up modal
isabelizimm Jul 15, 2025
d59fd66
linting for python
isabelizimm Jul 15, 2025
cc2d069
nit to modal
isabelizimm Jul 15, 2025
bae6ced
Merge branch 'export-as-code-comms' into copy-as-code-comms
isabelizimm Jul 15, 2025
1c0c11a
add modal into new branch
isabelizimm Jul 15, 2025
35a2114
update names and comments
isabelizimm Jul 15, 2025
4d624bc
updates from copilot
isabelizimm Jul 15, 2025
ac12c66
nit
isabelizimm Jul 15, 2025
0d6e7d9
cleanup
isabelizimm Jul 15, 2025
2e71d12
rename title creation
isabelizimm Jul 15, 2025
99e782f
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 15, 2025
c33df7c
updates from review
isabelizimm Jul 16, 2025
45cd402
guess syntax immediately
isabelizimm Jul 16, 2025
d75c201
updates from review
isabelizimm Jul 16, 2025
87ae32f
guess syntax immediately
isabelizimm Jul 16, 2025
5d9eaa5
rearrange with new updates
isabelizimm Jul 16, 2025
1adfc02
reorder guessing
isabelizimm Jul 16, 2025
7a0d40b
no undefined for guessing
isabelizimm Jul 16, 2025
47dc3e1
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 16, 2025
776a44e
cleanup modal
isabelizimm Jul 16, 2025
273b988
remove unused action id
isabelizimm Jul 16, 2025
9cbe02a
python lint
isabelizimm Jul 17, 2025
51893f0
Update positron/comms/data_explorer-backend-openrpc.json
isabelizimm Jul 17, 2025
9517202
rename, early exits
isabelizimm Jul 17, 2025
36bf5f5
use supported feature flag for syntaxes
isabelizimm Jul 17, 2025
da70e52
refactor
isabelizimm Jul 17, 2025
b6bbe5c
clean up comm names
isabelizimm Jul 17, 2025
6e5bcfc
Apply suggestions from code review
isabelizimm Jul 18, 2025
1525ad6
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 17, 2025
e85e6fe
fixes with comm updates
isabelizimm Jul 17, 2025
fbaf3cf
updates from review
isabelizimm Jul 18, 2025
50974b7
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 18, 2025
ccd15c4
updates from review
isabelizimm Jul 18, 2025
281ddac
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 18, 2025
b3aa955
updates to modal
isabelizimm Jul 18, 2025
0cc6f14
tweaks to runtime
isabelizimm Jul 18, 2025
744cc66
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 18, 2025
0c0ffac
Merge branch 'main' into copy-as-code-comms
isabelizimm Jul 18, 2025
a85ef9f
lint post merge from main
isabelizimm Jul 18, 2025
8806973
Merge branch 'copy-as-code-comms' into copy-as-code-modal
isabelizimm Jul 18, 2025
f8286a8
add feature flag for convert to code action
isabelizimm Jul 18, 2025
c108b91
clean up renderer
isabelizimm Jul 18, 2025
4f6c40a
rename files
isabelizimm Jul 18, 2025
38efe31
Update src/vs/workbench/browser/positronModalDialogs/convertToCodeMod…
isabelizimm Jul 21, 2025
7f394bd
Fix ESLint import warning
dhruvisompura Jul 19, 2025
28739b4
mark duckdb backends as unsupported
isabelizimm Jul 21, 2025
6115af3
clean up actions
isabelizimm Jul 21, 2025
4363bb7
always get code string
isabelizimm Jul 21, 2025
74027f9
only show for supported backends
isabelizimm Jul 21, 2025
e978ca5
Merge branch 'main' into copy-as-code-modal
isabelizimm Jul 21, 2025
781d7ae
Merge branch 'main' into copy-as-code-modal
isabelizimm Jul 22, 2025
3d01ba4
add precondition for syntaxes
isabelizimm Jul 23, 2025
2037e80
nit if no supported features
isabelizimm Jul 23, 2025
d8363e0
remove button if convertocode is missing
isabelizimm Jul 23, 2025
02c4686
remove unecessary services
isabelizimm Jul 23, 2025
ecb7bc1
updates from review
isabelizimm Jul 23, 2025
9b675eb
simplifying dropdown entry and onAccept
isabelizimm Jul 23, 2025
98de592
rearrange context key
isabelizimm Jul 23, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from .data_explorer_comm import (
ArraySelection,
BackendState,
CodeSyntaxFeatures,
CodeSyntaxName,
ColumnDisplayType,
ColumnFilter,
Expand All @@ -48,6 +47,7 @@
ColumnSummaryStats,
ColumnValue,
ConvertedCode,
ConvertToCodeFeatures,
ConvertToCodeRequest,
DataExplorerBackendMessageContent,
DataExplorerFrontendEvent,
Expand Down Expand Up @@ -84,7 +84,7 @@
SetRowFiltersFeatures,
SetRowFiltersParams,
SetSortColumnsFeatures,
SetSortColumnsRequest,
SetSortColumnsParams,
SuggestCodeSyntaxRequest,
SummaryStatsBoolean,
SummaryStatsDate,
Expand Down Expand Up @@ -292,10 +292,10 @@ def suggest_code_syntax(self, request: SuggestCodeSyntaxRequest):
def convert_to_code(self, request: ConvertToCodeRequest):
raise NotImplementedError

def search_schema(self, request: SearchSchemaRequest):
filters = request.params.filters
start_index = request.params.start_index
max_results = request.params.max_results
def search_schema(self, params: SearchSchemaParams):
filters = params.filters
start_index = params.start_index
max_results = params.max_results
if self._search_schema_last_result is not None:
last_filters, matches = self._search_schema_last_result
if last_filters != filters:
Expand Down Expand Up @@ -815,9 +815,12 @@ def _prof_histogram(
support_status=SupportStatus.Unsupported,
supported_formats=[],
),
code_syntaxes=CodeSyntaxFeatures(
convert_to_code=ConvertToCodeFeatures(
support_status=SupportStatus.Supported,
code_syntaxes=["pandas", "polars"],
code_syntaxes=[
CodeSyntaxName(code_syntax_name="pandas"),
CodeSyntaxName(code_syntax_name="polars"),
],
),
)

Expand Down Expand Up @@ -1936,8 +1939,9 @@ def _prof_histogram(
ExportFormat.Html,
],
),
code_syntaxes=CodeSyntaxFeatures(
support_status=SupportStatus.Supported, code_syntaxes=["pandas"]
convert_to_code=ConvertToCodeFeatures(
support_status=SupportStatus.Supported,
code_syntaxes=[CodeSyntaxName(code_syntax_name="pandas")],
),
)

Expand Down Expand Up @@ -2800,8 +2804,9 @@ def _prof_histogram(
supported_formats=[ExportFormat.Csv, ExportFormat.Tsv],
),
set_sort_columns=SetSortColumnsFeatures(support_status=SupportStatus.Supported),
code_syntaxes=CodeSyntaxFeatures(
support_status=SupportStatus.Supported, code_syntaxes=["polars"]
convert_to_code=ConvertToCodeFeatures(
support_status=SupportStatus.Supported,
code_syntaxes=[CodeSyntaxName(code_syntax_name="polars")],
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,17 @@ class ConvertedCode(BaseModel):
"""

converted_code: List[StrictStr] = Field(
description="Lines of code translating filters and sort keys",
description="Lines of code that implement filters and sort keys",
)


class CodeSyntaxName(BaseModel):
"""
Suggestion of syntax to use for code translation
Syntax to use for code conversion
"""

code_syntax_name: StrictStr = Field(
description="The syntax for converted code",
description="The name of the code syntax, eg, pandas, polars, dplyr, etc.",
)


Expand Down Expand Up @@ -992,8 +992,8 @@ class SupportedFeatures(BaseModel):
description="Support for 'export_data_selection' RPC and its features",
)

code_syntaxes: CodeSyntaxFeatures = Field(
description="Support for converting data selections to code",
convert_to_code: ConvertToCodeFeatures = Field(
description="Support for 'convert_to_code' RPC and its features",
)


Expand Down Expand Up @@ -1081,16 +1081,16 @@ class SetSortColumnsFeatures(BaseModel):
)


class CodeSyntaxFeatures(BaseModel):
class ConvertToCodeFeatures(BaseModel):
"""
A list of supported code syntax names for exporting data selections
Feature flags for convert to code RPC
"""

support_status: SupportStatus = Field(
description="The support status for this RPC method",
)

code_syntaxes: Optional[List[StrictStr]] = Field(
code_syntaxes: Optional[List[CodeSyntaxName]] = Field(
default=None,
description="The syntaxes for converted code",
)
Expand Down Expand Up @@ -1485,8 +1485,8 @@ class ConvertToCodeParams(BaseModel):
description="Zero or more sort keys to apply",
)

code_syntax_name: StrictStr = Field(
description="The code syntax to use for translation",
code_syntax_name: CodeSyntaxName = Field(
description="The code syntax to use for conversion",
)


Expand Down Expand Up @@ -1815,7 +1815,7 @@ class ReturnColumnProfilesParams(BaseModel):

SetSortColumnsFeatures.update_forward_refs()

CodeSyntaxFeatures.update_forward_refs()
ConvertToCodeFeatures.update_forward_refs()

TableSelection.update_forward_refs()

Expand Down
39 changes: 21 additions & 18 deletions positron/comms/data_explorer-backend-openrpc.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@
}
}
},
{
{
"name": "convert_to_code",
"summary": "Converts the current data view into a code snippet.",
"description": "Converts filters and sort keys as code in different syntaxes like pandas, polars, data.table, dplyr",
Expand Down Expand Up @@ -255,14 +255,14 @@
},
{
"name": "code_syntax_name",
"description": "The code syntax to use for translation",
"description": "The code syntax to use for conversion",
"required": true,
"schema": {
"type": "string",
"description": "The syntax for converted code"
"$ref": "#/components/schemas/code_syntax_name",
"description": "The name of the code syntax, eg, pandas, polars, dplyr, etc."
}
}
],
],
"result": {
"schema": {
"name": "converted_code",
Expand All @@ -274,7 +274,7 @@
"properties": {
"converted_code": {
"type": "array",
"description": "Lines of code translating filters and sort keys",
"description": "Lines of code that implement filters and sort keys",
"items": {
"type": "string"
}
Expand All @@ -283,7 +283,7 @@
}
}
},
{
{
"name": "suggest_code_syntax",
"summary": "Suggest code syntax for code conversion",
"description": "Suggest code syntax for code conversion based on the current backend state",
Expand All @@ -292,14 +292,14 @@
"schema": {
"name": "code_syntax_name",
"type": "object",
"description": "Suggestion of syntax to use for code translation",
"description": "Syntax to use for code conversion",
"required": [
"code_syntax_name"
],
"properties": {
"code_syntax_name": {
"type": "string",
"description": "The syntax for converted code"
"description": "The name of the code syntax, eg, pandas, polars, dplyr, etc."
}
}
}
Expand Down Expand Up @@ -1393,8 +1393,7 @@
"get_column_profiles",
"set_sort_columns",
"export_data_selection",
"export_as_code",
"code_syntaxes"
"convert_to_code"
],
"properties": {
"search_schema": {
Expand All @@ -1421,9 +1420,9 @@
"description": "Support for 'export_data_selection' RPC and its features",
"$ref": "#/components/schemas/export_data_selection_features"
},
"code_syntaxes": {
"description": "Support for converting data selections to code",
"$ref": "#/components/schemas/code_syntax_features"
"convert_to_code": {
"description": "Support for 'convert_to_code' RPC and its features",
"$ref": "#/components/schemas/convert_to_code_features"
}
}
},
Expand Down Expand Up @@ -1550,9 +1549,9 @@
}
}
},
"code_syntax_features": {
"convert_to_code_features": {
"type": "object",
"description": "A list of supported code syntax names for exporting data selections",
"description": "Feature flags for convert to code RPC",
"required": [
"support_status"
],
Expand All @@ -1565,12 +1564,16 @@
"type": "array",
"description": "The syntaxes for converted code",
"items": {
"type": "string",
"description": "The syntaxes for converted code"
"$ref": "#/components/schemas/code_syntax_name",
"description": "The name of the code syntax, eg, pandas, polars, dplyr, etc."
}
}
}
},
"code_syntax_name": {
"type": "string",
"description": "The name of the code syntax, eg, pandas, polars, dplyr, etc."
},
"table_selection": {
"type": "object",
"description": "A selection on the data grid, for copying to the clipboard or other actions",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import { ICommandService } from '../../../platform/commands/common/commands.js';
import { IKeybindingService } from '../../../platform/keybinding/common/keybinding.js';
import { IWorkbenchLayoutService } from '../../services/layout/browser/layoutService.js';
import { VerticalStack } from '../positronComponents/positronModalDialog/components/verticalStack.js';
import { PositronModalReactRenderer } from '../positronModalReactRenderer/positronModalReactRenderer.js';
import { OKCancelModalDialog } from '../positronComponents/positronModalDialog/positronOKCancelModalDialog.js';
import { IPositronDataExplorerInstance } from '../../services/positronDataExplorer/browser/interfaces/positronDataExplorerInstance.js';
import { PositronDataExplorerCommandId } from '../../contrib/positronDataExplorerEditor/browser/positronDataExplorerActions.js';
import { DropDownListBox } from '../positronComponents/dropDownListBox/dropDownListBox.js';
import { DropDownListBoxItem } from '../positronComponents/dropDownListBox/dropDownListBoxItem.js';
import { DropdownEntry } from './components/dropdownEntry.js';
import { CodeSyntaxName } from '../../services/languageRuntime/common/positronDataExplorerComm.js';
import { PositronModalReactRenderer } from '../../../base/browser/positronModalReactRenderer.js';

/**
* Shows the convert to code modal dialog.
Expand All @@ -35,11 +36,7 @@ export const showConvertToCodeModalDialog = async (
dataExplorerClientInstance: IPositronDataExplorerInstance,
): Promise<void> => {
// Create the renderer.
const renderer = new PositronModalReactRenderer({
keybindingService,
layoutService,
container: layoutService.activeContainer
});
const renderer = new PositronModalReactRenderer()

// Show the copy as code dialog.
renderer.render(
Expand All @@ -54,9 +51,9 @@ export const showConvertToCodeModalDialog = async (
};

/**
* CopyAsCodeDialogProps interface.
* ConvertToCodeDialogProps interface.
*/
interface CopyAsCodeDialogProps {
interface ConvertToCodeDialogProps {
commandService: ICommandService;
dataExplorerClientInstance: IPositronDataExplorerInstance
keybindingService: IKeybindingService;
Expand All @@ -66,23 +63,24 @@ interface CopyAsCodeDialogProps {


/**
* CopyAsCodeModalDialog component.
* ConvertToCodeModalDialog component.
* @param props The component properties.
* @returns The rendered component.
*/
export const ConvertToCodeModalDialog = (props: CopyAsCodeDialogProps) => {
export const ConvertToCodeModalDialog = (props: ConvertToCodeDialogProps) => {
// State hooks.
const instance = props.dataExplorerClientInstance.dataExplorerClientInstance;
const codeSyntaxOptions = instance.cachedBackendState?.supported_features?.code_syntaxes.code_syntaxes ?? [];
const codeSyntaxOptions = instance.cachedBackendState?.supported_features?.convert_to_code.code_syntaxes ?? [];

const [selectedSyntax, setSelectedSyntax] = useState<string>(
instance.suggestedSyntax?.code_syntax_name ?? localize('selectCodeSyntax', 'Select Code Syntax')
);
const [selectedSyntax, setSelectedSyntax] = useState<CodeSyntaxName | undefined>(instance.suggestedSyntax);

const [codeString, setCodeString] = useState<string | undefined>(undefined);

useEffect(() => {
const getCodeString = async () => {
if (!selectedSyntax) {
return;
}
// Execute the command to get the code string based on the selected syntax.
const codeString = await props.commandService.executeCommand(PositronDataExplorerCommandId.ConvertToCodeAction, selectedSyntax);
setCodeString(codeString);
Expand All @@ -96,23 +94,31 @@ export const ConvertToCodeModalDialog = (props: CopyAsCodeDialogProps) => {
};

const syntaxInfoToDropDownItems = (
syntaxes: string[]
): DropDownListBoxItem<string, string>[] => {
syntaxes: CodeSyntaxName[]
): DropDownListBoxItem<string, CodeSyntaxName>[] => {
return syntaxes.map(
(syntax) =>
new DropDownListBoxItem<string, string>({
identifier: syntax,
new DropDownListBoxItem<string, CodeSyntaxName>({
identifier: syntax.code_syntax_name,
value: syntax,
})
);
};

const onSelectionChanged = async (item: DropDownListBoxItem<string, string>) => {
const typedItem = item as DropDownListBoxItem<string, string>;
setSelectedSyntax(typedItem.options.identifier);
const syntaxDropdownTitle = (): string => {
// if selectedSyntax is an object with code_syntax_name, return that name
if (typeof selectedSyntax === 'object' && 'code_syntax_name' in selectedSyntax) {
return (selectedSyntax as CodeSyntaxName).code_syntax_name;
}
return localize('selectCodeSyntax', 'Select Code Syntax');
}

const onSelectionChanged = async (item: DropDownListBoxItem<string, CodeSyntaxName>) => {
const typedItem = item as DropDownListBoxItem<string, CodeSyntaxName>;
setSelectedSyntax(typedItem.options.value);

// Execute the command to get the code string based on the selected syntax.
const exc = await props.commandService.executeCommand(PositronDataExplorerCommandId.ConvertToCodeAction, typedItem.options.identifier)
const exc = await props.commandService.executeCommand(PositronDataExplorerCommandId.ConvertToCodeAction, typedItem.options.value);
setCodeString(exc);
};

Expand Down Expand Up @@ -140,9 +146,7 @@ export const ConvertToCodeModalDialog = (props: CopyAsCodeDialogProps) => {
/>
)}
entries={syntaxDropdownEntries()}
keybindingService={props.keybindingService}
layoutService={props.layoutService}
title={selectedSyntax}
title={syntaxDropdownTitle()}
onSelectionChanged={onSelectionChanged}
/>
<pre>
Expand Down
Loading