Skip to content

Commit

Permalink
feat: Sidebar cohorts and annotations movement (#18200)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite authored Nov 8, 2023
1 parent cf4ba98 commit e118f3b
Show file tree
Hide file tree
Showing 123 changed files with 834 additions and 903 deletions.
4 changes: 1 addition & 3 deletions cypress/e2e/a11y.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ describe('a11y', () => {
'experiments',
'events',
'datamanagement',
'persons',
'cohorts',
'annotations',
'personsmanagement',
'apps',
'toolbarlaunch',
'projectsettings',
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/annotations.cy.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
describe('Annotations', () => {
beforeEach(() => {
cy.clickNavMenu('annotations')
cy.clickNavMenu('datamanagement')
cy.get('[data-attr=data-management-annotations-tab]').click()
})

it('Annotations loaded', () => {
cy.get('h1').should('contain', 'Annotations')
cy.get('h2').should('contain', 'Create your first annotation')
cy.get('[data-attr="product-introduction-docs-link"]').should('contain', 'Learn more about Annotations')
})
Expand Down
17 changes: 11 additions & 6 deletions cypress/e2e/cohorts.cy.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
describe('Cohorts', () => {
const goToCohorts = (): void => {
cy.clickNavMenu('personsmanagement')
cy.get('[data-attr=persons-management-cohorts-tab]').click()
}

beforeEach(() => {
cy.clickNavMenu('cohorts')
goToCohorts()
})

it('Cohorts new and list', () => {
// load an empty page
cy.get('h1').should('contain', 'Cohorts')
cy.title().should('equal', 'Cohorts • PostHog')
cy.get('h1').should('contain', 'People')
cy.title().should('equal', 'Cohorts • People • PostHog')
cy.get('h2').should('contain', 'Create your first cohort')
cy.get('[data-attr="product-introduction-docs-link"]').should('contain', 'Learn more about Cohorts')

// go to create a new cohort
cy.get('[data-attr="create-cohort"]').click()
cy.get('[data-attr="new-cohort"]').click()

// select "add filter" and "property"
cy.get('[data-attr="cohort-selector-field-value"]').click()
Expand All @@ -34,7 +39,7 @@ describe('Cohorts', () => {
cy.get('[data-attr=success-toast]').contains('Cohort saved').should('exist')

// back to cohorts
cy.clickNavMenu('cohorts')
goToCohorts()
cy.get('tbody').contains('Test Cohort')
cy.get('h2').should('not.have.text', 'Create your first cohort')

Expand Down Expand Up @@ -69,7 +74,7 @@ describe('Cohorts', () => {
// delete cohort
cy.get('[data-attr="more-button"]').click()
cy.get('.Popover__content').contains('Delete cohort').click()
cy.clickNavMenu('cohorts')
goToCohorts()
cy.get('tbody').should('not.have.text', 'Test Cohort (dynamic copy) (static copy)')
})
})
6 changes: 2 additions & 4 deletions cypress/e2e/insights-unsaved-confirmation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ describe('Insights', () => {
const insightName = randomString('to save and then navigate away from')
insight.create(insightName)

cy.get('[data-attr="menu-item-annotations"]').click()
cy.get('[data-attr="menu-item-dashboards"]').click()

// the annotations API call is made before the annotations page loads, so we can't wait for it
cy.get('[data-attr="annotations-content"]').should('exist')
cy.url().should('include', '/annotations')
cy.url().should('include', '/dashboard')
})

it('Can keep editing changed new insight after navigating away with confirm() rejection (case 1)', () => {
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/person.cy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
describe('Person Visualization Check', () => {
beforeEach(() => {
cy.clickNavMenu('persons')
cy.clickNavMenu('personsmanagement')
cy.location('pathname').should('eq', '/persons')
cy.get('.ant-spin-spinning').should('not.exist') // Wait until initial table load to be able to use the search
cy.wait(1000)
cy.get('[data-attr=persons-search]').type('deb').should('have.value', 'deb')
cy.contains('[email protected]').should('not.exist')
cy.contains('[email protected]').click()
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/persons.cy.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
describe('Persons', () => {
beforeEach(() => {
cy.clickNavMenu('persons')
cy.clickNavMenu('personsmanagement')
})

it('All tabs work', () => {
cy.get('h1').should('contain', 'Persons')
cy.get('h1').should('contain', 'People')
cy.get('[data-attr=persons-search]').type('marisol').type('{enter}').should('have.value', 'marisol')
cy.wait(200)
cy.get('[data-row-key]').its('length').should('be.gte', 0)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/posthog-3000-navigation--dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/posthog-3000-navigation--light-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-annotations--annotations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-apps--installed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-batchexports--create-export.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-batchexports--exports.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-batchexports--view-export.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-dashboards--list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-dashboards--new.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-data-management--database.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-events--event-explorer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-features--features-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-features--new-feature-flag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-app-insights--lifecycle--webkit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--lifecycle.png
Binary file modified frontend/__snapshots__/scenes-app-insights--stickiness--webkit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--stickiness.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-number.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-table-edit.png
Binary file modified frontend/__snapshots__/scenes-app-insights--trends-table.png
Binary file modified frontend/__snapshots__/scenes-app-notebooks--bullet-list.png
Binary file modified frontend/__snapshots__/scenes-app-notebooks--empty-notebook.png
Binary file modified frontend/__snapshots__/scenes-app-notebooks--headings.png
Binary file modified frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png
Binary file modified frontend/__snapshots__/scenes-app-notebooks--numbered-list.png
Binary file modified frontend/__snapshots__/scenes-app-notebooks--text-formats.png
Binary file modified frontend/__snapshots__/scenes-app-saved-insights--empty-state.png
Binary file modified frontend/__snapshots__/scenes-app-saved-insights--list-view.png
Binary file modified frontend/__snapshots__/scenes-app-surveys--survey-not-found.png
Binary file modified frontend/__snapshots__/scenes-app-surveys--survey-view.png
Binary file modified frontend/__snapshots__/scenes-app-surveys--surveys-list.png
58 changes: 38 additions & 20 deletions frontend/src/layout/navigation-3000/components/NavbarButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Tooltip } from 'lib/lemon-ui/Tooltip'
import clsx from 'clsx'
import { useValues } from 'kea'
import { sceneLogic } from 'scenes/sceneLogic'
import { SidebarChangeNoticeContent, useSidebarChangeNotices } from '~/layout/navigation/SideBar/SidebarChangeNotice'
import { navigation3000Logic } from '../navigationLogic'
import { LemonTag } from '@posthog/lemon-ui'
import { useFeatureFlag } from 'lib/hooks/useFeatureFlag'
Expand Down Expand Up @@ -63,29 +64,46 @@ export const NavbarButton: FunctionComponent<NavbarButtonProps> = React.forwardR
}
}

const buttonContent = (
<LemonButton
ref={ref}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
onMouseEnter={() => setHasBeenClicked(false)}
onClick={() => {
setHasBeenClicked(true)
onClick?.()
}}
className={clsx('NavbarButton', isUsingNewNav && here && 'NavbarButton--here')}
fullWidth
{...buttonProps}
>
{content}
</LemonButton>
)

const [notices, onAcknowledged] = useSidebarChangeNotices({ identifier })

return (
<li className="w-full">
<Tooltip
title={isNavCollapsedActually ? (here ? `${title} (you are here)` : title) : null}
placement="right"
delayMs={0}
visible={!persistentTooltip && hasBeenClicked ? false : undefined} // Force-hide tooltip after button click
>
<LemonButton
ref={ref}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
onMouseEnter={() => setHasBeenClicked(false)}
onClick={() => {
setHasBeenClicked(true)
onClick?.()
}}
className={clsx('NavbarButton', isUsingNewNav && here && 'NavbarButton--here')}
fullWidth
{...buttonProps}
{notices.length ? (
<Tooltip
title={<SidebarChangeNoticeContent notices={notices} onAcknowledged={onAcknowledged} />}
placement={notices[0].placement ?? 'right'}
delayMs={0}
visible={true}
>
{buttonContent}
</Tooltip>
) : (
<Tooltip
title={isNavCollapsedActually ? (here ? `${title} (you are here)` : title) : null}
placement="right"
delayMs={0}
visible={!persistentTooltip && hasBeenClicked ? false : undefined} // Force-hide tooltip after button click
>
{content}
</LemonButton>
</Tooltip>
{buttonContent}
</Tooltip>
)}
</li>
)
})
Expand Down
38 changes: 10 additions & 28 deletions frontend/src/layout/navigation-3000/navigationLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ import {
IconHome,
IconLive,
IconPeople,
IconPerson,
IconPieChart,
IconQuestion,
IconRewindPlay,
IconTestTube,
IconToggle,
Expand All @@ -32,8 +30,6 @@ import {
IconChat,
} from '@posthog/icons'
import { urls } from 'scenes/urls'
import { annotationsSidebarLogic } from './sidebars/annotations'
import { cohortsSidebarLogic } from './sidebars/cohorts'
import { dashboardsSidebarLogic } from './sidebars/dashboards'
import { dataManagementSidebarLogic } from './sidebars/dataManagement'
import { experimentsSidebarLogic } from './sidebars/experiments'
Expand Down Expand Up @@ -322,33 +318,12 @@ export const navigation3000Logic = kea<navigation3000LogicType>([
to: isUsingSidebar ? undefined : urls.eventDefinitions(),
},
{
identifier: Scene.Persons,
label: 'People and groups',
icon: <IconPerson />,
identifier: Scene.PersonsManagement,
label: 'People',
icon: <IconPeople />,
logic: isUsingSidebar ? personsAndGroupsSidebarLogic : undefined,
to: isUsingSidebar ? undefined : urls.persons(),
},
{
identifier: Scene.Cohorts,
label: 'Cohorts',
icon: <IconPeople />,
logic: isUsingSidebar ? cohortsSidebarLogic : undefined,
to: isUsingSidebar ? undefined : urls.cohorts(),
},
{
identifier: Scene.Annotations,
label: 'Annotations',
icon: <IconQuestion />,
logic: isUsingSidebar ? annotationsSidebarLogic : undefined,
to: isUsingSidebar ? undefined : urls.annotations(),
},
{
identifier: Scene.ToolbarLaunch,
label: 'Toolbar',
icon: <IconToolbar />,
logic: isUsingSidebar ? toolbarSidebarLogic : undefined,
to: isUsingSidebar ? undefined : urls.toolbarLaunch(),
},
],
[
{
Expand Down Expand Up @@ -415,6 +390,13 @@ export const navigation3000Logic = kea<navigation3000LogicType>([
icon: <IconApps />,
to: urls.projectApps(),
},
{
identifier: Scene.ToolbarLaunch,
label: 'Toolbar',
icon: <IconToolbar />,
logic: isUsingSidebar ? toolbarSidebarLogic : undefined,
to: isUsingSidebar ? undefined : urls.toolbarLaunch(),
},
],
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { sceneLogic } from 'scenes/sceneLogic'
import { Scene } from 'scenes/sceneTypes'

const blankScene = (): any => ({ scene: { component: () => null, logic: null } })
const scenes: any = { [Scene.Annotations]: blankScene, [Scene.Dashboards]: blankScene }
const scenes: any = { [Scene.SavedInsights]: blankScene, [Scene.Dashboards]: blankScene }

describe('breadcrumbsLogic', () => {
let logic: ReturnType<typeof breadcrumbsLogic.build>
Expand All @@ -24,9 +24,9 @@ describe('breadcrumbsLogic', () => {
logic.mount()

// test with .delay because subscriptions happen async
router.actions.push(urls.annotations())
await expectLogic(logic).delay(1).toMatchValues({ documentTitle: 'Annotations • PostHog' })
expect(global.document.title).toEqual('Annotations • PostHog')
router.actions.push(urls.savedInsights())
await expectLogic(logic).delay(1).toMatchValues({ documentTitle: 'Insights • PostHog' })
expect(global.document.title).toEqual('Insights • PostHog')

router.actions.push(urls.dashboards())
await expectLogic(logic).delay(1).toMatchValues({ documentTitle: 'Dashboards • PostHog' })
Expand Down
88 changes: 46 additions & 42 deletions frontend/src/layout/navigation/SideBar/PageButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Scene } from 'scenes/sceneTypes'
import { LemonButton, LemonButtonProps, LemonButtonWithSideAction, SideAction } from 'lib/lemon-ui/LemonButton'
import { sceneConfigurations } from 'scenes/scenes'
import { LemonTag } from 'lib/lemon-ui/LemonTag/LemonTag'
import { SidebarChangeNoticeTooltip } from '~/layout/navigation/SideBar/SidebarChangeNotice'

export interface PageButtonProps extends Pick<LemonButtonProps, 'icon' | 'onClick' | 'to'> {
/** Used for highlighting the active scene. `identifier` of type number means dashboard ID instead of scene. */
Expand All @@ -32,48 +33,51 @@ export function PageButton({ title, sideAction, identifier, highlight, ...button

return (
<li>
{sideAction ? (
<LemonButtonWithSideAction
fullWidth
status={buttonStatus}
active={isActive}
onClick={hideSideBarMobile}
sideAction={{
...sideAction,
'data-attr': sideAction.identifier
? `menu-item-${sideAction.identifier.toLowerCase()}`
: undefined,
}}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
{...buttonProps}
>
<span className="text-default">{title}</span>
</LemonButtonWithSideAction>
) : (
<LemonButton
fullWidth
status={buttonStatus}
active={isActive}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
onClick={hideSideBarMobile}
{...buttonProps}
>
<span className="text-default grow">{title}</span>
{highlight === 'alpha' ? (
<LemonTag type="completion" className="ml-1 float-right uppercase">
Alpha
</LemonTag>
) : highlight === 'beta' ? (
<LemonTag type="warning" className="ml-1 float-right uppercase">
Beta
</LemonTag>
) : highlight === 'new' ? (
<LemonTag type="success" className="ml-1 float-right uppercase">
New
</LemonTag>
) : null}
</LemonButton>
)}
<SidebarChangeNoticeTooltip identifier={identifier}>
{sideAction ? (
<LemonButtonWithSideAction
fullWidth
status={buttonStatus}
active={isActive}
onClick={hideSideBarMobile}
sideAction={{
...sideAction,
'data-attr': sideAction.identifier
? `menu-item-${sideAction.identifier.toLowerCase()}`
: undefined,
}}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
{...buttonProps}
>
<span className="text-default">{title}</span>
</LemonButtonWithSideAction>
) : (
<LemonButton
fullWidth
status={buttonStatus}
active={isActive}
data-attr={`menu-item-${identifier.toString().toLowerCase()}`}
onClick={hideSideBarMobile}
sideIcon={null}
{...buttonProps}
>
<span className="text-default grow">{title}</span>
{highlight === 'alpha' ? (
<LemonTag type="completion" className="ml-1 float-right uppercase">
Alpha
</LemonTag>
) : highlight === 'beta' ? (
<LemonTag type="warning" className="ml-1 float-right uppercase">
Beta
</LemonTag>
) : highlight === 'new' ? (
<LemonTag type="success" className="ml-1 float-right uppercase">
New
</LemonTag>
) : null}
</LemonButton>
)}
</SidebarChangeNoticeTooltip>
</li>
)
}
Loading

0 comments on commit e118f3b

Please sign in to comment.