diff --git a/apps/zui/src/app/routes/app-wrapper/main-area.tsx b/apps/zui/src/app/routes/app-wrapper/main-area.tsx index 6c34d6dc62..27474c51ba 100644 --- a/apps/zui/src/app/routes/app-wrapper/main-area.tsx +++ b/apps/zui/src/app/routes/app-wrapper/main-area.tsx @@ -47,7 +47,13 @@ export function MainArea({children}) { } return ( - + {children} ) diff --git a/apps/zui/src/domain/session/handlers/pins.ts b/apps/zui/src/domain/session/handlers/pins.ts index 68ab000d48..1e52928cc1 100644 --- a/apps/zui/src/domain/session/handlers/pins.ts +++ b/apps/zui/src/domain/session/handlers/pins.ts @@ -5,12 +5,12 @@ import {TimeRangeQueryPin} from "src/js/state/Editor/types" import Pools from "src/js/state/Pools" import Current from "src/js/state/Current" import PoolSettings from "src/js/state/PoolSettings" -import Tabs from "src/js/state/Tabs" import {submitSearch} from "src/domain/session/handlers" import {createHandler} from "src/core/handlers" import ZuiApi from "src/js/api/zui-api" import Selection from "src/js/state/Selection" -import {Snapshots} from "src/domain/handlers" +import {Session} from "src/models/session" +import {Active} from "src/models/active" export const createPinFromEditor = createHandler( "session.createPinFromEditor", @@ -43,13 +43,10 @@ export const createFromPin = createHandler( export const setFromPin = createHandler( "session.setFromPin", - ({dispatch, select}, value: string) => { - if (select(Tabs.none)) { - Snapshots.createAndShow({pins: [{type: "from", value}], value: ""}) - } else { - dispatch(Editor.setFrom(value)) - submitSearch() - } + ({dispatch}, value: string) => { + Session.activateLastFocused() + dispatch(Editor.setFrom(value)) + Active.session.navigate(Active.snapshot, Active.session.namedQuery) } ) diff --git a/apps/zui/src/js/components/TabBar/SearchTab.tsx b/apps/zui/src/js/components/TabBar/SearchTab.tsx index ec3ad070f4..e91ca409ca 100644 --- a/apps/zui/src/js/components/TabBar/SearchTab.tsx +++ b/apps/zui/src/js/components/TabBar/SearchTab.tsx @@ -40,6 +40,9 @@ const SearchTab = React.forwardRef(function SearchTab(
diff --git a/apps/zui/src/js/components/TabBar/TabBar.tsx b/apps/zui/src/js/components/TabBar/TabBar.tsx index 51a5e16d6b..48355738f7 100644 --- a/apps/zui/src/js/components/TabBar/TabBar.tsx +++ b/apps/zui/src/js/components/TabBar/TabBar.tsx @@ -83,7 +83,12 @@ export default function TabBar() { )} {sidebarCollapsed && !global.env.isMac && } - + {ids.map((id: string) => { const tabModel = tab(id, lakes, pools, queryIdNameMap, lakeId) return ( diff --git a/apps/zui/src/models/session.ts b/apps/zui/src/models/session.ts index 451de7f676..85ba6ce78c 100644 --- a/apps/zui/src/models/session.ts +++ b/apps/zui/src/models/session.ts @@ -37,20 +37,20 @@ export class Session extends DomainModel { return new Session({id}) } + get hasUrl() { + return !!this.parentId && !!this.snapshotId + } + get id() { return this.attrs.id } get parentId() { - if (!this.attrs.parentId) - throw new Error("Session has not yet navigated to a url") - else return this.attrs.parentId + return this.attrs.parentId } get snapshotId() { - if (!this.attrs.snapshotId) - throw new Error("Session has not yet navigated to a url") - else return this.attrs.snapshotId + return this.attrs.snapshotId } get pathname() { @@ -78,7 +78,7 @@ export class Session extends DomainModel { } get hasNamedQuery() { - return this.id !== this.parentId + return this.parentId && this.id !== this.parentId } get namedQuery() { diff --git a/packages/zui-player/helpers/test-app.ts b/packages/zui-player/helpers/test-app.ts index 79dea22085..bcc2f6c51b 100644 --- a/packages/zui-player/helpers/test-app.ts +++ b/packages/zui-player/helpers/test-app.ts @@ -129,6 +129,12 @@ export default class TestApp { return await this.mainWin.getByTestId('main-editor').textContent(); } + async getTabCount() { + const tablist = this.page.locator('[role=tablist][id=main-area-tabs]'); + const tabs = tablist.getByRole('tab'); + return await tabs.count(); + } + async getViewerResults(includeHeaders = true): Promise { const fields = await this.mainWin.locator('.zed-table__cell'); await fields.waitFor(); diff --git a/packages/zui-player/tests/set-as-from-pin.spec.ts b/packages/zui-player/tests/set-as-from-pin.spec.ts new file mode 100644 index 0000000000..90e707972d --- /dev/null +++ b/packages/zui-player/tests/set-as-from-pin.spec.ts @@ -0,0 +1,28 @@ +import { play } from 'zui-player'; +import { getPath } from 'zui-test-data'; + +play('Set As From Pin', (app, test) => { + test('when no session tab exists', async () => { + // it creates a session tab + await app.dropFile(getPath('small-zeek.zng')); + await app.click('button', 'Load'); + await app.attached(/Successfully/); + await app.rightClick('treeitem', 'small-zeek.zng'); + const tabCount = await app.getTabCount(); + await app.click('listitem', 'Use as From Pin'); + await app.attached('button', 'from small-zeek.zng'); + test.expect(await app.getTabCount()).toBe(tabCount + 1); + }); + + test('when a session tab does exist', async () => { + // it re-uses the existing session tab + await app.dropFile(getPath('small-zeek.zng')); + await app.click('button', 'Load'); + await app.attached(/Successfully/); + await app.rightClick('treeitem', 'small-zeek.zng_1'); + const tabCount = await app.getTabCount(); + await app.click('listitem', 'Use as From Pin'); + await app.attached('button', 'from small-zeek.zng_1'); + test.expect(await app.getTabCount()).toBe(tabCount); + }); +});