Skip to content

Commit

Permalink
Turbo mode (#6632)
Browse files Browse the repository at this point in the history
* fix router redirect

* remove dependence on user var

* split scenes and sceneTypes out of sceneLogic

* rename LoadedScene type to SceneExport

* export SceneExport from most scenes

* use exported scene objects, warn if not exported

* fix type import bugs

* remove dashboard

* keep all loaded scene logics in memory

* fix sorting bugs

* support scenes with params, make it work with dashboards

* fetch result from dashboard if mounted

* fix mutations

* add lastTouch

* refactor scene parameters to include searchParams and hashParams

* add insights scene to scene router

* add insight router scene to scene router

* fix cohort back/forward bug

* this works

* bring back delayed loading of scenes

* set insight from dashboard also in afterMount

* split events, actions, event stats and properties stats into their own scenes

* refactor to options object for setInsight

* override filters

* clean filters for comparison

* fix cohort bug

* get a better feature flag

* make turbo mode faster by making non-turbo-mode slower

* less noise in failed tests

* fix tests

* flyby: add jest tests pycharm launcher

* clean up scenes

* add test for loading from dashboardLogic

* fix bug

* split test init code into two

* have the same data in the context and in the api

* add basic tests for sceneLogic

* run the latest and greatest

* fix menu highlight

* implement screaming snake

* only show scenes with logics
  • Loading branch information
mariusandra committed Oct 26, 2021
1 parent df583d5 commit f76d0b6
Show file tree
Hide file tree
Showing 62 changed files with 1,103 additions and 592 deletions.
11 changes: 11 additions & 0 deletions .run/Jest Tests.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Jest Tests" type="JavaScriptTestRunnerJest">
<node-interpreter value="project" />
<node-options value="" />
<jest-package value="$PROJECT_DIR$/node_modules/jest" />
<working-dir value="$PROJECT_DIR$" />
<envs />
<scope-kind value="ALL" />
<method v="2" />
</configuration>
</component>
14 changes: 9 additions & 5 deletions frontend/src/layout/navigation/MainNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '@ant-design/icons'
import { useActions, useValues } from 'kea'
import { Link } from 'lib/components/Link'
import { Scene, sceneLogic } from 'scenes/sceneLogic'
import { sceneLogic } from 'scenes/sceneLogic'
import { urls } from 'scenes/urls'
import { isMobile } from 'lib/utils'
import { useEscapeKey } from 'lib/hooks/useEscapeKey'
Expand Down Expand Up @@ -44,12 +44,16 @@ import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { FEATURE_FLAGS } from 'lib/constants'
import { Tooltip } from 'lib/components/Tooltip'
import { teamLogic } from 'scenes/teamLogic'
import { Scene } from 'scenes/sceneTypes'

// to show the right page in the sidebar
const sceneOverride: Partial<Record<Scene, string>> = {
action: 'actions',
person: 'persons',
dashboard: 'dashboards',
const sceneOverride: Partial<Record<Scene, Scene>> = {
[Scene.Action]: Scene.Events,
[Scene.Actions]: Scene.Events,
[Scene.EventStats]: Scene.Events,
[Scene.EventPropertyStats]: Scene.Events,
[Scene.Person]: Scene.Persons,
[Scene.Dashboard]: Scene.Dashboards,
}

interface MenuItemProps {
Expand Down
12 changes: 7 additions & 5 deletions frontend/src/lib/api.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export const MOCK_ORGANIZATION_ID: OrganizationType['id'] = 'ABCD'

export const api = apiReal as any as APIMockReturnType

export const MOCK_DEFAULT_TEAM = {
id: MOCK_TEAM_ID,
ingested_event: true,
completed_snippet_onboarding: true,
}

export const mockAPI = (cb: (url: APIRoute) => any): void => {
beforeEach(async () => {
const methods = ['get', 'update', 'create', 'delete']
Expand All @@ -52,11 +58,7 @@ export function defaultAPIMocks(
team: { ingested_event: true, completed_snippet_onboarding: true },
}
} else if (pathname === 'api/projects/@current') {
return {
id: MOCK_TEAM_ID,
ingested_event: true,
completed_snippet_onboarding: true,
}
return MOCK_DEFAULT_TEAM
} else if (pathname === 'api/organizations/@current') {
return {
id: MOCK_ORGANIZATION_ID,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ export const FEATURE_FLAGS = {
SIGMA_ANALYSIS: 'sigma-analysis', // owner: @neilkakkar
NEW_SESSIONS_PLAYER: 'new-sessions-player', // owner: @rcmarron
BREAKDOWN_BY_MULTIPLE_PROPERTIES: '938-breakdown-by-multiple-properties', // owner: @pauldambra
TURBO_MODE: 'turbo-mode', // owner: @mariusandra
}

export const ENTITY_MATCH_TYPE = 'entities'
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/models/dashboardsModel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export const dashboardsModel = kea<dashboardsModelType>({
nameSortedDashboards: [
() => [selectors.rawDashboards],
(rawDashboards) => {
return Object.values(rawDashboards).sort((a, b) =>
return [...Object.values(rawDashboards)].sort((a, b) =>
(a.name ?? 'Untitled').localeCompare(b.name ?? 'Untitled')
)
},
Expand All @@ -198,7 +198,7 @@ export const dashboardsModel = kea<dashboardsModelType>({
pinSortedDashboards: [
() => [selectors.nameSortedDashboards],
(nameSortedDashboards) => {
return nameSortedDashboards.sort(
return [...nameSortedDashboards].sort(
(a, b) =>
(Number(b.pinned) - Number(a.pinned)) * 10 +
(a.name ?? 'Untitled').localeCompare(b.name ?? 'Untitled')
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/scenes/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { models } from '~/models'
import { FEATURE_FLAGS } from 'lib/constants'
import { CloudAnnouncement } from '~/layout/navigation/CloudAnnouncement'
import { teamLogic } from './teamLogic'
import { LoadedScene } from 'scenes/sceneTypes'

export const appLogic = kea<appLogicType>({
actions: {
Expand Down Expand Up @@ -64,11 +65,13 @@ export function App(): JSX.Element | null {
const { user } = useValues(userLogic)
const { currentTeamId } = useValues(teamLogic)
const { sceneConfig } = useValues(sceneLogic)
const { featureFlags } = useValues(featureFlagLogic)

if (showApp) {
return (
<>
{user && currentTeamId ? <Models /> : null}
{featureFlags[FEATURE_FLAGS.TURBO_MODE] ? <LoadedSceneLogics /> : null}
{(!sceneConfig.projectBased || currentTeamId) && <AppScene />}
</>
)
Expand All @@ -77,6 +80,27 @@ export function App(): JSX.Element | null {
return showingDelayedSpinner ? <SceneLoading /> : null
}

function LoadedSceneLogic({ scene }: { scene: LoadedScene }): null {
if (!scene.logic) {
throw new Error('Loading scene without a logic')
}
useMountedLogic(scene.logic(scene.paramsToProps?.(scene.sceneParams)))
return null
}

function LoadedSceneLogics(): JSX.Element {
const { loadedScenes } = useValues(sceneLogic)
return (
<>
{Object.entries(loadedScenes)
.filter(([, { logic }]) => !!logic)
.map(([key, loadedScene]) => (
<LoadedSceneLogic key={key} scene={loadedScene} />
))}
</>
)
}

/** Loads every logic in the "src/models" folder */
function Models(): null {
useMountedLogic(models)
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/PreflightCheck/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { router } from 'kea-router'
import { PageHeader } from 'lib/components/PageHeader'
import { capitalizeFirstLetter } from 'lib/utils'
import { urls } from 'scenes/urls'
import { SceneExport } from 'scenes/sceneTypes'

interface PreflightItemInterface {
name: string
Expand All @@ -29,6 +30,11 @@ interface CheckInterface extends PreflightItemInterface {
id: string
}

export const scene: SceneExport = {
component: PreflightCheck,
logic: preflightLogic,
}

function PreflightItem({ name, status, caption, failedState }: PreflightItemInterface): JSX.Element {
/*
status === undefined -> Item still loading (no positive or negative response yet)
Expand Down
11 changes: 10 additions & 1 deletion frontend/src/scenes/actions/ActionsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { PageHeader } from 'lib/components/PageHeader'
import { getBreakpoint } from 'lib/utils/responsiveUtils'
import { ColumnType } from 'antd/lib/table'
import { teamLogic } from '../teamLogic'
import { SceneExport } from 'scenes/sceneTypes'
import { EventsTab, EventsTabs } from 'scenes/events'
import api from '../../lib/api'
import { getCurrentTeamId } from '../../lib/utils/logics'

Expand All @@ -30,6 +32,12 @@ const searchActions = (sources: ActionType[], search: string): ActionType[] => {
.map((result) => result.item)
}

export const scene: SceneExport = {
component: ActionsTable,
logic: actionsModel,
paramsToProps: () => ({ params: 'include_count=1' }),
}

export function ActionsTable(): JSX.Element {
const { currentTeam, currentTeamId } = useValues(teamLogic)
const { actions, actionsLoading } = useValues(actionsModel({ params: 'include_count=1' }))
Expand Down Expand Up @@ -179,7 +187,8 @@ export function ActionsTable(): JSX.Element {
}

return (
<div>
<div data-attr="manage-events-table" style={{ paddingTop: 32 }}>
<EventsTabs tab={EventsTab.Actions} />
<PageHeader
title="Actions"
caption={
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/annotations/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs'
import generatePicker from 'antd/es/date-picker/generatePicker'
import { normalizeColumnTitle, useIsTableScrolling } from 'lib/components/Table/utils'
import { teamLogic } from '../teamLogic'
import { SceneExport } from 'scenes/sceneTypes'
const DatePicker = generatePicker<dayjs.Dayjs>(dayjsGenerateConfig)

const { TextArea } = Input

export const scene: SceneExport = {
component: Annotations,
logic: annotationsTableLogic,
}

export function Annotations(): JSX.Element {
const { annotations, annotationsLoading, next, loadingNext } = useValues(annotationsTableLogic)
const { updateAnnotation, deleteAnnotation, loadAnnotationsNext, restoreAnnotation } =
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/authentication/InviteSignup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ import { preflightLogic } from 'scenes/PreflightCheck/logic'
import Checkbox from 'antd/lib/checkbox/Checkbox'
import smLogo from 'public/icon-white.svg'
import { urls } from 'scenes/urls'
import { SceneExport } from 'scenes/sceneTypes'

export const scene: SceneExport = {
component: InviteSignup,
logic: inviteSignupLogic,
}

const UTM_TAGS = 'utm_medium=in-product&utm_campaign=invite-signup'
const PasswordStrength = lazy(() => import('../../lib/components/PasswordStrength'))
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/authentication/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import { ExclamationCircleFilled } from '@ant-design/icons'
import clsx from 'clsx'
import { ErrorMessage } from 'lib/components/ErrorMessage/ErrorMessage'
import { WelcomeLogo } from './WelcomeLogo'
import { SceneExport } from 'scenes/sceneTypes'

export const scene: SceneExport = {
component: Login,
logic: loginLogic,
}

export function Login(): JSX.Element {
const [form] = Form.useForm()
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/authentication/PasswordReset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import { preflightLogic } from 'scenes/PreflightCheck/logic'
import { CodeSnippet, Language } from 'scenes/ingestion/frameworks/CodeSnippet'
import { passwordResetLogic } from './passwordResetLogic'
import { router } from 'kea-router'
import { SceneExport } from 'scenes/sceneTypes'

export const scene: SceneExport = {
component: PasswordReset,
logic: passwordResetLogic,
}

export function PasswordReset(): JSX.Element {
const { preflight, preflightLoading } = useValues(preflightLogic)
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/authentication/PasswordResetComplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import { ExclamationCircleFilled, StopOutlined } from '@ant-design/icons'
import { useActions, useValues } from 'kea'
import { passwordResetLogic } from './passwordResetLogic'
import { router } from 'kea-router'
import { SceneExport } from 'scenes/sceneTypes'

export const scene: SceneExport = {
component: PasswordResetComplete,
logic: passwordResetLogic,
}

export function PasswordResetComplete(): JSX.Element {
const { validatedResetToken, validatedResetTokenLoading } = useValues(passwordResetLogic)
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/authentication/Signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import { userLogic } from '../userLogic'
import { WelcomeLogo } from './WelcomeLogo'
import hedgehogMain from 'public/hedgehog-bridge-page.png'
import { ErrorMessage } from 'lib/components/ErrorMessage/ErrorMessage'
import { SceneExport } from 'scenes/sceneTypes'

export const scene: SceneExport = {
component: Signup,
logic: signupLogic,
}

const UTM_TAGS = 'utm_campaign=in-product&utm_tag=signup-header'

Expand Down
6 changes: 6 additions & 0 deletions frontend/src/scenes/billing/Billing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { BillingEnrollment } from './BillingEnrollment'
import { useValues } from 'kea'
import './Billing.scss'
import { billingLogic } from './billingLogic'
import { SceneExport } from 'scenes/sceneTypes'

export const scene: SceneExport = {
component: Billing,
logic: billingLogic,
}

export function Billing(): JSX.Element {
const { billing } = useValues(billingLogic)
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/scenes/billing/billingLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { kea } from 'kea'
import api from 'lib/api'
import { billingLogicType } from './billingLogicType'
import { PlanInterface, BillingType } from '~/types'
import { sceneLogic, Scene } from 'scenes/sceneLogic'
import { sceneLogic } from 'scenes/sceneLogic'
import { preflightLogic } from 'scenes/PreflightCheck/logic'
import posthog from 'posthog-js'
import { Scene } from 'scenes/sceneTypes'

export const UTM_TAGS = 'utm_medium=in-product&utm_campaign=billing-management'
export const ALLOCATION_THRESHOLD_ALERT = 0.85 // Threshold to show warning of event usage near limit
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/scenes/cohorts/Cohorts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import relativeTime from 'dayjs/plugin/relativeTime'
import { cohortsUrlLogicType } from './CohortsType'
import { Link } from 'lib/components/Link'
import { PROPERTY_MATCH_TYPE } from 'lib/constants'
import { SceneExport } from 'scenes/sceneTypes'

dayjs.extend(relativeTime)

Expand Down Expand Up @@ -60,6 +61,8 @@ const cohortsUrlLogic = kea<cohortsUrlLogicType>({
actions.setOpenCohort(cohort)
} else if (cohortId === 'new') {
actions.setOpenCohort(NEW_COHORT)
} else if (!cohortId) {
actions.setOpenCohort(null)
}
},
}),
Expand Down Expand Up @@ -221,3 +224,8 @@ export function Cohorts(): JSX.Element {
</div>
)
}

export const scene: SceneExport = {
component: Cohorts,
logic: cohortsUrlLogic,
}
17 changes: 12 additions & 5 deletions frontend/src/scenes/dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
import React from 'react'
import { SceneLoading } from 'lib/utils'
import { BindLogic, useActions, useValues } from 'kea'
import { dashboardLogic } from 'scenes/dashboard/dashboardLogic'
import { dashboardLogic, DashboardLogicProps } from 'scenes/dashboard/dashboardLogic'
import { DashboardHeader } from 'scenes/dashboard/DashboardHeader'
import { DashboardItems } from 'scenes/dashboard/DashboardItems'
import { dashboardsModel } from '~/models/dashboardsModel'
import { DateFilter } from 'lib/components/DateFilter/DateFilter'
import { CalendarOutlined } from '@ant-design/icons'
import './Dashboard.scss'
import { useKeyboardHotkeys } from '../../lib/hooks/useKeyboardHotkeys'
import { DashboardMode } from '../../types'
import { DashboardEventSource } from '../../lib/utils/eventUsageLogic'
import { useKeyboardHotkeys } from 'lib/hooks/useKeyboardHotkeys'
import { DashboardMode } from '~/types'
import { DashboardEventSource } from 'lib/utils/eventUsageLogic'
import { TZIndicator } from 'lib/components/TimezoneAware'
import { EmptyDashboardComponent } from './EmptyDashboardComponent'
import { NotFound } from 'lib/components/NotFound'
import { DashboardReloadAction, LastRefreshText } from 'scenes/dashboard/DashboardReloadAction'
import { SceneExport } from 'scenes/sceneTypes'

interface Props {
id?: string
shareToken?: string
internal?: boolean
}

export function Dashboard({ id, shareToken, internal }: Props): JSX.Element {
export const scene: SceneExport = {
component: Dashboard,
logic: dashboardLogic,
paramsToProps: ({ params: { id } }): DashboardLogicProps => ({ id: parseInt(id) }),
}

export function Dashboard({ id, shareToken, internal }: Props = {}): JSX.Element {
return (
<BindLogic logic={dashboardLogic} props={{ id: id ? parseInt(id) : undefined, shareToken, internal }}>
<DashboardView />
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/scenes/dashboard/Dashboards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ import { userLogic } from 'scenes/userLogic'
import { ColumnType } from 'antd/lib/table'
import { DashboardEventSource } from 'lib/utils/eventUsageLogic'
import { urls } from 'scenes/urls'
import { SceneExport } from 'scenes/sceneTypes'
import { sceneLogic } from 'scenes/sceneLogic'

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

export function Dashboards(): JSX.Element {
const { dashboardsLoading } = useValues(dashboardsModel)
Expand Down

0 comments on commit f76d0b6

Please sign in to comment.