Skip to content

Commit

Permalink
Merge branch 'develop' into wip/sb/change-password-in-settings
Browse files Browse the repository at this point in the history
  • Loading branch information
PabloBuchu committed Feb 26, 2024
2 parents ba67c4d + 8f2b9da commit 66db667
Show file tree
Hide file tree
Showing 910 changed files with 15,552 additions and 6,529 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/formatting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

env:
# Please ensure that this is in sync with graalVersion in build.sbt
javaVersion: 21.0.1
javaVersion: 21.0.2
# Please ensure that this is in sync with project/build.properties
sbtVersion: 1.9.7

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,8 @@
- [Added `Table.to_xml`.][8979]
- [Implemented Write support for `S3_File`.][8921]
- [Separate `Group_By` from `columns` into new argument on `aggregate`.][9027]
- [Allow `copy_to` and `move_to` to work between local and S3 files.][9054]
- [Adjusted expression handling and new `Simple_Expression` type.][9128]

[debug-shortcuts]:
https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug
Expand Down Expand Up @@ -888,6 +890,8 @@
[8979]: https://github.com/enso-org/enso/pull/8979
[8921]: https://github.com/enso-org/enso/pull/8921
[9027]: https://github.com/enso-org/enso/pull/9027
[9054]: https://github.com/enso-org/enso/pull/9054
[9128]: https://github.com/enso-org/enso/pull/9128

#### Enso Compiler

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@ loadScript('https://cdnjs.cloudflare.com/ajax/libs/sql-formatter/4.0.2/sql-forma
* interpolated query parameters.
*/
class SqlVisualization extends Visualization {
// TODO Change the type below once #837 is done:
// 'Standard.Database.Data.Table.Table | Standard.Database.Data.DB_Column.DB_Column'
static inputType =
'Standard.Database.Data.Table.Table | Standard.Database.Data.DB_Column.DB_Column'
'Standard.Database.Data.DB_Table.DB_Table | Standard.Database.Data.DB_Column.DB_Column'
static label = 'SQL Query'

constructor(api) {
Expand Down
43 changes: 30 additions & 13 deletions app/gui2/e2e/collapsingAndEntering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,38 @@ test('Entering nodes', async ({ page }) => {
await actions.goToGraph(page)
await mockCollapsedFunctionInfo(page, 'final', 'func1')
await expectInsideMain(page)
await expect(locate.navBreadcrumb(page)).toHaveText(['main'])
await expect(locate.navBreadcrumb(page)).toHaveText(['Mock Project'])

await locate.graphNodeByBinding(page, 'final').dblclick()
await mockCollapsedFunctionInfo(page, 'f2', 'func2')
await expectInsideFunc1(page)
await expect(locate.navBreadcrumb(page)).toHaveText(['main', 'func1'])
await expect(locate.navBreadcrumb(page)).toHaveText(['Mock Project', 'func1'])

await locate.graphNodeByBinding(page, 'f2').dblclick()
await expectInsideFunc2(page)
await expect(locate.navBreadcrumb(page)).toHaveText(['main', 'func1', 'func2'])
await expect(locate.navBreadcrumb(page)).toHaveText(['Mock Project', 'func1', 'func2'])
})

test('Leaving entered nodes', async ({ page }) => {
await actions.goToGraph(page)
await enterToFunc2(page)

await locate.graphEditor(page).dblclick()
await page.mouse.dblclick(100, 100)
await expectInsideFunc1(page)

await locate.graphEditor(page).dblclick()
await page.mouse.dblclick(100, 100)
await expectInsideMain(page)
})

test('Using breadcrumbs to navigate', async ({ page }) => {
await actions.goToGraph(page)
await enterToFunc2(page)
await locate.graphEditor(page).dblclick()
await locate.graphEditor(page).dblclick()
await page.mouse.dblclick(100, 100)
await expectInsideFunc1(page)
await page.mouse.dblclick(100, 100)
await expectInsideMain(page)
// Breadcrumbs still have all the crumbs, but the last two are dimmed.
await expect(locate.navBreadcrumb(page)).toHaveText(['main', 'func1', 'func2'])
await expect(locate.navBreadcrumb(page)).toHaveText(['Mock Project', 'func1', 'func2'])
await expect(locate.navBreadcrumb(page, (f) => f.class('inactive'))).toHaveText([
'func1',
'func2',
Expand All @@ -49,7 +51,7 @@ test('Using breadcrumbs to navigate', async ({ page }) => {
await locate.navBreadcrumb(page).filter({ hasText: 'func2' }).click()
await expectInsideFunc2(page)

await locate.navBreadcrumb(page).filter({ hasText: 'main' }).click()
await locate.navBreadcrumb(page).filter({ hasText: 'Mock Project' }).click()
await expectInsideMain(page)

await locate.navBreadcrumb(page).filter({ hasText: 'func1' }).click()
Expand All @@ -61,9 +63,19 @@ test('Collapsing nodes', async ({ page }) => {
const initialNodesCount = await locate.graphNode(page).count()
await mockCollapsedFunctionInfo(page, 'final', 'func1')

await locate.graphNodeByBinding(page, 'ten').click({ modifiers: ['Shift'] })
await locate.graphNodeByBinding(page, 'sum').click({ modifiers: ['Shift'] })
await locate.graphNodeByBinding(page, 'prod').click({ modifiers: ['Shift'] })
// Widgets may "steal" clicks, so we always click at icon.
await locate
.graphNodeByBinding(page, 'ten')
.locator('.icon')
.click({ modifiers: ['Shift'] })
await locate
.graphNodeByBinding(page, 'sum')
.locator('.icon')
.click({ modifiers: ['Shift'] })
await locate
.graphNodeByBinding(page, 'prod')
.locator('.icon')
.click({ modifiers: ['Shift'] })

await page.keyboard.press(COLLAPSE_SHORTCUT)
await expect(locate.graphNode(page)).toHaveCount(initialNodesCount - 2)
Expand All @@ -77,7 +89,10 @@ test('Collapsing nodes', async ({ page }) => {
await customExpect.toExist(locate.graphNodeByBinding(page, 'sum'))
await customExpect.toExist(locate.graphNodeByBinding(page, 'prod'))

locate.graphNodeByBinding(page, 'ten').click({ modifiers: ['Shift'] })
locate
.graphNodeByBinding(page, 'ten')
.locator('.icon')
.click({ modifiers: ['Shift'] })
// Wait till node is selected.
await expect(locate.graphNodeByBinding(page, 'ten').and(page.locator('.selected'))).toHaveCount(1)
await page.keyboard.press(COLLAPSE_SHORTCUT)
Expand Down Expand Up @@ -118,6 +133,8 @@ async function expectInsideFunc2(page: Page) {
async function enterToFunc2(page: Page) {
await mockCollapsedFunctionInfo(page, 'final', 'func1')
await locate.graphNodeByBinding(page, 'final').dblclick()
await expectInsideFunc1(page)
await mockCollapsedFunctionInfo(page, 'f2', 'func2')
await locate.graphNodeByBinding(page, 'f2').dblclick()
await expectInsideFunc2(page)
}
33 changes: 33 additions & 0 deletions app/gui2/e2e/componentBrowser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,36 @@ test('Filtering list', async ({ page }) => {
const highlighted = locate.componentBrowserEntry(page).locator('.component-label-segment.match')
await expect(highlighted).toHaveText(['re', '_te'])
})

test('Editing existing nodes', async ({ page }) => {
await actions.goToGraph(page)
const node = locate.graphNodeByBinding(page, 'data')
const ADDED_PATH = '"/home/enso/Input.txt"'

// Start node editing
await locate.graphNodeIcon(node).click({ modifiers: ['Control'] })
await expect(locate.componentBrowser(page)).toBeVisible()
const input = locate.componentBrowserInput(page).locator('input')
await expect(input).toHaveValue('Data.read')

// Add argument and accept
await page.keyboard.press('End')
await input.pressSequentially(` ${ADDED_PATH}`)
await expect(input).toHaveValue(`Data.read ${ADDED_PATH}`)
await page.keyboard.press('Enter')
await expect(locate.componentBrowser(page)).not.toBeVisible()
await expect(node.locator('.WidgetToken')).toHaveText(['Data', '.', 'read'])
await expect(node.locator('.WidgetText input')).toHaveValue(ADDED_PATH)

// Edit again, using "edit" button
await locate.graphNodeIcon(node).click()
await node.getByTestId('edit-button').click()
await expect(locate.componentBrowser(page)).toBeVisible()
await expect(input).toHaveValue(`Data.read ${ADDED_PATH}`)
for (let i = 0; i < ADDED_PATH.length; ++i) await page.keyboard.press('Backspace')
await expect(input).toHaveValue('Data.read ')
await page.keyboard.press('Enter')
await expect(locate.componentBrowser(page)).not.toBeVisible()
await expect(node.locator('.WidgetToken')).toHaveText(['Data', '.', 'read'])
await expect(node.locator('.WidgetText')).not.toBeVisible()
})
6 changes: 3 additions & 3 deletions app/gui2/e2e/edgeInteractions.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { expect, Page, test } from '@playwright/test'
import { expect, test, type Page } from '@playwright/test'
import * as actions from './actions'
import { edgesToNodeWithBinding, graphNodeByBinding } from './locate'

Expand All @@ -22,7 +22,7 @@ test('Disconnect an edge from a port', async ({ page }) => {
await initGraph(page)
await expect(await edgesToNodeWithBinding(page, 'sum')).toHaveCount(2 * EDGE_PARTS)

const targetEdge = page.locator('path:nth-child(4)')
const targetEdge = page.locator('svg.behindNodes g:nth-child(2) path.edge.visible')

// Hover over edge to the right of node with binding `ten`.
await targetEdge.click({
Expand All @@ -41,7 +41,7 @@ test('Connect an node to a port via dragging the edge', async ({ page }) => {
await initGraph(page)

await expect(await edgesToNodeWithBinding(page, 'sum')).toHaveCount(2 * EDGE_PARTS)
const targetEdge = page.locator('path:nth-child(4)')
const targetEdge = page.locator('svg.behindNodes g:nth-child(2) path.edge.visible')
// Hover over edge to the left of node with binding `ten`.
await targetEdge.click({
position: { x: 450, y: 5.0 },
Expand Down
4 changes: 2 additions & 2 deletions app/gui2/e2e/edgeRendering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ test('Hover behaviour of edges', async ({ page }) => {
await expect(hoveredEdgeElements).toHaveCount(SPLIT_EDGE_PARTS)

// Expect the top edge part to be dimmed
const topEdge = page.locator('path:nth-child(3)')
const topEdge = page.locator('svg.behindNodes g:nth-child(2) path:nth-child(1)')
await expect(topEdge).toHaveClass('edge visible dimmed')
// Expect the bottom edge part not to be dimmed
const bottomEdge = page.locator('path:nth-child(5)')
const bottomEdge = page.locator('svg.behindNodes g:nth-child(2) path:nth-child(3)')
await expect(bottomEdge).toHaveClass('edge visible')
})
21 changes: 17 additions & 4 deletions app/gui2/e2e/locate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,23 @@ export function exitFullscreenButton(page: Locator | Page) {

export const toggleFullscreenButton = or(enterFullscreenButton, exitFullscreenButton)

// === Nodes ===

declare const nodeLocatorBrand: unique symbol
type Node = Locator & { [nodeLocatorBrand]: never }

export function graphNode(page: Page | Locator): Node {
return page.locator('.GraphNode') as Node
}
export function graphNodeByBinding(page: Locator | Page, binding: string): Node {
return graphNode(page).filter({
has: page.locator('.binding').and(page.getByText(binding)),
}) as Node
}
export function graphNodeIcon(node: Node) {
return node.locator('.icon')
}

// === Data locators ===

type SanitizeClassName<T extends string> = T extends `${infer A}.${infer B}`
Expand All @@ -128,10 +145,6 @@ function componentLocator<T extends string>(className: SanitizeClassName<T>) {
}

export const graphEditor = componentLocator('GraphEditor')
export const graphNode = componentLocator('GraphNode')
export function graphNodeByBinding(page: Locator | Page, binding: string) {
return graphNode(page).filter({ has: page.locator('.binding').and(page.getByText(binding)) })
}
// @ts-expect-error
export const anyVisualization = componentLocator('GraphVisualization > *')
export const circularMenu = componentLocator('CircularMenu')
Expand Down
2 changes: 1 addition & 1 deletion app/gui2/mock/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function projectStore() {
const mod = projectStore.projectModel.createNewModule('Main.enso')
mod.doc.ydoc.emit('load', [])
const syncModule = new Ast.MutableModule(mod.doc.ydoc)
mod.transact(() => {
syncModule.transact(() => {
const root = Ast.parseBlock('main =\n', syncModule)
syncModule.replaceRoot(root)
})
Expand Down
4 changes: 2 additions & 2 deletions app/gui2/scripts/generateIconMetadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ console.info('Writing icon name type to "./src/util/iconName.ts"...')
await fs.writeFile(
'./src/util/iconName.ts',
`\
// Generated by \`scripts/generateIcons.js\`.
// Please run \`npm run generate\` to regenerate this file whenever \`icons.svg\` is changed.
// Generated by \`scripts/generateIconMetadata.js\`.
// Please run \`npm run generate-metadata\` to regenerate this file whenever \`icons.svg\` is changed.
import iconNames from '@/util/iconList.json'
export type Icon =
Expand Down
22 changes: 22 additions & 0 deletions app/gui2/shared/ast/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Ast } from './tree'

/// Returns a GraphViz graph illustrating parent/child relationships in the given subtree.
export function graphParentPointers(ast: Ast) {
const sanitize = (id: string) => id.replace('ast:', '').replace(/[^A-Za-z0-9]/g, '')
const parentToChild = new Array<{ parent: string; child: string }>()
const childToParent = new Array<{ child: string; parent: string }>()
ast.visitRecursiveAst((ast) => {
for (const child of ast.children()) {
if (child instanceof Ast)
parentToChild.push({ child: sanitize(child.id), parent: sanitize(ast.id) })
}
const parent = ast.parentId
if (parent) childToParent.push({ child: sanitize(ast.id), parent: sanitize(parent) })
})
let result = 'digraph parentPointers {\n'
for (const { parent, child } of parentToChild) result += `${parent} -> ${child};\n`
for (const { child, parent } of childToParent)
result += `${child} -> ${parent} [weight=0; color=red; style=dotted];\n`
result += '}\n'
return result
}
11 changes: 11 additions & 0 deletions app/gui2/shared/ast/ffi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { createXXHash128 } from 'hash-wasm'
import init, { is_ident_or_operator, parse, parse_doc_to_json } from '../../rust-ffi/pkg/rust_ffi'
import { assertDefined } from '../util/assert'
import { isNode } from '../util/detect'

let xxHasher128: Awaited<ReturnType<typeof createXXHash128>> | undefined
export function xxHash128(input: string) {
assertDefined(xxHasher128, 'Module should have been loaded with `initializeFFI`.')
xxHasher128.init()
xxHasher128.update(input)
return xxHasher128.digest()
}

export async function initializeFFI(path?: string | undefined) {
if (isNode) {
const fs = await import('node:fs/promises')
Expand All @@ -9,6 +19,7 @@ export async function initializeFFI(path?: string | undefined) {
} else {
await init()
}
xxHasher128 = await createXXHash128()
}

// TODO[ao]: We cannot to that, because the ffi is used by cjs modules.
Expand Down
10 changes: 5 additions & 5 deletions app/gui2/shared/ast/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function parentId(ast: Ast): AstId | undefined {
export function subtrees(module: Module, ids: Iterable<AstId>) {
const subtrees = new Set<AstId>()
for (const id of ids) {
let ast = module.get(id)
let ast = module.tryGet(id)
while (ast != null && !subtrees.has(ast.id)) {
subtrees.add(ast.id)
ast = ast.parent()
Expand All @@ -50,10 +50,10 @@ export function subtrees(module: Module, ids: Iterable<AstId>) {
}

/** Returns the IDs of the ASTs that are not descendants of any others in the given set. */
export function subtreeRoots(module: Module, ids: Set<AstId>) {
const roots = new Array<AstId>()
export function subtreeRoots(module: Module, ids: Set<AstId>): Set<AstId> {
const roots = new Set<AstId>()
for (const id of ids) {
const astInModule = module.get(id)
const astInModule = module.tryGet(id)
if (!astInModule) continue
let ast = astInModule.parent()
let hasParentInSet
Expand All @@ -64,7 +64,7 @@ export function subtreeRoots(module: Module, ids: Set<AstId>) {
}
ast = ast.parent()
}
if (!hasParentInSet) roots.push(id)
if (!hasParentInSet) roots.add(id)
}
return roots
}
Loading

0 comments on commit 66db667

Please sign in to comment.