Merge branch 'develop' into wip/sergeigarin/increase-retries

This commit is contained in:
mergify[bot] 2024-11-21 12:19:23 +00:00 committed by GitHub
commit c29198eb02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 153 additions and 145 deletions

View File

@ -29,6 +29,9 @@
- ["Write" button in component menu allows to evaluate it separately from the
rest of the workflow][11523].
- [The documentation editor can now display tables][11564]
- [Table Input Widget is now matched for Table.input method instead of
Table.new. Values must be string literals, and their content is parsed to the
suitable type][11612].
[11151]: https://github.com/enso-org/enso/pull/11151
[11271]: https://github.com/enso-org/enso/pull/11271
@ -48,6 +51,7 @@
[11547]: https://github.com/enso-org/enso/pull/11547
[11523]: https://github.com/enso-org/enso/pull/11523
[11564]: https://github.com/enso-org/enso/pull/11564
[11612]: https://github.com/enso-org/enso/pull/11612
#### Enso Standard Library

View File

@ -113,22 +113,22 @@ export async function createTableNode(page: Page) {
// Adding `Table.new` component will display the widget
await locate.addNewNodeButton(page).click()
await expect(locate.componentBrowser(page)).toBeVisible()
await page.keyboard.type('Table.new')
await page.keyboard.type('Table.input')
// Wait for CB entry to appear; this way we're sure about node name (binding).
await expect(locate.componentBrowserSelectedEntry(page)).toHaveCount(1)
await expect(locate.componentBrowserSelectedEntry(page)).toHaveText('Table.new')
await expect(locate.componentBrowserSelectedEntry(page)).toHaveText('Table.input')
await page.keyboard.press('Enter')
const node = locate.graphNodeByBinding(page, 'table1')
await expect(node).toHaveCount(1)
await expect(node).toBeVisible()
await mockMethodCallInfo(
page,
{ binding: 'table1', expr: 'Table.new' },
{ binding: 'table1', expr: 'Table.input' },
{
methodPointer: {
module: 'Standard.Table.Table',
definedOnType: 'Standard.Table.Table.Table',
name: 'new',
name: 'input',
},
notAppliedArguments: [0],
},

View File

@ -3,10 +3,10 @@ import { WidgetInputIsSpecificMethodCall } from '@/components/GraphEditor/widget
import TableHeader from '@/components/GraphEditor/widgets/WidgetTableEditor/TableHeader.vue'
import {
CELLS_LIMIT,
tableNewCallMayBeHandled,
useTableNewArgument,
tableInputCallMayBeHandled,
useTableInputArgument,
type RowData,
} from '@/components/GraphEditor/widgets/WidgetTableEditor/tableNewArgument'
} from '@/components/GraphEditor/widgets/WidgetTableEditor/tableInputArgument'
import ResizeHandles from '@/components/ResizeHandles.vue'
import AgGridTableView from '@/components/shared/AgGridTableView.vue'
import { injectGraphNavigator } from '@/providers/graphNavigator'
@ -55,7 +55,7 @@ const config = computed(() => {
}
})
const { rowData, columnDefs, moveColumn, moveRow, pasteFromClipboard } = useTableNewArgument(
const { rowData, columnDefs, moveColumn, moveRow, pasteFromClipboard } = useTableInputArgument(
() => props.input,
graph,
suggestionDb.entries,
@ -235,12 +235,12 @@ export const widgetDefinition = defineWidget(
WidgetInputIsSpecificMethodCall({
module: 'Standard.Table.Table',
definedOnType: 'Standard.Table.Table.Table',
name: 'new',
name: 'input',
}),
{
priority: 999,
score: (props) => {
if (!tableNewCallMayBeHandled(props.input.value)) return Score.Mismatch
if (!tableInputCallMayBeHandled(props.input.value)) return Score.Mismatch
return Score.Perfect
},
},

View File

@ -4,9 +4,9 @@ import {
NEW_COLUMN_ID,
ROW_INDEX_HEADER,
RowData,
tableNewCallMayBeHandled,
useTableNewArgument,
} from '@/components/GraphEditor/widgets/WidgetTableEditor/tableNewArgument'
tableInputCallMayBeHandled,
useTableInputArgument,
} from '@/components/GraphEditor/widgets/WidgetTableEditor/tableInputArgument'
import { MenuItem } from '@/components/shared/AgGridTableView.vue'
import { WidgetInput } from '@/providers/widgetRegistry'
import { SuggestionDb } from '@/stores/suggestionDatabase'
@ -24,7 +24,7 @@ function suggestionDbWithNothing() {
}
function generateTableOfOnes(rows: number, cols: number) {
const code = `Table.new [${[...Array(cols).keys()].map((i) => `['Column #${i}', [${Array(rows).fill('1').join(',')}]]`).join(',')}]`
const code = `Table.input [${[...Array(cols).keys()].map((i) => `['Column #${i}', [${Array(rows).fill("'1'").join(',')}]]`).join(',')}]`
const ast = Ast.parseExpression(code)
assertDefined(ast)
return ast
@ -38,7 +38,7 @@ assert(CELLS_LIMIT_SQRT === Math.floor(CELLS_LIMIT_SQRT))
test.each([
{
code: 'Table.new [["a", [1, 2, 3]], ["b", [4, 5, "six"]], ["empty", [Nothing, Standard.Base.Nothing, Nothing]]]',
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', 'six']], ['empty', [Nothing, Standard.Base.Nothing, Nothing]]]",
expectedColumnDefs: [
expectedRowIndexColumnDef,
{ headerName: 'a' },
@ -47,34 +47,34 @@ test.each([
expectedNewColumnDef,
],
expectedRows: [
{ [ROW_INDEX_HEADER]: 0, a: 1, b: 4, empty: null, '': null },
{ [ROW_INDEX_HEADER]: 1, a: 2, b: 5, empty: null, '': null },
{ [ROW_INDEX_HEADER]: 2, a: 3, b: 'six', empty: null, '': null },
{ [ROW_INDEX_HEADER]: 0, a: '1', b: '4', empty: null, '': null },
{ [ROW_INDEX_HEADER]: 1, a: '2', b: '5', empty: null, '': null },
{ [ROW_INDEX_HEADER]: 2, a: '3', b: 'six', empty: null, '': null },
{ [ROW_INDEX_HEADER]: 3, a: null, b: null, empty: null, '': null },
],
},
{
code: 'Table.new []',
code: 'Table.input []',
expectedColumnDefs: [expectedRowIndexColumnDef, expectedNewColumnDef],
expectedRows: [{ [ROW_INDEX_HEADER]: 0, '': null }],
},
{
code: 'Table.new',
code: 'Table.input',
expectedColumnDefs: [expectedRowIndexColumnDef, expectedNewColumnDef],
expectedRows: [{ [ROW_INDEX_HEADER]: 0, '': null }],
},
{
code: 'Table.new _',
code: 'Table.input _',
expectedColumnDefs: [expectedRowIndexColumnDef, expectedNewColumnDef],
expectedRows: [{ [ROW_INDEX_HEADER]: 0, '': null }],
},
{
code: 'Table.new [["a", []]]',
code: 'Table.input [["a", []]]',
expectedColumnDefs: [expectedRowIndexColumnDef, { headerName: 'a' }, expectedNewColumnDef],
expectedRows: [{ [ROW_INDEX_HEADER]: 0, a: null, '': null }],
},
{
code: 'Table.new [["a", [1,,2]], ["b", [3, 4,]], ["c", [, 5, 6]], ["d", [,,]]]',
code: "Table.input [['a', ['1',,'2']], ['b', ['3', '4',]], ['c', [, '5', '6']], ['d', [,,]]]",
expectedColumnDefs: [
expectedRowIndexColumnDef,
{ headerName: 'a' },
@ -84,21 +84,21 @@ test.each([
expectedNewColumnDef,
],
expectedRows: [
{ [ROW_INDEX_HEADER]: 0, a: 1, b: 3, c: null, d: null, '': null },
{ [ROW_INDEX_HEADER]: 1, a: null, b: 4, c: 5, d: null, '': null },
{ [ROW_INDEX_HEADER]: 2, a: 2, b: null, c: 6, d: null, '': null },
{ [ROW_INDEX_HEADER]: 0, a: '1', b: '3', c: null, d: null, '': null },
{ [ROW_INDEX_HEADER]: 1, a: null, b: '4', c: '5', d: null, '': null },
{ [ROW_INDEX_HEADER]: 2, a: '2', b: null, c: '6', d: null, '': null },
{ [ROW_INDEX_HEADER]: 3, a: null, b: null, c: null, d: null, '': null },
],
},
])('Read table from $code', ({ code, expectedColumnDefs, expectedRows }) => {
const ast = Ast.parseExpression(code)
assertDefined(ast)
expect(tableNewCallMayBeHandled(ast)).toBeTruthy()
expect(tableInputCallMayBeHandled(ast)).toBeTruthy()
const input = WidgetInput.FromAst(ast)
const startEdit = vi.fn()
const addMissingImports = vi.fn()
const onUpdate = vi.fn()
const tableNewArgs = useTableNewArgument(
const tableNewArgs = useTableInputArgument(
input,
{ startEdit, addMissingImports },
suggestionDbWithNothing(),
@ -160,7 +160,7 @@ test.each([
'Allowed actions in table near limit (rows: $rows, cols: $cols)',
({ rows, cols, expectNewRowEnabled, expectNewColEnabled }) => {
const input = WidgetInput.FromAst(generateTableOfOnes(rows, cols))
const tableNewArgs = useTableNewArgument(
const tableNewArgs = useTableInputArgument(
input,
{ startEdit: vi.fn(), addMissingImports: vi.fn() },
suggestionDbWithNothing(),
@ -174,16 +174,17 @@ test.each([
)
test.each([
'Table.new 14',
'Table.new array1',
"Table.new ['a', [123]]",
"Table.new [['a', [123]], ['b', [124], []]]",
"Table.new [['a', [123]], ['a'.repeat 170, [123]]]",
"Table.new [['a', [1, 2, 3, 3 + 1]]]",
'Table.input 14',
'Table.input array1',
"Table.input ['a', ['123']]",
"Table.input [['a', [123]]]",
"Table.input [['a', ['123']], ['b', ['124'], []]]",
"Table.input [['a', ['123']], ['a'.repeat 170, ['123']]]",
"Table.input [['a', ['1', '2', '3', 3 + 1]]]",
])('"%s" is not valid input for Table Editor Widget', (code) => {
const ast = Ast.parseExpression(code)
assertDefined(ast)
expect(tableNewCallMayBeHandled(ast)).toBeFalsy()
expect(tableInputCallMayBeHandled(ast)).toBeFalsy()
})
function tableEditFixture(code: string, expectedCode: string) {
@ -207,7 +208,7 @@ function tableEditFixture(code: string, expectedCode: string) {
},
])
})
const tableNewArgs = useTableNewArgument(
const tableNewArgs = useTableInputArgument(
input,
{ startEdit, addMissingImports },
suggestionDbWithNothing(),
@ -223,62 +224,56 @@ function tableEditFixture(code: string, expectedCode: string) {
test.each([
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
description: 'Edit number',
edit: { column: 1, row: 1, value: -22 },
expected: "Table.new [['a', [1, -22, 3]], ['b', [4, 5, 6]]]",
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
description: 'Edit string',
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
description: 'Edit value',
edit: { column: 1, row: 1, value: 'two' },
expected: "Table.new [['a', [1, 'two', 3]], ['b', [4, 5, 6]]]",
expected: "Table.input [['a', ['1', 'two', '3']], ['b', ['4', '5', '6']]]",
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
description: 'Put blank value',
edit: { column: 2, row: 1, value: '' },
expected: "Table.new [['a', [1, 2, 3]], ['b', [4, Nothing, 6]]]",
expected: "Table.input [['a', ['1', '2', '3']], ['b', ['4', Nothing, '6']]]",
importExpected: true,
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
description: 'Add new row',
edit: { column: 1, row: 3, value: 4.5 },
expected: "Table.new [['a', [1, 2, 3, 4.5]], ['b', [4, 5, 6, Nothing]]]",
edit: { column: 1, row: 3, value: '4.5' },
expected: "Table.input [['a', ['1', '2', '3', '4.5']], ['b', ['4', '5', '6', Nothing]]]",
importExpected: true,
},
{
code: "Table.new [['a', []], ['b', []]]",
code: "Table.input [['a', []], ['b', []]]",
description: 'Add first row',
edit: { column: 2, row: 0, value: 'val' },
expected: "Table.new [['a', [Nothing]], ['b', ['val']]]",
expected: "Table.input [['a', [Nothing]], ['b', ['val']]]",
importExpected: true,
},
{
code: "Table.new [['a', [1, ,3]]]",
code: "Table.input [['a', ['1', ,'3']]]",
description: 'Set missing value',
edit: { column: 1, row: 1, value: 2 },
expected: "Table.new [['a', [1, 2 ,3]]]",
edit: { column: 1, row: 1, value: '2' },
expected: "Table.input [['a', ['1', '2' ,'3']]]",
},
{
code: "Table.new [['a', [, 2, 3]]]",
code: "Table.input [['a', [, '2', '3']]]",
description: 'Set missing value at first row',
edit: { column: 1, row: 0, value: 1 },
expected: "Table.new [['a', [1, 2, 3]]]",
edit: { column: 1, row: 0, value: '1' },
expected: "Table.input [['a', ['1', '2', '3']]]",
},
{
code: "Table.new [['a', [1, 2,]]]",
code: "Table.input [['a', ['1', '2',]]]",
description: 'Set missing value at last row',
edit: { column: 1, row: 2, value: 3 },
expected: "Table.new [['a', [1, 2, 3]]]",
edit: { column: 1, row: 2, value: '3' },
expected: "Table.input [['a', ['1', '2', '3']]]",
},
{
code: "Table.new [['a', [1, 2]], ['a', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['a', ['3', '4']]]",
description: 'Edit with duplicated column name',
edit: { column: 1, row: 1, value: 5 },
expected: "Table.new [['a', [1, 5]], ['a', [3, 4]]]",
edit: { column: 1, row: 1, value: '5' },
expected: "Table.input [['a', ['1', '5']], ['a', ['3', '4']]]",
},
])('Edit table $code: $description', ({ code, edit, expected, importExpected }) => {
const { tableNewArgs, onUpdate, addMissingImports } = tableEditFixture(code, expected)
@ -295,21 +290,21 @@ test.each([
test.each([
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
expected: `Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, Nothing, Nothing]]]`,
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
expected: `Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, Nothing, Nothing]]]`,
importExpected: true,
},
{
code: 'Table.new []',
expected: `Table.new [['${DEFAULT_COLUMN_PREFIX}1', []]]`,
code: 'Table.input []',
expected: `Table.input [['${DEFAULT_COLUMN_PREFIX}1', []]]`,
},
{
code: 'Table.new',
expected: `Table.new [['${DEFAULT_COLUMN_PREFIX}1', []]]`,
code: 'Table.input',
expected: `Table.input [['${DEFAULT_COLUMN_PREFIX}1', []]]`,
},
{
code: 'Table.new _',
expected: `Table.new [['${DEFAULT_COLUMN_PREFIX}1', []]]`,
code: 'Table.input _',
expected: `Table.input [['${DEFAULT_COLUMN_PREFIX}1', []]]`,
},
])('Add column to table $code', ({ code, expected, importExpected }) => {
const { tableNewArgs, onUpdate, addMissingImports } = tableEditFixture(code, expected)
@ -340,24 +335,24 @@ function getCustomMenuItemByName(
test.each([
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
removedRowIndex: 0,
expected: "Table.new [['a', [2, 3]], ['b', [5, 6]]]",
expected: "Table.input [['a', ['2', '3']], ['b', ['5', '6']]]",
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
removedRowIndex: 1,
expected: "Table.new [['a', [1, 3]], ['b', [4, 6]]]",
expected: "Table.input [['a', ['1', '3']], ['b', ['4', '6']]]",
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
removedRowIndex: 2,
expected: "Table.new [['a', [1, 2]], ['b', [4, 5]]]",
expected: "Table.input [['a', ['1', '2']], ['b', ['4', '5']]]",
},
{
code: "Table.new [['a', [1]], ['b', [4]]]",
code: "Table.input [['a', ['1']], ['b', ['4']]]",
removedRowIndex: 0,
expected: "Table.new [['a', []], ['b', []]]",
expected: "Table.input [['a', []], ['b', []]]",
},
])('Remove $removedRowIndex row in $code', ({ code, removedRowIndex, expected }) => {
const { tableNewArgs, onUpdate, addMissingImports, gridApi } = tableEditFixture(code, expected)
@ -376,24 +371,24 @@ test.each([
test.each([
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]], ['c', [5, 6]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']], ['c', ['5', '6']]]",
removedColIndex: 1,
expected: "Table.new [['b', [3, 4]], ['c', [5, 6]]]",
expected: "Table.input [['b', ['3', '4']], ['c', ['5', '6']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]], ['c', [5, 6]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']], ['c', ['5', '6']]]",
removedColIndex: 2,
expected: "Table.new [['a', [1, 2]], ['c', [5, 6]]]",
expected: "Table.input [['a', ['1', '2']], ['c', ['5', '6']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]], ['c', [5, 6]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']], ['c', ['5', '6']]]",
removedColIndex: 3,
expected: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
expected: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
},
{
code: "Table.new [['a', [1, 2]]]",
code: "Table.input [['a', ['1', '2']]]",
removedColIndex: 1,
expected: 'Table.new []',
expected: 'Table.input []',
},
])('Remove $removedColIndex column in $code', ({ code, removedColIndex, expected }) => {
const { tableNewArgs, onUpdate, addMissingImports, gridApi } = tableEditFixture(code, expected)
@ -414,16 +409,16 @@ test.each([
test.each([
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]], ['c', [5, 6]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']], ['c', ['5', '6']]]",
fromIndex: 1,
toIndex: 3,
expected: "Table.new [['b', [3, 4]], ['c', [5, 6]], ['a', [1, 2]]]",
expected: "Table.input [['b', ['3', '4']], ['c', ['5', '6']], ['a', ['1', '2']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]], ['c', [5, 6]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']], ['c', ['5', '6']]]",
fromIndex: 3,
toIndex: 2,
expected: "Table.new [['a', [1, 2]], ['c', [5, 6]], ['b', [3, 4]]]",
expected: "Table.input [['a', ['1', '2']], ['c', ['5', '6']], ['b', ['3', '4']]]",
},
])(
'Move column $fromIndex to $toIndex in table $code',
@ -439,22 +434,22 @@ test.each([
test.each([
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
fromIndex: 1,
toIndex: 2,
expected: "Table.new [['a', [1, 3, 2]], ['b', [4, 6, 5]]]",
expected: "Table.input [['a', ['1', '3', '2']], ['b', ['4', '6', '5']]]",
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
fromIndex: 2,
toIndex: 0,
expected: "Table.new [['a', [3, 1, 2]], ['b', [6, 4, 5]]]",
expected: "Table.input [['a', ['3', '1', '2']], ['b', ['6', '4', '5']]]",
},
{
code: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
code: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
fromIndex: 1,
toIndex: -1,
expected: "Table.new [['a', [1, 2, 3]], ['b', [4, 5, 6]]]",
expected: "Table.input [['a', ['1', '2', '3']], ['b', ['4', '5', '6']]]",
},
])('Move row $fromIndex to $toIndex in table $code', ({ code, fromIndex, toIndex, expected }) => {
const { tableNewArgs, onUpdate, addMissingImports } = tableEditFixture(code, expected)
@ -467,100 +462,100 @@ test.each([
test.each([
{
code: 'Table.new',
code: 'Table.input',
focused: { rowIndex: 0, colIndex: 1 },
data: [
['1', '3'],
['2', '4'],
],
expected: `Table.new [['${DEFAULT_COLUMN_PREFIX}1', [1, 2]], ['${DEFAULT_COLUMN_PREFIX}2', [3, 4]]]`,
expected: `Table.input [['${DEFAULT_COLUMN_PREFIX}1', ['1', '2']], ['${DEFAULT_COLUMN_PREFIX}2', ['3', '4']]]`,
},
{
code: 'Table.new []',
code: 'Table.input []',
focused: { rowIndex: 0, colIndex: 1 },
data: [
['1', '3'],
['2', '4'],
],
expected: `Table.new [['${DEFAULT_COLUMN_PREFIX}1', [1, 2]], ['${DEFAULT_COLUMN_PREFIX}2', [3, 4]]]`,
expected: `Table.input [['${DEFAULT_COLUMN_PREFIX}1', ['1', '2']], ['${DEFAULT_COLUMN_PREFIX}2', ['3', '4']]]`,
},
{
code: 'Table.new []',
code: 'Table.input []',
focused: { rowIndex: 0, colIndex: 1 },
data: [['a single cell']],
expected: `Table.new [['${DEFAULT_COLUMN_PREFIX}1', ['a single cell']]]`,
expected: `Table.input [['${DEFAULT_COLUMN_PREFIX}1', ['a single cell']]]`,
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 0, colIndex: 1 },
data: [['a single cell']],
expected: "Table.new [['a', ['a single cell', 2]], ['b', [3, 4]]]",
expected: "Table.input [['a', ['a single cell', '2']], ['b', ['3', '4']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 1, colIndex: 2 },
data: [['a single cell']],
expected: "Table.new [['a', [1, 2]], ['b', [3, 'a single cell']]]",
expected: "Table.input [['a', ['1', '2']], ['b', ['3', 'a single cell']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 2, colIndex: 2 },
data: [['a single cell']],
expected: "Table.new [['a', [1, 2, Nothing]], ['b', [3, 4, 'a single cell']]]",
expected: "Table.input [['a', ['1', '2', Nothing]], ['b', ['3', '4', 'a single cell']]]",
importExpected: true,
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 1, colIndex: 3 },
data: [['a single cell']],
expected: `Table.new [['a', [1, 2]], ['b', [3, 4]], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, 'a single cell']]]`,
expected: `Table.input [['a', ['1', '2']], ['b', ['3', '4']], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, 'a single cell']]]`,
importExpected: true,
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 0, colIndex: 1 },
data: [
['5', '7'],
['6', '8'],
],
expected: "Table.new [['a', [5, 6]], ['b', [7, 8]]]",
expected: "Table.input [['a', ['5', '6']], ['b', ['7', '8']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 1, colIndex: 1 },
data: [
['5', '7'],
['6', '8'],
],
expected: "Table.new [['a', [1, 5, 6]], ['b', [3, 7, 8]]]",
expected: "Table.input [['a', ['1', '5', '6']], ['b', ['3', '7', '8']]]",
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 0, colIndex: 2 },
data: [
['5', '7'],
['6', '8'],
],
expected: `Table.new [['a', [1, 2]], ['b', [5, 6]], ['${DEFAULT_COLUMN_PREFIX}3', [7, 8]]]`,
expected: `Table.input [['a', ['1', '2']], ['b', ['5', '6']], ['${DEFAULT_COLUMN_PREFIX}3', ['7', '8']]]`,
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 1, colIndex: 2 },
data: [
['5', '7'],
['6', '8'],
],
expected: `Table.new [['a', [1, 2, Nothing]], ['b', [3, 5, 6]], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, 7, 8]]]`,
expected: `Table.input [['a', ['1', '2', Nothing]], ['b', ['3', '5', '6']], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, '7', '8']]]`,
importExpected: true,
},
{
code: "Table.new [['a', [1, 2]], ['b', [3, 4]]]",
code: "Table.input [['a', ['1', '2']], ['b', ['3', '4']]]",
focused: { rowIndex: 2, colIndex: 2 },
data: [
['5', '7'],
['6', '8'],
],
expected: `Table.new [['a', [1, 2, Nothing, Nothing]], ['b', [3, 4, 5, 6]], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, Nothing, 7, 8]]]`,
expected: `Table.input [['a', ['1', '2', Nothing, Nothing]], ['b', ['3', '4', '5', '6']], ['${DEFAULT_COLUMN_PREFIX}3', [Nothing, Nothing, '7', '8']]]`,
importExpected: true,
},
])(
@ -593,12 +588,13 @@ test('Pasted data which would exceed cells limit is truncated', () => {
let cellCount = 0
inputAst.visitRecursive((ast: Ast.Ast | Ast.Token) => {
if (ast instanceof Ast.Token) return
if (ast instanceof Ast.NumericLiteral || ast.code() === 'Nothing') cellCount++
if (ast instanceof Ast.TextLiteral && ast.code().startsWith("'Column #")) return
if (ast instanceof Ast.TextLiteral || ast.code() === 'Nothing') cellCount++
})
expect(cellCount).toBe(CELLS_LIMIT)
})
const addMissingImports = vi.fn()
const tableNewArgs = useTableNewArgument(
const tableNewArgs = useTableInputArgument(
input,
{ startEdit, addMissingImports },
suggestionDbWithNothing(),

View File

@ -4,7 +4,6 @@ import { type RequiredImport, requiredImportsByFQN } from '@/stores/graph/import
import type { SuggestionDb } from '@/stores/suggestionDatabase'
import { assert } from '@/util/assert'
import { Ast } from '@/util/ast'
import { tryEnsoToNumber, tryNumberToEnso } from '@/util/ast/abstract'
import { findIndexOpt } from '@/util/data/array'
import { Err, Ok, type Result, transposeResult, unwrapOrWithLog } from '@/util/data/result'
import { qnLastSegment, type QualifiedName } from '@/util/qualifiedName'
@ -41,7 +40,7 @@ export type RowData = {
*/
export interface ColumnDef extends ColDef<RowData> {
valueGetter: ({ data }: { data: RowData | undefined }) => any
valueSetter?: ({ data, newValue }: { data: RowData; newValue: any }) => boolean
valueSetter?: ({ data, newValue }: { data: RowData; newValue: string }) => boolean
mainMenuItems: (string | MenuItem<RowData>)[]
contextMenuItems: (string | MenuItem<RowData>)[]
rowDrag?: ({ data }: { data: RowData | undefined }) => boolean
@ -54,12 +53,8 @@ namespace cellValueConversion {
if (ast instanceof Ast.TextLiteral) return Ok(ast.rawTextContent)
else if (ast instanceof Ast.Ident && ast.code() === NOTHING_NAME) return Ok(null)
else if (ast instanceof Ast.PropertyAccess && ast.rhs.code() === NOTHING_NAME) return Ok(null)
else {
const asNumber = tryEnsoToNumber(ast)
if (asNumber != null) return Ok(asNumber)
else return Err('Ast is not convertible to AGGrid value')
}
}
/**
* Convert value of Grid cell (received, for example, from valueSetter) to AST module.
@ -72,16 +67,9 @@ namespace cellValueConversion {
): { ast: Ast.Owned<Ast.MutableExpression>; requireNothingImport: boolean } {
if (value == null || value === '') {
return { ast: Ast.Ident.new(module, 'Nothing' as Ast.Identifier), requireNothingImport: true }
} else if (typeof value === 'number') {
return {
ast: tryNumberToEnso(value, module) ?? Ast.TextLiteral.new(`${value}`, module),
requireNothingImport: false,
}
} else {
return {
ast:
Ast.NumericLiteral.tryParseWithSign(`${value}`, module) ??
Ast.TextLiteral.new(`${value}`, module),
ast: Ast.TextLiteral.new(`${value}`, module),
requireNothingImport: false,
}
}
@ -92,7 +80,7 @@ function retrieveColumnsAst(call: Ast.Expression): Result<Ast.Vector | undefined
if (!(call instanceof Ast.App)) return Ok(undefined)
if (call.argument instanceof Ast.Vector) return Ok(call.argument)
if (call.argument instanceof Ast.Wildcard) return Ok(undefined)
return Err('Expected Table.new argument to be a vector of columns or placeholder')
return Err('Expected Table.input argument to be a vector of columns or placeholder')
}
function readColumn(
@ -121,11 +109,11 @@ function retrieveColumnsDefinitions(columnsAst: Ast.Vector) {
}
/**
* Check if given ast is a `Table.new` call which may be handled by the TableEditorWidget.
* Check if given ast is a `Table.input` call which may be handled by the TableEditorWidget.
*
* This widget may handle table definitions filled with literals or `Nothing` values.
*/
export function tableNewCallMayBeHandled(call: Ast.Expression) {
export function tableInputCallMayBeHandled(call: Ast.Expression) {
const columnsAst = retrieveColumnsAst(call)
if (!columnsAst.ok) return false
if (!columnsAst.value) return true // We can handle lack of the argument
@ -140,13 +128,13 @@ export function tableNewCallMayBeHandled(call: Ast.Expression) {
}
/**
* A composable responsible for interpreting `Table.new` expressions, creating AGGrid column
* A composable responsible for interpreting `Table.input` expressions, creating AGGrid column
* definitions allowing also editing AST through AGGrid editing.
* @param input the widget's input
* @param graph the graph store
* @param onUpdate callback called when AGGrid was edited by user, resulting in AST change.
*/
export function useTableNewArgument(
export function useTableInputArgument(
input: ToValue<WidgetInput & { value: Ast.Expression }>,
graph: {
startEdit(): Ast.MutableModule

View File

@ -1047,6 +1047,26 @@
"documentation": "",
"annotations": []
},
{
"type": "method",
"module": "Standard.Table.Table",
"name": "input",
"arguments": [
{
"name": "columns",
"reprType": "Standard.Base.Data.Vector.Vector Standard.Base.Data.Vector.Vector | Standard.Table.Column.Column",
"isSuspended": false,
"hasDefault": false,
"defaultValue": null,
"tagValues": null
}
],
"selfType": "Standard.Table.Table.Table",
"returnType": "Standard.Table.Table.Table",
"isStatic": true,
"documentation": "",
"annotations": []
},
{
"type": "method",
"module": "Standard.Table.Table",