Back to Posthog

How to add tabs to a scene?

frontend/src/stories/How to add tabs to a scene.stories.mdx

1.43.13.7 KB
Original Source

import { Meta } from '@storybook/addon-docs'

<Meta title="How to add tabs to a scene?" />

How to add tabs to a scene?

This guide follows on from "How to build a scene" – we'll be adding tabs to that guide's Dashboards scene.

  1. Add an enum to frontend/src/types.ts to define the tabs:
ts
export enum DashboardsTabs {
  First = 'first',
  Second = 'second',
}
  1. Update the URL in frontend/src/scenes/urls.ts to handle tabs:
ts
dashboards: (tab: DashboardsTabs = DashboardsTabs.First): string => `/dashboards/${tab}`
  1. Add entries to routes per tab in frontend/src/scenes/scenes.ts:
ts
     // One entry for every available tab
    ...Object.fromEntries(
        Object.values(DashboardsTabs).map((tab) => [urls.dashboards(tab), Scene.Dashboards])
    ) as Record<string, Scene>,
  1. Update dashboardsLogic to handle tab changes in frontend/src/scenes/dashboards/dashboardsLogic.ts:
ts
import { actions, kea, path, reducers, selectors } from 'kea'
import { actionToUrl, urlToAction } from 'kea-router'

import { urls } from 'scenes/urls'

import { Breadcrumb, DashboardsTabs } from '~/types'

export const DASHBOARDS_TAB_TO_NAME: Record<DashboardsTabs, string> = {
  [DashboardsTabs.First]: 'First',
  [DashboardsTabs.Second]: 'Second',
}

export const dashboardsLogic = kea([
  path(['scenes', 'dashboard', 'dashboardsLogic']),
  actions({
    setCurrentTab: (tab: DashboardsTabs = DashboardsTabs.First) => ({ tab }),
  }),
  reducers({
    currentTab: [
      DashboardsTabs.First as DashboardsTabs,
      {
        setCurrentTab: (_, { tab }) => tab,
      },
    ],
  }),
  selectors(() => ({
    breadcrumbs: [
      // Optional if you'd like the breadcrumbs to show the current tab
      (s) => [s.currentTab],
      (tab): Breadcrumb[] => {
        const breadcrumbs: Breadcrumb[] = [{ name: 'Dashboards' }]
        breadcrumbs.push({
          name: DASHBOARDS_TAB_TO_NAME[tab],
        })

        return breadcrumbs
      },
    ],
  })),
  actionToUrl(({ values }) => {
    return {
      setCurrentTab: () => [urls.dashboards(values.currentTab)],
    }
  }),
  urlToAction(({ actions, values }) => ({
    '/dashboards/:tab': ({ tab }) => {
      if (tab !== values.currentTab) {
        actions.setCurrentTab(tab as DashboardsTabs)
      }
    },
  })),
])
  1. Update frontend/src/scenes/dashboards/Dashboards.tsx to render the tabs:
tsx
import { useValues } from 'kea'
import { router } from 'kea-router'

import { LemonTabs } from 'lib/lemon-ui/LemonTabs/LemonTabs'
import { SceneExport } from 'scenes/sceneTypes'
import { urls } from 'scenes/urls'

import { DashboardsTabs } from '~/types'

import { dashboardsLogic, humanFriendlyTabName } from './dashboardsLogic'

const DASHBOARDS_TAB_TO_CONTENT: Record<DashboardsTabs, JSX.Element> = {
  [DashboardsTabs.First]: <div>First tab content</div>,
  [DashboardsTabs.Second]: <div>Second tab content</div>,
}

export const scene: SceneExport = {
  component: Dashboards,
  logic: dashboardsLogic,
}

export function Dashboards(): JSX.Element {
  const { currentTab } = useValues(dashboardsLogic)

  return (
    <div>
      <LemonTabs
        activeKey={currentTab}
        onChange={(tab) => router.actions.push(urls.dashboards(tab as DashboardsTabs))}
        tabs={Object.values(DashboardsTabs).map((tab) => ({
          label: DASHBOARDS_TAB_TO_NAME[tab],
          key: tab,
          content: DASHBOARDS_TAB_TO_CONTENT[tab],
        }))}
      />
    </div>
  )
}