mirror of
https://github.com/enso-org/enso.git
synced 2024-11-21 16:36:59 +03:00
Merge branch 'develop' into wip/sergeigarin/increase-retries
This commit is contained in:
commit
c29198eb02
@ -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
|
||||
|
||||
|
@ -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],
|
||||
},
|
||||
|
@ -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
|
||||
},
|
||||
},
|
||||
|
@ -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(),
|
@ -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,11 +53,7 @@ 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')
|
||||
}
|
||||
else return Err('Ast is not convertible to AGGrid value')
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user