JMLizano JMLizano commited on
Commit
0715aa0
·
unverified ·
1 Parent(s): 58bf1b1

59 fix default workspace env (#68)

Browse files

* Fix default workspace environment

---------

Co-authored-by: JMLizano <[email protected]>

lynxkite-app/src/lynxkite/app/crdt.py CHANGED
@@ -11,7 +11,7 @@ import pycrdt_websocket
11
  import pycrdt_websocket.ystore
12
  import uvicorn
13
  import builtins
14
- from lynxkite.core import workspace
15
 
16
  router = fastapi.APIRouter()
17
  DATA_PATH = pathlib.Path.cwd() / "data"
@@ -52,7 +52,7 @@ class WebsocketServer(pycrdt_websocket.WebsocketServer):
52
  if "edges" not in ws:
53
  ws["edges"] = pycrdt.Array()
54
  if "env" not in ws:
55
- ws["env"] = "unset"
56
  # We have two possible sources of truth for the workspaces, the YStore and the JSON files.
57
  # In case we didn't find the workspace in the YStore, we try to load it from the JSON files.
58
  try_to_load_workspace(ws, name)
 
11
  import pycrdt_websocket.ystore
12
  import uvicorn
13
  import builtins
14
+ from lynxkite.core import workspace, ops
15
 
16
  router = fastapi.APIRouter()
17
  DATA_PATH = pathlib.Path.cwd() / "data"
 
52
  if "edges" not in ws:
53
  ws["edges"] = pycrdt.Array()
54
  if "env" not in ws:
55
+ ws["env"] = next(iter(ops.CATALOGS), 'unset')
56
  # We have two possible sources of truth for the workspaces, the YStore and the JSON files.
57
  # In case we didn't find the workspace in the YStore, we try to load it from the JSON files.
58
  try_to_load_workspace(ws, name)
lynxkite-app/web/playwright.config.ts CHANGED
@@ -3,7 +3,7 @@ import { defineConfig, devices } from '@playwright/test';
3
 
4
  export default defineConfig({
5
  testDir: './tests',
6
- timeout: 60000,
7
  fullyParallel: false,
8
  /* Fail the build on CI if you accidentally left test.only in the source code. */
9
  forbidOnly: !!process.env.CI,
@@ -26,6 +26,6 @@ export default defineConfig({
26
  webServer: {
27
  command: 'cd .. && lynxkite',
28
  url: 'http://127.0.0.1:8000',
29
- reuseExistingServer: !process.env.CI,
30
  },
31
  });
 
3
 
4
  export default defineConfig({
5
  testDir: './tests',
6
+ timeout: 30000,
7
  fullyParallel: false,
8
  /* Fail the build on CI if you accidentally left test.only in the source code. */
9
  forbidOnly: !!process.env.CI,
 
26
  webServer: {
27
  command: 'cd .. && lynxkite',
28
  url: 'http://127.0.0.1:8000',
29
+ reuseExistingServer: false,
30
  },
31
  });
lynxkite-app/web/src/Directory.tsx CHANGED
@@ -25,7 +25,7 @@ const fetcher = (url: string) => fetch(url).then((res) => res.json());
25
  export default function () {
26
  const { path } = useParams();
27
  const encodedPath = encodeURIComponent(path || '');
28
- let list = useSWR(`/api/dir/list?path=${encodedPath}`, fetcher);
29
  const navigate = useNavigate();
30
  const [isCreatingDir, setIsCreatingDir] = useState(false);
31
  const [isCreatingWorkspace, setIsCreatingWorkspace] = useState(false);
@@ -70,7 +70,6 @@ export default function () {
70
  headers: { 'Content-Type': 'application/json' },
71
  body: JSON.stringify({ path: pathSlash + name }),
72
  });
73
- list = await res.json();
74
  if (res.ok) {
75
  navigate(`/dir/${pathSlash}${name}`);
76
  } else {
@@ -83,12 +82,11 @@ export default function () {
83
  const pathSlash = path ? `${path}/` : "";
84
 
85
  const apiPath = item.type === "directory" ? `/api/dir/delete`: `/api/delete`;
86
- const res = await fetch(apiPath, {
87
  method: "POST",
88
  headers: { "Content-Type": "application/json" },
89
  body: JSON.stringify({ path: pathSlash + item.name }),
90
  });
91
- list = await res.json();
92
  }
93
 
94
  return (
 
25
  export default function () {
26
  const { path } = useParams();
27
  const encodedPath = encodeURIComponent(path || '');
28
+ const list = useSWR(`/api/dir/list?path=${encodedPath}`, fetcher);
29
  const navigate = useNavigate();
30
  const [isCreatingDir, setIsCreatingDir] = useState(false);
31
  const [isCreatingWorkspace, setIsCreatingWorkspace] = useState(false);
 
70
  headers: { 'Content-Type': 'application/json' },
71
  body: JSON.stringify({ path: pathSlash + name }),
72
  });
 
73
  if (res.ok) {
74
  navigate(`/dir/${pathSlash}${name}`);
75
  } else {
 
82
  const pathSlash = path ? `${path}/` : "";
83
 
84
  const apiPath = item.type === "directory" ? `/api/dir/delete`: `/api/delete`;
85
+ await fetch(apiPath, {
86
  method: "POST",
87
  headers: { "Content-Type": "application/json" },
88
  body: JSON.stringify({ path: pathSlash + item.name }),
89
  });
 
90
  }
91
 
92
  return (
lynxkite-app/web/tests/basic.spec.ts CHANGED
@@ -10,7 +10,7 @@ test.beforeEach(async ({ browser }) => {
10
  workspace = await Workspace.empty(await browser.newPage(), 'basic_spec_test');
11
  });
12
 
13
- test.afterEach(async ({ }) => {
14
  await workspace.close();
15
  const splash = await new Splash(workspace.page);
16
  splash.page.on('dialog', async dialog => { await dialog.accept(); });
 
10
  workspace = await Workspace.empty(await browser.newPage(), 'basic_spec_test');
11
  });
12
 
13
+ test.afterEach(async () => {
14
  await workspace.close();
15
  const splash = await new Splash(workspace.page);
16
  splash.page.on('dialog', async dialog => { await dialog.accept(); });
lynxkite-app/web/tests/directory.spec.ts CHANGED
@@ -20,7 +20,6 @@ test.describe("Directory operations", () => {
20
  // Not checking for exact match, since there may be pre-existing "Untitled" workspaces
21
  expect(workspace.name).toContain('Untitled');
22
  await workspace.close();
23
- await splash.deleteEntry(workspace.name);
24
  });
25
 
26
  test('Create & delete workspace', async () => {
 
20
  // Not checking for exact match, since there may be pre-existing "Untitled" workspaces
21
  expect(workspace.name).toContain('Untitled');
22
  await workspace.close();
 
23
  });
24
 
25
  test('Create & delete workspace', async () => {
lynxkite-app/web/tests/examples.spec.ts CHANGED
@@ -5,7 +5,7 @@ import { Workspace } from './lynxkite';
5
 
6
  test('LynxKite Graph Analytics example', async ({ page }) => {
7
  const ws = await Workspace.open(page, "NetworkX demo");
8
- expect(await ws.isErrorFree()).toBeTruthy();
9
  });
10
 
11
 
@@ -31,7 +31,7 @@ test.fail('LynxScribe example', async ({ page }) => {
31
  test.fail('Graph RAG', async ({ page }) => {
32
  // Fails due to some issue with ChromaDB
33
  const ws = await Workspace.open(page, "Graph RAG");
34
- expect(await ws.isErrorFree()).toBeTruthy();
35
  });
36
 
37
 
@@ -46,7 +46,7 @@ test.fail('night demo', async ({ page }) => {
46
  // airlines.graphml file not found
47
  // requires cugraph
48
  const ws = await Workspace.open(page, "night demo");
49
- expect(await ws.isErrorFree()).toBeTruthy();
50
  });
51
 
52
 
 
5
 
6
  test('LynxKite Graph Analytics example', async ({ page }) => {
7
  const ws = await Workspace.open(page, "NetworkX demo");
8
+ expect(await ws.isErrorFree(process.env.CI? 2000: 1000)).toBeTruthy();
9
  });
10
 
11
 
 
31
  test.fail('Graph RAG', async ({ page }) => {
32
  // Fails due to some issue with ChromaDB
33
  const ws = await Workspace.open(page, "Graph RAG");
34
+ expect(await ws.isErrorFree(process.env.CI? 2000: 500)).toBeTruthy();
35
  });
36
 
37
 
 
46
  // airlines.graphml file not found
47
  // requires cugraph
48
  const ws = await Workspace.open(page, "night demo");
49
+ expect(await ws.isErrorFree(process.env.CI? 10000: 500)).toBeTruthy();
50
  });
51
 
52
 
lynxkite-app/web/tests/lynxkite.ts CHANGED
@@ -29,19 +29,20 @@ export class Workspace {
29
  static async open(page: Page, workspaceName: string): Promise<Workspace> {
30
  const splash = await Splash.open(page);
31
  const ws = await splash.openWorkspace(workspaceName);
32
- await ws.waitForNodesToLoad()
33
  await ws.expectCurrentWorkspaceIs(workspaceName);
34
  return ws
35
  }
36
 
37
  async getEnvs() {
38
  // Return all available workspace environments
39
- return await this.page.locator('select[name="workspace-env"] option').allInnerTexts();
 
 
40
  }
41
 
42
  async setEnv(env: string) {
43
  await this.page.locator('select[name="workspace-env"]').selectOption(env);
44
- // await this.page.getByRole('combobox', {'name': 'workspace-env'}).selectOption(env);
45
  }
46
 
47
  async expectCurrentWorkspaceIs(name) {
@@ -50,11 +51,8 @@ export class Workspace {
50
 
51
  async waitForNodesToLoad() {
52
  // This method should be used only on non empty workspaces
53
- await this.page.locator('.react-flow__nodes').waitFor({state: 'visible'});
54
- let nodes: Locator[] = [];
55
- while (nodes.length === 0) {
56
- nodes = await this.getBoxes();
57
- }
58
  }
59
 
60
  async addBox(boxName) {
@@ -131,7 +129,10 @@ export class Workspace {
131
  await this.page.mouse.up();
132
  }
133
 
134
- async isErrorFree(): Promise<boolean> {
 
 
 
135
  const boxes = await this.getBoxes();
136
  for (const box of boxes) {
137
  if (await box.locator('.error').isVisible()) {
@@ -188,8 +189,6 @@ export class Splash {
188
  }
189
  await this.page.locator('input[name="workspaceName"]').press('Enter');
190
  const ws = new Workspace(this.page, workspaceName);
191
- // Workaround until we fix the default environment
192
- await ws.setEnv('PyTorch model');
193
  await ws.setEnv('LynxKite Graph Analytics');
194
  return ws;
195
  }
 
29
  static async open(page: Page, workspaceName: string): Promise<Workspace> {
30
  const splash = await Splash.open(page);
31
  const ws = await splash.openWorkspace(workspaceName);
32
+ await ws.waitForNodesToLoad();
33
  await ws.expectCurrentWorkspaceIs(workspaceName);
34
  return ws
35
  }
36
 
37
  async getEnvs() {
38
  // Return all available workspace environments
39
+ const envs = this.page.locator('select[name="workspace-env"] option');
40
+ await expect(envs).not.toHaveCount(0);
41
+ return await envs.allInnerTexts();
42
  }
43
 
44
  async setEnv(env: string) {
45
  await this.page.locator('select[name="workspace-env"]').selectOption(env);
 
46
  }
47
 
48
  async expectCurrentWorkspaceIs(name) {
 
51
 
52
  async waitForNodesToLoad() {
53
  // This method should be used only on non empty workspaces
54
+ await this.page.locator('.react-flow__nodes').waitFor();
55
+ await this.page.locator('.react-flow__node').first().waitFor();
 
 
 
56
  }
57
 
58
  async addBox(boxName) {
 
129
  await this.page.mouse.up();
130
  }
131
 
132
+ async isErrorFree(executionWaitTime?): Promise<boolean> {
133
+ // TODO: Workaround, to account for workspace execution. Once
134
+ // we have a load indicator we can use that instead.
135
+ await new Promise(resolve => setTimeout(resolve, executionWaitTime? executionWaitTime : 500));
136
  const boxes = await this.getBoxes();
137
  for (const box of boxes) {
138
  if (await box.locator('.error').isVisible()) {
 
189
  }
190
  await this.page.locator('input[name="workspaceName"]').press('Enter');
191
  const ws = new Workspace(this.page, workspaceName);
 
 
192
  await ws.setEnv('LynxKite Graph Analytics');
193
  return ws;
194
  }