diff --git a/.eslintrc.js b/.eslintrc.js
index 73da9704eee46..5f71d84aebdd8 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -12,7 +12,7 @@ const globals = {
}
module.exports = {
- ignorePatterns: ['node_modules', 'plugin-server'],
+ ignorePatterns: ['node_modules', 'plugin-server', 'cypress'],
env,
settings: {
react: {
@@ -27,12 +27,12 @@ module.exports = {
},
extends: [
'eslint:recommended',
- 'plugin:@typescript-eslint/recommended',
+ 'plugin:@typescript-eslint/recommended-type-checked',
'plugin:react/recommended',
'plugin:eslint-comments/recommended',
'plugin:storybook/recommended',
- 'prettier',
'plugin:compat/recommended',
+ 'prettier',
],
globals,
parser: '@typescript-eslint/parser',
@@ -42,12 +42,25 @@ module.exports = {
},
ecmaVersion: 2018,
sourceType: 'module',
+ project: 'tsconfig.json',
},
- plugins: ['prettier', 'react', 'cypress', '@typescript-eslint', 'no-only-tests', 'jest', 'compat', 'posthog'],
+ plugins: [
+ 'prettier',
+ 'react',
+ 'cypress',
+ '@typescript-eslint',
+ 'no-only-tests',
+ 'jest',
+ 'compat',
+ 'posthog',
+ 'simple-import-sort',
+ ],
rules: {
'no-console': ['error', { allow: ['warn', 'error'] }],
'no-debugger': 'error',
'no-only-tests/no-only-tests': 'error',
+ 'simple-import-sort/imports': 'error',
+ 'simple-import-sort/exports': 'error',
'react/prop-types': [0],
'react/react-in-jsx-scope': [0],
'react/no-unescaped-entities': [0],
@@ -72,7 +85,27 @@ module.exports = {
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
- '@typescript-eslint/no-non-null-assertion': 'error',
+ '@typescript-eslint/require-await': 'off', // TODO: Enable - this rule is useful, but doesn't have an autofix
+ '@typescript-eslint/no-unsafe-assignment': 'off',
+ '@typescript-eslint/no-unsafe-member-access': 'off',
+ '@typescript-eslint/no-unsafe-enum-comparison': 'off',
+ '@typescript-eslint/no-unsafe-argument': 'off',
+ '@typescript-eslint/no-unsafe-return': 'off',
+ '@typescript-eslint/no-unsafe-call': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/restrict-template-expressions': 'off',
+ '@typescript-eslint/explicit-function-return-type': [
+ 'error',
+ {
+ allowExpressions: true,
+ },
+ ],
+ '@typescript-eslint/explicit-module-boundary-types': [
+ 'error',
+ {
+ allowArgumentsExplicitlyTypedAsAny: true,
+ },
+ ],
curly: 'error',
'no-restricted-imports': [
'error',
@@ -91,6 +124,11 @@ module.exports = {
importNames: ['Tooltip'],
message: 'Please use Tooltip from @posthog/lemon-ui instead.',
},
+ {
+ name: 'antd',
+ importNames: ['Alert'],
+ message: 'Please use LemonBanner from @posthog/lemon-ui instead.',
+ },
],
},
],
@@ -210,6 +248,10 @@ module.exports = {
element: 'a',
message: 'use instead',
},
+ {
+ element: 'Alert',
+ message: 'use instead',
+ },
],
},
],
@@ -230,43 +272,37 @@ module.exports = {
...globals,
given: 'readonly',
},
+ rules: {
+ // The below complains needlessly about expect(api.createInvite).toHaveBeenCalledWith(...)
+ '@typescript-eslint/unbound-method': 'off',
+ },
},
{
- // disable these rules for files generated by kea-typegen
- files: ['*Type.ts', '*Type.tsx'],
+ files: ['*Type.ts', '*Type.tsx'], // Kea typegen output
rules: {
- '@typescript-eslint/no-explicit-any': ['off'],
- '@typescript-eslint/ban-types': ['off'],
+ 'no-restricted-imports': 'off',
+ '@typescript-eslint/ban-types': 'off',
+ 'simple-import-sort/imports': 'off',
+ 'simple-import-sort/exports': 'off',
},
},
{
- // enable the rule specifically for TypeScript files
- files: ['*.ts', '*.tsx'],
+ files: ['frontend/src/scenes/notebooks/Nodes/*'], // Notebooks code weirdly relies on its order of sorting
rules: {
- '@typescript-eslint/no-explicit-any': ['off'],
- '@typescript-eslint/explicit-function-return-type': [
- 'error',
- {
- allowExpressions: true,
- },
- ],
- '@typescript-eslint/explicit-module-boundary-types': [
- 'error',
- {
- allowArgumentsExplicitlyTypedAsAny: true,
- },
- ],
+ 'simple-import-sort/imports': 'off',
+ 'simple-import-sort/exports': 'off',
},
},
{
files: ['*.js'],
rules: {
'@typescript-eslint/no-var-requires': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
},
},
{
files: 'eslint-rules/**/*',
- extends: ['eslint:recommended'],
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml
index 3411304b8795a..2ea70218bd608 100644
--- a/.github/workflows/ci-frontend.yml
+++ b/.github/workflows/ci-frontend.yml
@@ -2,10 +2,6 @@ name: Frontend CI
on:
pull_request:
- # NOTE: by running on master, aside from highlight issues on master it also
- # ensures we have e.g. node modules cached for master, which can then be
- # used for branches. See https://github.com/actions/cache#cache-scopes for
- # scope details.
push:
branches:
- master
@@ -15,28 +11,71 @@ concurrency:
cancel-in-progress: true
jobs:
+ # Job to decide if we should run frontend ci
+ # See https://github.com/dorny/paths-filter#conditional-execution for more details
+ # we skip each step individually, so they are still reported as success
+ # because many of them are required for CI checks to be green
+ changes:
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ name: Determine need to run frontend checks
+ outputs:
+ frontend: ${{ steps.filter.outputs.frontend }}
+ steps:
+ # For pull requests it's not necessary to check out the code, but we
+ # also want this to run on master, so we need to check out
+ - uses: actions/checkout@v3
+
+ - uses: dorny/paths-filter@v2
+ id: filter
+ with:
+ filters: |
+ frontend:
+ # Avoid running frontend tests for irrelevant changes
+ # NOTE: we are at risk of missing a dependency here.
+ - 'bin/**'
+ - 'frontend/**'
+ # Make sure we run if someone is explicitly change the workflow
+ - .github/workflows/ci-frontend.yml
+ # various JS config files
+ - .eslintrc.js
+ - .prettier*
+ - babel.config.js
+ - jest.*.ts
+ - tsconfig.json
+ - tsconfig.*.json
+ - webpack.config.js
+ - postcss.config.js
+ - stylelint*
+
frontend-code-quality:
name: Code quality checks
+ needs: changes
# kea typegen and typescript:check need some more oomph
runs-on: ubuntu-latest
steps:
+ # we need at least one thing to run to make sure we include everything for required jobs
- uses: actions/checkout@v3
- name: Install pnpm
+ if: needs.changes.outputs.frontend == 'true'
uses: pnpm/action-setup@v2
with:
version: 8.x.x
- name: Set up Node.js
- uses: buildjet/setup-node@v3
+ if: needs.changes.outputs.frontend == 'true'
+ uses: actions/setup-node@v3
with:
node-version: 18
- name: Get pnpm cache directory path
+ if: needs.changes.outputs.frontend == 'true'
id: pnpm-cache-dir
run: echo "PNPM_STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
+ if: needs.changes.outputs.frontend == 'true'
id: pnpm-cache
with:
path: ${{ steps.pnpm-cache-dir.outputs.PNPM_STORE_PATH }}
@@ -44,22 +83,40 @@ jobs:
restore-keys: ${{ runner.os }}-pnpm-cypress-
- name: Install package.json dependencies with pnpm
+ if: needs.changes.outputs.frontend == 'true'
run: pnpm install --frozen-lockfile
- name: Check formatting with prettier
+ if: needs.changes.outputs.frontend == 'true'
run: pnpm prettier:check
- - name: Lint with ESLint
- run: pnpm eslint
+ - name: Lint with Stylelint
+ if: needs.changes.outputs.frontend == 'true'
+ run: pnpm lint:css
- name: Generate logic types and run typescript with strict
+ if: needs.changes.outputs.frontend == 'true'
run: pnpm typegen:write && pnpm typescript:check
+ - name: Lint with ESLint
+ if: needs.changes.outputs.frontend == 'true'
+ run: pnpm lint:js
+
- name: Check if "schema.json" is up to date
+ if: needs.changes.outputs.frontend == 'true'
run: pnpm schema:build:json && git diff --exit-code
+ - name: Check toolbar bundle size
+ if: needs.changes.outputs.frontend == 'true'
+ uses: preactjs/compressed-size-action@v2
+ with:
+ build-script: 'build'
+ compression: 'none'
+ pattern: 'frontend/dist/toolbar.js'
+
jest:
runs-on: ubuntu-latest
+ needs: changes
name: Jest test (${{ matrix.chunk }})
strategy:
@@ -69,24 +126,29 @@ jobs:
chunk: [1, 2, 3]
steps:
+ # we need at least one thing to run to make sure we include everything for required jobs
- uses: actions/checkout@v3
- name: Install pnpm
+ if: needs.changes.outputs.frontend == 'true'
uses: pnpm/action-setup@v2
with:
version: 8.x.x
- name: Set up Node.js
- uses: buildjet/setup-node@v3
+ if: needs.changes.outputs.frontend == 'true'
+ uses: actions/setup-node@v3
with:
node-version: 18
cache: pnpm
- name: Install package.json dependencies with pnpm
+ if: needs.changes.outputs.frontend == 'true'
run: pnpm install --frozen-lockfile
- name: Test with Jest
# set maxWorkers or Jest only uses 1 CPU in GitHub Actions
run: pnpm test:unit --maxWorkers=2 --shard=${{ matrix.chunk }}/3
+ if: needs.changes.outputs.frontend == 'true'
env:
NODE_OPTIONS: --max-old-space-size=6144
diff --git a/.github/workflows/storybook-chromatic.yml b/.github/workflows/storybook-chromatic.yml
index 02397ca2586db..9ae51e2933067 100644
--- a/.github/workflows/storybook-chromatic.yml
+++ b/.github/workflows/storybook-chromatic.yml
@@ -144,6 +144,7 @@ jobs:
HOME: /root
# Update snapshots for PRs on the main repo, verify on forks, which don't have access to PostHog Bot
VARIANT: ${{ github.event.pull_request.head.repo.full_name == github.repository && 'update' || 'verify' }}
+ STORYBOOK_SKIP_TAGS: 'test-skip,test-skip-${{ matrix.browser }}'
run: |
pnpm test:visual-regression:stories:ci:$VARIANT --browsers ${{ matrix.browser }} --shard ${{ matrix.shard }}/$SHARD_COUNT
diff --git a/.run/Dev.run.xml b/.run/Dev.run.xml
new file mode 100644
index 0000000000000..8e0efc8b0e7b3
--- /dev/null
+++ b/.run/Dev.run.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.storybook/decorators/withSnapshotsDisabled.tsx b/.storybook/decorators/withSnapshotsDisabled.tsx
deleted file mode 100644
index 6e7598c7a9c7e..0000000000000
--- a/.storybook/decorators/withSnapshotsDisabled.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Decorator } from '@storybook/react'
-import { inStorybookTestRunner } from 'lib/utils'
-
-/** Workaround for https://github.com/storybookjs/test-runner/issues/74 */
-// TODO: Smoke-test all the stories by removing this decorator, once all the stories pass
-export const withSnapshotsDisabled: Decorator = (Story, { parameters }) => {
- if (parameters?.testOptions?.skip && inStorybookTestRunner()) {
- return <>Disabled for Test Runner>
- }
- return
-}
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index 091884046929e..fe45ae823c620 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -8,7 +8,6 @@ import { getStorybookAppContext } from './app-context'
import { withKea } from './decorators/withKea'
import { withMockDate } from './decorators/withMockDate'
import { defaultMocks } from '~/mocks/handlers'
-import { withSnapshotsDisabled } from './decorators/withSnapshotsDisabled'
import { withFeatureFlags } from './decorators/withFeatureFlags'
import { withTheme } from './decorators/withTheme'
@@ -79,7 +78,6 @@ export const parameters: Parameters = {
// Setup storybook global decorators. See https://storybook.js.org/docs/react/writing-stories/decorators#global-decorators
export const decorators: Meta['decorators'] = [
- withSnapshotsDisabled,
// Make sure the msw service worker is started, and reset the handlers to defaults.
withKea,
// Allow us to time travel to ensure our stories don't change over time.
diff --git a/.storybook/test-runner.ts b/.storybook/test-runner.ts
index 8decd13e17a65..0ec91135cda24 100644
--- a/.storybook/test-runner.ts
+++ b/.storybook/test-runner.ts
@@ -13,11 +13,6 @@ declare module '@storybook/types' {
options?: any
layout?: 'padded' | 'fullscreen' | 'centered'
testOptions?: {
- /**
- * Whether the test should be a no-op (doesn't jest.skip as @storybook/test-runner doesn't allow that).
- * @default false
- */
- skip?: boolean
/**
* Whether we should wait for all loading indicators to disappear before taking a snapshot.
* @default true
@@ -71,19 +66,20 @@ module.exports = {
jest.retryTimes(RETRY_TIMES, { logErrorsBeforeRetry: true })
jest.setTimeout(JEST_TIMEOUT_MS)
},
- async postRender(page, context) {
+ async postVisit(page, context) {
const browserContext = page.context()
const storyContext = (await getStoryContext(page, context)) as StoryContext
- const { skip = false, snapshotBrowsers = ['chromium'] } = storyContext.parameters?.testOptions ?? {}
+ const { snapshotBrowsers = ['chromium'] } = storyContext.parameters?.testOptions ?? {}
browserContext.setDefaultTimeout(PLAYWRIGHT_TIMEOUT_MS)
- if (!skip) {
- const currentBrowser = browserContext.browser()!.browserType().name() as SupportedBrowserName
- if (snapshotBrowsers.includes(currentBrowser)) {
- await expectStoryToMatchSnapshot(page, context, storyContext, currentBrowser)
- }
+ const currentBrowser = browserContext.browser()!.browserType().name() as SupportedBrowserName
+ if (snapshotBrowsers.includes(currentBrowser)) {
+ await expectStoryToMatchSnapshot(page, context, storyContext, currentBrowser)
}
},
+ tags: {
+ skip: ['test-skip'], // NOTE: This is overridden by the CI action storybook-chromatic.yml to include browser specific skipping
+ },
} as TestRunnerConfig
async function expectStoryToMatchSnapshot(
diff --git a/.stylelintignore b/.stylelintignore
new file mode 100644
index 0000000000000..46b4d2996945c
--- /dev/null
+++ b/.stylelintignore
@@ -0,0 +1 @@
+frontend/dist/
diff --git a/.stylelintrc.js b/.stylelintrc.js
new file mode 100644
index 0000000000000..19bbc999f0f51
--- /dev/null
+++ b/.stylelintrc.js
@@ -0,0 +1,49 @@
+module.exports = {
+ extends: 'stylelint-config-standard-scss', // TODO: Enable separately, as the diff will be significant
+ // TODO: Enable separately, as the diff will be significant "plugins": ["stylelint-order"],
+ rules: {
+ 'no-descending-specificity': null,
+ 'number-max-precision': 5,
+ 'value-keyword-case': [
+ 'lower',
+ {
+ // CSS Color Module Level 3 says currentColor, Level 4 candidate says currentcolor
+ // Sticking to Level 3 for now
+ camelCaseSvgKeywords: true,
+ ignoreKeywords: ['BlinkMacSystemFont'], // BlinkMacSystemFont MUST have this particular casing
+ },
+ ],
+ // Sadly Safari only started supporting the range syntax of media queries in 2023, so let's switch to that
+ // ('context' value) in 2024, once support is better https://caniuse.com/?search=range%20context
+ 'media-feature-range-notation': 'prefix',
+ 'selector-class-pattern': [
+ '^[A-Za-z0-9_-]+(__[A-Za-z0-9_-]+)?(--[A-Za-z0-9-]+)?$',
+ {
+ message: 'Expected class selector to match Block__Element--Modifier or plain snake-case',
+ },
+ ],
+ 'selector-id-pattern': [
+ '^[A-Za-z0-9_-]+(__[A-Za-z0-9_-]+)?(--[A-Za-z0-9_-]+)?$',
+ {
+ message: 'Expected id selector to match Block__Element--Modifier or plain kebak-case',
+ },
+ ],
+ 'keyframes-name-pattern': [
+ '^[A-Za-z0-9_-]+__[A-Za-z0-9_-]+$',
+ {
+ message: 'Expected keyframe name to match Block__Animation',
+ },
+ ],
+ 'scss/dollar-variable-pattern': [
+ '^[A-Za-z_]+[A-Za-z0-9_-]+$',
+ {
+ message: 'Expected variable to match kebab-case or snake_case',
+ },
+ ],
+ 'scss/operator-no-newline-after': null, // Doesn't always play well with prettier
+ 'scss/at-extend-no-missing-placeholder': null,
+ 'scss/comment-no-empty': null,
+ // "order/order": ["dollar-variables", "custom-properties", "declarations", "rules", "at-rules"],
+ // "order/properties-order": ["width", "height"],
+ },
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9ed14cbd01cc..4047d14a6106b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,3 @@
# Changelog
-Updates to the PostHog project can be found on [https://posthog.com/changelog](our changelog).
\ No newline at end of file
+Updates to the PostHog project can be found on [our changelog](https://posthog.com/changelog).
diff --git a/cypress/e2e/actions.cy.ts b/cypress/e2e/actions.cy.ts
index 9819b7d02cdab..356607c64bf8f 100644
--- a/cypress/e2e/actions.cy.ts
+++ b/cypress/e2e/actions.cy.ts
@@ -5,7 +5,7 @@ const createAction = (actionName: string): void => {
cy.get('[data-attr=action-name-create]').should('exist')
cy.get('[data-attr=action-name-create]').type(actionName)
- cy.get('.ant-radio-group > :nth-child(3)').click()
+ cy.get('.LemonSegmentedButton > ul > :nth-child(3)').click()
cy.get('[data-attr=edit-action-url-input]').click().type(Cypress.config().baseUrl)
cy.get('[data-attr=save-action-button]').click()
diff --git a/cypress/e2e/billingv2.cy.ts b/cypress/e2e/billingv2.cy.ts
index 3c01f489e1f78..5fa21e7b99d2f 100644
--- a/cypress/e2e/billingv2.cy.ts
+++ b/cypress/e2e/billingv2.cy.ts
@@ -9,12 +9,14 @@ describe('Billing', () => {
cy.intercept('/api/billing-v2/deactivate?products=product_analytics', {
fixture: 'api/billing-v2/billing-v2-unsubscribed-product-analytics.json',
}).as('unsubscribeProductAnalytics')
+
cy.get('[data-attr=more-button]').first().click()
cy.contains('.LemonButton', 'Unsubscribe').click()
cy.get('.LemonModal__content h3').should(
'contain',
'Why are you unsubscribing from Product analytics + data stack?'
)
+ cy.get('[data-attr=unsubscribe-reason-survey-textarea]').type('Product analytics')
cy.contains('.LemonModal .LemonButton', 'Unsubscribe').click()
cy.get('.LemonModal').should('not.exist')
diff --git a/cypress/e2e/early-access-management.cy.ts b/cypress/e2e/early-access-management.cy.ts
index 9a594d8d1c34c..8736a39ab945a 100644
--- a/cypress/e2e/early-access-management.cy.ts
+++ b/cypress/e2e/early-access-management.cy.ts
@@ -6,7 +6,7 @@ describe('Early Access Management', () => {
it('Early access feature new and list', () => {
// load an empty early access feature page
cy.get('h1').should('contain', 'Early Access Management')
- cy.title().should('equal', 'Early Access Management • PostHog')
+ cy.title().should('equal', 'Early access features • PostHog')
cy.get('h2').should('contain', 'Create your first feature')
cy.get('[data-attr="product-introduction-docs-link"]').should(
'contain',
diff --git a/cypress/e2e/featureFlags.cy.ts b/cypress/e2e/featureFlags.cy.ts
index 9045a51a4f485..bf37822321ad1 100644
--- a/cypress/e2e/featureFlags.cy.ts
+++ b/cypress/e2e/featureFlags.cy.ts
@@ -48,6 +48,7 @@ describe('Feature Flags', () => {
cy.get('[data-attr=save-feature-flag]').first().click()
// after save there should be a delete button
+ cy.get('[data-attr="more-button"]').click()
cy.get('button[data-attr="delete-feature-flag"]').should('have.text', 'Delete feature flag')
// make sure the data is there as expected after a page reload!
@@ -83,11 +84,13 @@ describe('Feature Flags', () => {
cy.get('[data-attr=save-feature-flag]').first().click()
// after save there should be a delete button
+ cy.get('[data-attr="more-button"]').click()
cy.get('button[data-attr="delete-feature-flag"]').should('have.text', 'Delete feature flag')
cy.clickNavMenu('featureflags')
cy.get('[data-attr=feature-flag-table]').should('contain', name)
cy.get(`[data-row-key=${name}]`).contains(name).click()
+ cy.get('[data-attr="more-button"]').click()
cy.get('[data-attr=delete-feature-flag]').click()
cy.get('.Toastify').contains('Undo').should('be.visible')
})
diff --git a/cypress/e2e/insights-navigation-open-directly.cy.ts b/cypress/e2e/insights-navigation-open-directly.cy.ts
index 406445d9f6636..4eec9fcd7aba7 100644
--- a/cypress/e2e/insights-navigation-open-directly.cy.ts
+++ b/cypress/e2e/insights-navigation-open-directly.cy.ts
@@ -30,7 +30,7 @@ describe('Insights', () => {
describe('opening a new insight directly', () => {
it('can open a new trends insight', () => {
insight.newInsight('TRENDS')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
})
@@ -52,12 +52,12 @@ describe('Insights', () => {
it('can open a new stickiness insight', () => {
insight.newInsight('STICKINESS')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
})
it('can open a new lifecycle insight', () => {
insight.newInsight('LIFECYCLE')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
})
it('can open a new SQL insight', () => {
diff --git a/cypress/e2e/insights-navigation-open-sql-insight-first.cy.ts b/cypress/e2e/insights-navigation-open-sql-insight-first.cy.ts
index ca286d2e7c765..2b03880515ece 100644
--- a/cypress/e2e/insights-navigation-open-sql-insight-first.cy.ts
+++ b/cypress/e2e/insights-navigation-open-sql-insight-first.cy.ts
@@ -42,7 +42,7 @@ describe('Insights', () => {
it('can open a new trends insight', () => {
insight.clickTab('TRENDS')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
})
@@ -65,12 +65,12 @@ describe('Insights', () => {
it('can open a new stickiness insight', () => {
insight.clickTab('STICKINESS')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
})
it('can open a new lifecycle insight', () => {
insight.clickTab('LIFECYCLE')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
})
it('can open a new SQL insight', () => {
diff --git a/cypress/e2e/insights-navigation.cy.ts b/cypress/e2e/insights-navigation.cy.ts
index 7adf79c284cba..a3526833bee81 100644
--- a/cypress/e2e/insights-navigation.cy.ts
+++ b/cypress/e2e/insights-navigation.cy.ts
@@ -62,7 +62,7 @@ describe('Insights', () => {
cy.get('.DataTable tr').should('have.length.gte', 2)
insight.clickTab('TRENDS')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
@@ -73,7 +73,7 @@ describe('Insights', () => {
cy.get('.DataTable tr').should('have.length.gte', 2)
insight.clickTab('TRENDS')
- cy.get('.trends-insights-container canvas').should('exist')
+ cy.get('.TrendsInsight canvas').should('exist')
cy.get('tr').should('have.length.gte', 2)
cy.contains('tr', 'No insight results').should('not.exist')
})
diff --git a/cypress/e2e/insights.cy.ts b/cypress/e2e/insights.cy.ts
index 0e449825b2194..80b1c06c4398e 100644
--- a/cypress/e2e/insights.cy.ts
+++ b/cypress/e2e/insights.cy.ts
@@ -1,7 +1,8 @@
import { urls } from 'scenes/urls'
-import { randomString } from '../support/random'
+
import { decideResponse } from '../fixtures/api/decide'
-import { savedInsights, createInsight, insight } from '../productAnalytics'
+import { createInsight, insight, savedInsights } from '../productAnalytics'
+import { randomString } from '../support/random'
// For tests related to trends please check trendsElements.js
// insight tests were split up because Cypress was struggling with this many tests in one file🙈
@@ -24,7 +25,7 @@ describe('Insights', () => {
cy.get('[data-attr=breadcrumb-0]').should('contain', 'Hogflix')
cy.get('[data-attr=breadcrumb-1]').should('contain', 'Hogflix Demo App')
- cy.get('[data-attr=breadcrumb-2]').should('have.text', 'Insights')
+ cy.get('[data-attr=breadcrumb-2]').should('have.text', 'Product analytics')
cy.get('[data-attr=breadcrumb-3]').should('have.text', 'insight name')
})
diff --git a/docker/clickhouse/config.xml b/docker/clickhouse/config.xml
index f3f858be7d117..7047c93e5c5d8 100644
--- a/docker/clickhouse/config.xml
+++ b/docker/clickhouse/config.xml
@@ -20,17 +20,20 @@
- trace
- test (not for production usage)
- [1]: https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
+ [1]:
+ https://github.com/pocoproject/poco/blob/poco-1.9.4-release/Foundation/include/Poco/Logger.h#L105-L114
-->
trace/var/log/clickhouse-server/clickhouse-server.log/var/log/clickhouse-server/clickhouse-server.err.log1000M10
-
+
-
+
@@ -217,7 +225,8 @@
/path/to/ssl_ca_cert_file
-
none
@@ -232,10 +241,12 @@
false
-
+
-
+
/etc/clickhouse-server/server.crt/etc/clickhouse-server/server.key
+ truetruesslv2,sslv3
@@ -264,24 +276,30 @@
-
+
1000
@@ -302,21 +320,25 @@
-->
0.9
-
4194304
-
0
-
@@ -341,14 +363,18 @@
-
-
-
+
true
@@ -644,14 +698,16 @@
-
+
localhost9000
-
+
@@ -666,22 +722,28 @@
Example: "yandex.ru", "yandex.ru." and "www.yandex.ru" are different hosts.
If port is explicitly specified in URL, the host:port is checked as a whole.
If host specified here without port, any port with this host allowed.
- "yandex.ru" -> "yandex.ru:443", "yandex.ru:80" etc. is allowed, but "yandex.ru:80" -> only "yandex.ru:80" is allowed.
- If the host is specified as IP address, it is checked as specified in URL. Example: "[2a02:6b8:a::a]".
- If there are redirects and support for redirects is enabled, every redirect (the Location field) is checked.
+ "yandex.ru" -> "yandex.ru:443", "yandex.ru:80" etc. is allowed, but "yandex.ru:80" -> only
+ "yandex.ru:80" is allowed.
+ If the host is specified as IP address, it is checked as specified in URL. Example:
+ "[2a02:6b8:a::a]".
+ If there are redirects and support for redirects is enabled, every redirect (the Location field) is
+ checked.
Host should be specified using the host xml tag:
yandex.ru
-->
.*
-
@@ -701,7 +763,8 @@
@@ -710,7 +773,6 @@
-
3600
@@ -788,7 +850,8 @@
system
query_log
toYYYYMM(event_date)
-
@@ -843,7 +909,8 @@
+ Part log contains information about all actions with parts in MergeTree tables (creation, deletion,
+ merges, downloads).-->
system
part_log
@@ -852,8 +919,10 @@
-
+
system
metric_log
@@ -933,7 +1003,8 @@
-->
-
+
@@ -965,12 +1036,14 @@
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1032,7 +1107,8 @@
-
+
/var/lib/clickhouse/format_schemas/
-
false
-
+
false
-
+
https://6f33034cfe684dd7a3ab9875e57b1c8d@o388870.ingest.sentry.io/5226277
@@ -1183,4 +1267,4 @@
-->
-
+
\ No newline at end of file
diff --git a/docker/clickhouse/users-dev.xml b/docker/clickhouse/users-dev.xml
index dd6e54d7c5de3..704e99ef9e961 100644
--- a/docker/clickhouse/users-dev.xml
+++ b/docker/clickhouse/users-dev.xml
@@ -15,7 +15,8 @@
with minimum number of different symbols between replica's hostname and local hostname
(Hamming distance).
in_order - first live replica is chosen in specified order.
- first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
+ first_or_random - if first replica one has higher number of errors, pick a random one from replicas
+ with minimum number of errors.
-->
random
@@ -45,30 +46,39 @@
Password could be empty.
If you want to specify SHA256, place it in 'password_sha256_hex' element.
- Example: 65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5
- Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
+ Example:
+ 65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5
+ Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July
+ 2019).
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
- Example: e395796d6546b1b65db9d665cd43f0e858dd4303
+ Example:
+ e395796d6546b1b65db9d665cd43f0e858dd4303
- If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for authentication,
+ If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for
+ authentication,
place its name in 'server' element inside 'ldap' element.
Example: my_ldap_server
- If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in the main config),
+ If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in
+ the main config),
place 'kerberos' element instead of 'password' (and similar) elements.
- The name part of the canonical principal name of the initiator must match the user name for authentication to succeed.
- You can also place 'realm' element inside 'kerberos' element to further restrict authentication to only those requests
+ The name part of the canonical principal name of the initiator must match the user name for
+ authentication to succeed.
+ You can also place 'realm' element inside 'kerberos' element to further restrict authentication to
+ only those requests
whose initiator's realm matches it.
Example:
Example: EXAMPLE.COM
How to generate decent password:
- Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
+ Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" |
+ sha256sum | tr -d '-'
In first line will be password and in second - corresponding SHA256.
How to generate double SHA1:
- Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
+ Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" |
+ sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
In first line will be password and in second - corresponding double SHA1.
-->
@@ -89,7 +99,8 @@
To check access, DNS query is performed, and all received addresses compared to peer address.
Regular expression for host names. Example, ^server\d\d-\d\d-\d\.yandex\.ru$
To check access, DNS PTR query is performed for peer address and then regexp is applied.
- Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
+ Then, for result of PTR query, another DNS query is performed and all received addresses compared
+ to peer address.
Strongly recommended that regexp is ends with $
All results of DNS requests are cached till server restart.
-->
@@ -126,4 +137,4 @@
-
+
\ No newline at end of file
diff --git a/docker/clickhouse/users.xml b/docker/clickhouse/users.xml
index 49ac9f73e0de5..ece3df0f09fbe 100644
--- a/docker/clickhouse/users.xml
+++ b/docker/clickhouse/users.xml
@@ -15,7 +15,8 @@
with minimum number of different symbols between replica's hostname and local hostname
(Hamming distance).
in_order - first live replica is chosen in specified order.
- first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
+ first_or_random - if first replica one has higher number of errors, pick a random one from replicas
+ with minimum number of errors.
-->
random
@@ -43,30 +44,39 @@
Password could be empty.
If you want to specify SHA256, place it in 'password_sha256_hex' element.
- Example: 65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5
- Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
+ Example:
+ 65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5
+ Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July
+ 2019).
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
- Example: e395796d6546b1b65db9d665cd43f0e858dd4303
+ Example:
+ e395796d6546b1b65db9d665cd43f0e858dd4303
- If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for authentication,
+ If you want to specify a previously defined LDAP server (see 'ldap_servers' in the main config) for
+ authentication,
place its name in 'server' element inside 'ldap' element.
Example: my_ldap_server
- If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in the main config),
+ If you want to authenticate the user via Kerberos (assuming Kerberos is enabled, see 'kerberos' in
+ the main config),
place 'kerberos' element instead of 'password' (and similar) elements.
- The name part of the canonical principal name of the initiator must match the user name for authentication to succeed.
- You can also place 'realm' element inside 'kerberos' element to further restrict authentication to only those requests
+ The name part of the canonical principal name of the initiator must match the user name for
+ authentication to succeed.
+ You can also place 'realm' element inside 'kerberos' element to further restrict authentication to
+ only those requests
whose initiator's realm matches it.
Example:
Example: EXAMPLE.COM
How to generate decent password:
- Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
+ Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" |
+ sha256sum | tr -d '-'
In first line will be password and in second - corresponding SHA256.
How to generate double SHA1:
- Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
+ Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" |
+ sha1sum | tr -d '-' | xxd -r -p | sha1sum | tr -d '-'
In first line will be password and in second - corresponding double SHA1.
-->
@@ -87,7 +97,8 @@
To check access, DNS query is performed, and all received addresses compared to peer address.
Regular expression for host names. Example, ^server\d\d-\d\d-\d\.yandex\.ru$
To check access, DNS PTR query is performed for peer address and then regexp is applied.
- Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
+ Then, for result of PTR query, another DNS query is performed and all received addresses compared
+ to peer address.
Strongly recommended that regexp is ends with $
All results of DNS requests are cached till server restart.
-->
@@ -124,4 +135,4 @@
-
+
\ No newline at end of file
diff --git a/ee/api/feature_flag_role_access.py b/ee/api/feature_flag_role_access.py
index d3ca7a68c1a32..3ce77dca89599 100644
--- a/ee/api/feature_flag_role_access.py
+++ b/ee/api/feature_flag_role_access.py
@@ -35,7 +35,11 @@ def has_permission(self, request, view):
return True
try:
feature_flag: FeatureFlag = FeatureFlag.objects.get(id=view.parents_query_dict["feature_flag_id"])
- if feature_flag.created_by.uuid == request.user.uuid:
+ if (
+ hasattr(feature_flag, "created_by")
+ and feature_flag.created_by
+ and feature_flag.created_by.uuid == request.user.uuid
+ ):
return True
except FeatureFlag.DoesNotExist:
raise exceptions.NotFound("Feature flag not found.")
diff --git a/ee/api/test/test_billing.py b/ee/api/test/test_billing.py
index 87838d0b39dcc..c37c3ee9d6482 100644
--- a/ee/api/test/test_billing.py
+++ b/ee/api/test/test_billing.py
@@ -2,9 +2,9 @@
from typing import Any, Dict, List
from unittest.mock import MagicMock, patch
from uuid import uuid4
+from zoneinfo import ZoneInfo
import jwt
-from zoneinfo import ZoneInfo
from dateutil.relativedelta import relativedelta
from django.utils.timezone import now
from freezegun import freeze_time
@@ -43,6 +43,7 @@ def create_missing_billing_customer(**kwargs) -> CustomerInfo:
usage_summary={
"events": {"limit": None, "usage": 0},
"recordings": {"limit": None, "usage": 0},
+ "rows_synced": {"limit": None, "usage": 0},
},
free_trial_until=None,
available_features=[],
@@ -96,6 +97,7 @@ def create_billing_customer(**kwargs) -> CustomerInfo:
usage_summary={
"events": {"limit": None, "usage": 0},
"recordings": {"limit": None, "usage": 0},
+ "rows_synced": {"limit": None, "usage": 0},
},
free_trial_until=None,
)
@@ -292,6 +294,7 @@ def mock_implementation(url: str, headers: Any = None, params: Any = None) -> Ma
"usage_summary": {
"events": {"limit": None, "usage": 0},
"recordings": {"limit": None, "usage": 0},
+ "rows_synced": {"limit": None, "usage": 0},
},
"free_trial_until": None,
}
@@ -363,6 +366,7 @@ def mock_implementation(url: str, headers: Any = None, params: Any = None) -> Ma
"usage_summary": {
"events": {"limit": None, "usage": 0},
"recordings": {"limit": None, "usage": 0},
+ "rows_synced": {"limit": None, "usage": 0},
},
"free_trial_until": None,
"current_total_amount_usd": "0.00",
@@ -521,6 +525,11 @@ def mock_implementation(url: str, headers: Any = None, params: Any = None) -> Ma
"todays_usage": 0,
"usage": 0,
},
+ "rows_synced": {
+ "limit": None,
+ "todays_usage": 0,
+ "usage": 0,
+ },
"period": ["2022-10-07T11:12:48", "2022-11-07T11:12:48"],
}
@@ -556,6 +565,11 @@ def mock_implementation_missing_customer(url: str, headers: Any = None, params:
"todays_usage": 0,
"usage": 0,
},
+ "rows_synced": {
+ "limit": None,
+ "todays_usage": 0,
+ "usage": 0,
+ },
"period": ["2022-10-07T11:12:48", "2022-11-07T11:12:48"],
}
assert self.organization.customer_id == "cus_123"
@@ -613,5 +627,6 @@ def mock_implementation(url: str, headers: Any = None, params: Any = None) -> Ma
assert self.organization.usage == {
"events": {"limit": None, "usage": 0, "todays_usage": 0},
"recordings": {"limit": None, "usage": 0, "todays_usage": 0},
+ "rows_synced": {"limit": None, "usage": 0, "todays_usage": 0},
"period": ["2022-10-07T11:12:48", "2022-11-07T11:12:48"],
}
diff --git a/ee/api/test/test_feature_flag_role_access.py b/ee/api/test/test_feature_flag_role_access.py
index f143f10505f0f..3cd4e947d90c9 100644
--- a/ee/api/test/test_feature_flag_role_access.py
+++ b/ee/api/test/test_feature_flag_role_access.py
@@ -37,6 +37,26 @@ def test_can_always_add_role_access_if_creator_of_feature_flag(self):
self.assertEqual(flag_role.role.name, self.eng_role.name)
self.assertEqual(flag_role.feature_flag.id, self.feature_flag.id)
+ def test_role_access_with_deleted_creator_of_feature_flag(self):
+ OrganizationResourceAccess.objects.create(
+ resource=OrganizationResourceAccess.Resources.FEATURE_FLAGS,
+ access_level=OrganizationResourceAccess.AccessLevel.CAN_ONLY_VIEW,
+ organization=self.organization,
+ )
+
+ flag = FeatureFlag.objects.create(
+ created_by=None,
+ team=self.team,
+ key="flag_role_access_none",
+ name="Flag role access",
+ )
+ self.assertEqual(self.user.role_memberships.count(), 0)
+ flag_role_access_create_res = self.client.post(
+ f"/api/projects/@current/feature_flags/{flag.id}/role_access",
+ {"role_id": self.eng_role.id},
+ )
+ self.assertEqual(flag_role_access_create_res.status_code, status.HTTP_403_FORBIDDEN)
+
def test_cannot_add_role_access_if_feature_flags_access_level_too_low_and_not_creator(self):
OrganizationResourceAccess.objects.create(
resource=OrganizationResourceAccess.Resources.FEATURE_FLAGS,
diff --git a/ee/api/test/test_organization.py b/ee/api/test/test_organization.py
index 2f1b11bb95256..a77361dc579e8 100644
--- a/ee/api/test/test_organization.py
+++ b/ee/api/test/test_organization.py
@@ -1,6 +1,7 @@
import datetime as dt
import random
-from unittest.mock import ANY, patch
+from unittest import mock
+from unittest.mock import ANY, call, patch
from freezegun.api import freeze_time
from rest_framework import status
@@ -104,11 +105,21 @@ def test_delete_last_organization(self, mock_capture):
"Did not return a 404 on trying to delete a nonexistent org",
)
- mock_capture.assert_called_once_with(
- self.user.distinct_id,
- "organization deleted",
- organization_props,
- groups={"instance": ANY, "organization": str(org_id)},
+ mock_capture.assert_has_calls(
+ [
+ call(
+ self.user.distinct_id,
+ "membership level changed",
+ properties={"new_level": 15, "previous_level": 1},
+ groups=mock.ANY,
+ ),
+ call(
+ self.user.distinct_id,
+ "organization deleted",
+ organization_props,
+ groups={"instance": mock.ANY, "organization": str(org_id)},
+ ),
+ ]
)
def test_no_delete_organization_not_owning(self):
diff --git a/ee/billing/billing_manager.py b/ee/billing/billing_manager.py
index c626083460ef4..324b158fe071d 100644
--- a/ee/billing/billing_manager.py
+++ b/ee/billing/billing_manager.py
@@ -6,6 +6,7 @@
import structlog
from django.utils import timezone
from rest_framework.exceptions import NotAuthenticated
+from sentry_sdk import capture_exception
from ee.billing.billing_types import BillingStatus
from ee.billing.quota_limiting import set_org_usage_summary, sync_org_quota_limits
@@ -13,7 +14,7 @@
from ee.settings import BILLING_SERVICE_URL
from posthog.cloud_utils import get_cached_instance_license
from posthog.models import Organization
-from posthog.models.organization import OrganizationUsageInfo
+from posthog.models.organization import OrganizationMembership, OrganizationUsageInfo
logger = structlog.get_logger(__name__)
@@ -114,6 +115,14 @@ def update_billing_distinct_ids(self, organization: Organization) -> None:
distinct_ids = list(organization.members.values_list("distinct_id", flat=True))
self.update_billing(organization, {"distinct_ids": distinct_ids})
+ def update_billing_customer_email(self, organization: Organization) -> None:
+ try:
+ owner_membership = OrganizationMembership.objects.get(organization=organization, level=15)
+ user = owner_membership.user
+ self.update_billing(organization, {"org_customer_email": user.email})
+ except Exception as e:
+ capture_exception(e)
+
def deactivate_products(self, organization: Organization, products: str) -> None:
res = requests.get(
f"{BILLING_SERVICE_URL}/api/billing/deactivate?products={products}",
@@ -225,6 +234,7 @@ def update_org_details(self, organization: Organization, billing_status: Billing
usage_info = OrganizationUsageInfo(
events=usage_summary["events"],
recordings=usage_summary["recordings"],
+ rows_synced=usage_summary.get("rows_synced", None),
period=[
data["billing_period"]["current_period_start"],
data["billing_period"]["current_period_end"],
diff --git a/ee/billing/quota_limiting.py b/ee/billing/quota_limiting.py
index ae6eefcc0b77a..ef3e12a421575 100644
--- a/ee/billing/quota_limiting.py
+++ b/ee/billing/quota_limiting.py
@@ -17,6 +17,7 @@
convert_team_usage_rows_to_dict,
get_teams_with_billable_event_count_in_period,
get_teams_with_recording_count_in_period,
+ get_teams_with_rows_synced_in_period,
)
from posthog.utils import get_current_day
@@ -26,11 +27,13 @@
class QuotaResource(Enum):
EVENTS = "events"
RECORDINGS = "recordings"
+ ROWS_SYNCED = "rows_synced"
OVERAGE_BUFFER = {
QuotaResource.EVENTS: 0,
QuotaResource.RECORDINGS: 1000,
+ QuotaResource.ROWS_SYNCED: 0,
}
@@ -53,7 +56,7 @@ def remove_limited_team_tokens(resource: QuotaResource, tokens: List[str]) -> No
@cache_for(timedelta(seconds=30), background_refresh=True)
-def list_limited_team_tokens(resource: QuotaResource) -> List[str]:
+def list_limited_team_attributes(resource: QuotaResource) -> List[str]:
now = timezone.now()
redis_client = get_client()
results = redis_client.zrangebyscore(f"{QUOTA_LIMITER_CACHE_KEY}{resource.value}", min=now.timestamp(), max="+inf")
@@ -63,6 +66,7 @@ def list_limited_team_tokens(resource: QuotaResource) -> List[str]:
class UsageCounters(TypedDict):
events: int
recordings: int
+ rows_synced: int
def org_quota_limited_until(organization: Organization, resource: QuotaResource) -> Optional[int]:
@@ -70,6 +74,8 @@ def org_quota_limited_until(organization: Organization, resource: QuotaResource)
return None
summary = organization.usage.get(resource.value, {})
+ if not summary:
+ return None
usage = summary.get("usage", 0)
todays_usage = summary.get("todays_usage", 0)
limit = summary.get("limit")
@@ -93,19 +99,34 @@ def sync_org_quota_limits(organization: Organization):
if not organization.usage:
return None
- team_tokens: List[str] = [x for x in list(organization.teams.values_list("api_token", flat=True)) if x]
-
- if not team_tokens:
- capture_exception(Exception(f"quota_limiting: No team tokens found for organization: {organization.id}"))
- return
-
- for resource in [QuotaResource.EVENTS, QuotaResource.RECORDINGS]:
+ for resource in [QuotaResource.EVENTS, QuotaResource.RECORDINGS, QuotaResource.ROWS_SYNCED]:
+ team_attributes = get_team_attribute_by_quota_resource(organization, resource)
quota_limited_until = org_quota_limited_until(organization, resource)
if quota_limited_until:
- add_limited_team_tokens(resource, {x: quota_limited_until for x in team_tokens})
+ add_limited_team_tokens(resource, {x: quota_limited_until for x in team_attributes})
else:
- remove_limited_team_tokens(resource, team_tokens)
+ remove_limited_team_tokens(resource, team_attributes)
+
+
+def get_team_attribute_by_quota_resource(organization: Organization, resource: QuotaResource):
+ if resource in [QuotaResource.EVENTS, QuotaResource.RECORDINGS]:
+ team_tokens: List[str] = [x for x in list(organization.teams.values_list("api_token", flat=True)) if x]
+
+ if not team_tokens:
+ capture_exception(Exception(f"quota_limiting: No team tokens found for organization: {organization.id}"))
+ return
+
+ return team_tokens
+
+ if resource == QuotaResource.ROWS_SYNCED:
+ team_ids: List[str] = [x for x in list(organization.teams.values_list("id", flat=True)) if x]
+
+ if not team_ids:
+ capture_exception(Exception(f"quota_limiting: No team ids found for organization: {organization.id}"))
+ return
+
+ return team_ids
def set_org_usage_summary(
@@ -125,8 +146,10 @@ def set_org_usage_summary(
new_usage = copy.deepcopy(new_usage)
- for field in ["events", "recordings"]:
+ for field in ["events", "recordings", "rows_synced"]:
resource_usage = new_usage[field] # type: ignore
+ if not resource_usage:
+ continue
if todays_usage:
resource_usage["todays_usage"] = todays_usage[field] # type: ignore
@@ -155,6 +178,9 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
teams_with_recording_count_in_period=convert_team_usage_rows_to_dict(
get_teams_with_recording_count_in_period(period_start, period_end)
),
+ teams_with_rows_synced_in_period=convert_team_usage_rows_to_dict(
+ get_teams_with_rows_synced_in_period(period_start, period_end)
+ ),
)
teams: Sequence[Team] = list(
@@ -171,6 +197,7 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
team_report = UsageCounters(
events=all_data["teams_with_event_count_in_period"].get(team.id, 0),
recordings=all_data["teams_with_recording_count_in_period"].get(team.id, 0),
+ rows_synced=all_data["teams_with_rows_synced_in_period"].get(team.id, 0),
)
org_id = str(team.organization.id)
@@ -183,7 +210,7 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
for field in team_report:
org_report[field] += team_report[field] # type: ignore
- quota_limited_orgs: Dict[str, Dict[str, int]] = {"events": {}, "recordings": {}}
+ quota_limited_orgs: Dict[str, Dict[str, int]] = {"events": {}, "recordings": {}, "rows_synced": {}}
# We find all orgs that should be rate limited
for org_id, todays_report in todays_usage_report.items():
@@ -195,7 +222,7 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
if set_org_usage_summary(org, todays_usage=todays_report):
org.save(update_fields=["usage"])
- for field in ["events", "recordings"]:
+ for field in ["events", "recordings", "rows_synced"]:
quota_limited_until = org_quota_limited_until(org, QuotaResource(field))
if quota_limited_until:
@@ -207,12 +234,13 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
previously_quota_limited_team_tokens: Dict[str, Dict[str, int]] = {
"events": {},
"recordings": {},
+ "rows_synced": {},
}
for field in quota_limited_orgs:
- previously_quota_limited_team_tokens[field] = list_limited_team_tokens(QuotaResource(field))
+ previously_quota_limited_team_tokens[field] = list_limited_team_attributes(QuotaResource(field))
- quota_limited_teams: Dict[str, Dict[str, int]] = {"events": {}, "recordings": {}}
+ quota_limited_teams: Dict[str, Dict[str, int]] = {"events": {}, "recordings": {}, "rows_synced": {}}
# Convert the org ids to team tokens
for team in teams:
@@ -233,6 +261,7 @@ def update_all_org_billing_quotas(dry_run: bool = False) -> Dict[str, Dict[str,
properties = {
"quota_limited_events": quota_limited_orgs["events"].get(org_id, None),
"quota_limited_recordings": quota_limited_orgs["events"].get(org_id, None),
+ "quota_limited_rows_synced": quota_limited_orgs["rows_synced"].get(org_id, None),
}
report_organization_action(
diff --git a/ee/billing/test/test_billing_manager.py b/ee/billing/test/test_billing_manager.py
index e0c09e0d071fb..1dbbcb464f068 100644
--- a/ee/billing/test/test_billing_manager.py
+++ b/ee/billing/test/test_billing_manager.py
@@ -33,3 +33,26 @@ def test_update_billing_distinct_ids(self, billing_patch_request_mock: MagicMock
BillingManager(license).update_billing_distinct_ids(organization)
assert billing_patch_request_mock.call_count == 1
assert len(billing_patch_request_mock.call_args[1]["json"]["distinct_ids"]) == 2
+
+ @patch(
+ "ee.billing.billing_manager.requests.patch",
+ return_value=MagicMock(status_code=200, json=MagicMock(return_value={"text": "ok"})),
+ )
+ def test_update_billing_customer_email(self, billing_patch_request_mock: MagicMock):
+ organization = self.organization
+ license = super(LicenseManager, cast(LicenseManager, License.objects)).create(
+ key="key123::key123",
+ plan="enterprise",
+ valid_until=timezone.datetime(2038, 1, 19, 3, 14, 7),
+ )
+ User.objects.create_and_join(
+ organization=organization,
+ email="y@x.com",
+ password=None,
+ level=OrganizationMembership.Level.OWNER,
+ )
+ organization.refresh_from_db()
+ assert len(organization.members.values_list("distinct_id", flat=True)) == 2 # one exists in the test base
+ BillingManager(license).update_billing_customer_email(organization)
+ assert billing_patch_request_mock.call_count == 1
+ assert billing_patch_request_mock.call_args[1]["json"]["org_customer_email"] == "y@x.com"
diff --git a/ee/billing/test/test_quota_limiting.py b/ee/billing/test/test_quota_limiting.py
index 3bdc70a06df9e..b8e68c235b2c5 100644
--- a/ee/billing/test/test_quota_limiting.py
+++ b/ee/billing/test/test_quota_limiting.py
@@ -9,7 +9,7 @@
from ee.billing.quota_limiting import (
QUOTA_LIMITER_CACHE_KEY,
QuotaResource,
- list_limited_team_tokens,
+ list_limited_team_attributes,
org_quota_limited_until,
replace_limited_team_tokens,
set_org_usage_summary,
@@ -47,15 +47,18 @@ def test_billing_rate_limit_not_set_if_missing_org_usage(self) -> None:
result = update_all_org_billing_quotas()
assert result["events"] == {}
assert result["recordings"] == {}
+ assert result["rows_synced"] == {}
assert self.redis_client.zrange(f"{QUOTA_LIMITER_CACHE_KEY}events", 0, -1) == []
assert self.redis_client.zrange(f"{QUOTA_LIMITER_CACHE_KEY}recordings", 0, -1) == []
+ assert self.redis_client.zrange(f"{QUOTA_LIMITER_CACHE_KEY}rows_synced", 0, -1) == []
def test_billing_rate_limit(self) -> None:
with self.settings(USE_TZ=False):
self.organization.usage = {
"events": {"usage": 99, "limit": 100},
"recordings": {"usage": 1, "limit": 100},
+ "rows_synced": {"usage": 5, "limit": 100},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
self.organization.save()
@@ -77,16 +80,19 @@ def test_billing_rate_limit(self) -> None:
org_id = str(self.organization.id)
assert result["events"] == {org_id: 1612137599}
assert result["recordings"] == {}
+ assert result["rows_synced"] == {}
assert self.redis_client.zrange(f"{QUOTA_LIMITER_CACHE_KEY}events", 0, -1) == [
self.team.api_token.encode("UTF-8")
]
assert self.redis_client.zrange(f"{QUOTA_LIMITER_CACHE_KEY}recordings", 0, -1) == []
+ assert self.redis_client.zrange(f"{QUOTA_LIMITER_CACHE_KEY}rows_synced", 0, -1) == []
self.organization.refresh_from_db()
assert self.organization.usage == {
"events": {"usage": 99, "limit": 100, "todays_usage": 10},
"recordings": {"usage": 1, "limit": 100, "todays_usage": 0},
+ "rows_synced": {"usage": 5, "limit": 100, "todays_usage": 0},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
@@ -94,6 +100,7 @@ def test_set_org_usage_summary_updates_correctly(self):
self.organization.usage = {
"events": {"usage": 99, "limit": 100},
"recordings": {"usage": 1, "limit": 100},
+ "rows_synced": {"usage": 5, "limit": 100},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
self.organization.save()
@@ -101,6 +108,7 @@ def test_set_org_usage_summary_updates_correctly(self):
new_usage = dict(
events={"usage": 100, "limit": 100},
recordings={"usage": 2, "limit": 100},
+ rows_synced={"usage": 6, "limit": 100},
period=[
"2021-01-01T00:00:00Z",
"2021-01-31T23:59:59Z",
@@ -112,6 +120,7 @@ def test_set_org_usage_summary_updates_correctly(self):
assert self.organization.usage == {
"events": {"usage": 100, "limit": 100, "todays_usage": 0},
"recordings": {"usage": 2, "limit": 100, "todays_usage": 0},
+ "rows_synced": {"usage": 6, "limit": 100, "todays_usage": 0},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
@@ -119,6 +128,7 @@ def test_set_org_usage_summary_does_nothing_if_the_same(self):
self.organization.usage = {
"events": {"usage": 99, "limit": 100, "todays_usage": 10},
"recordings": {"usage": 1, "limit": 100, "todays_usage": 11},
+ "rows_synced": {"usage": 5, "limit": 100, "todays_usage": 11},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
self.organization.save()
@@ -126,6 +136,7 @@ def test_set_org_usage_summary_does_nothing_if_the_same(self):
new_usage = dict(
events={"usage": 99, "limit": 100},
recordings={"usage": 1, "limit": 100},
+ rows_synced={"usage": 5, "limit": 100},
period=[
"2021-01-01T00:00:00Z",
"2021-01-31T23:59:59Z",
@@ -137,6 +148,7 @@ def test_set_org_usage_summary_does_nothing_if_the_same(self):
assert self.organization.usage == {
"events": {"usage": 99, "limit": 100, "todays_usage": 10},
"recordings": {"usage": 1, "limit": 100, "todays_usage": 11},
+ "rows_synced": {"usage": 5, "limit": 100, "todays_usage": 11},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
@@ -144,15 +156,19 @@ def test_set_org_usage_summary_updates_todays_usage(self):
self.organization.usage = {
"events": {"usage": 99, "limit": 100, "todays_usage": 10},
"recordings": {"usage": 1, "limit": 100, "todays_usage": 11},
+ "rows_synced": {"usage": 5, "limit": 100, "todays_usage": 11},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
self.organization.save()
- assert set_org_usage_summary(self.organization, todays_usage={"events": 20, "recordings": 21})
+ assert set_org_usage_summary(
+ self.organization, todays_usage={"events": 20, "recordings": 21, "rows_synced": 21}
+ )
assert self.organization.usage == {
"events": {"usage": 99, "limit": 100, "todays_usage": 20},
"recordings": {"usage": 1, "limit": 100, "todays_usage": 21},
+ "rows_synced": {"usage": 5, "limit": 100, "todays_usage": 21},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
@@ -163,6 +179,7 @@ def test_org_quota_limited_until(self):
self.organization.usage = {
"events": {"usage": 99, "limit": 100},
"recordings": {"usage": 1, "limit": 100},
+ "rows_synced": {"usage": 99, "limit": 100},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
@@ -184,6 +201,11 @@ def test_org_quota_limited_until(self):
self.organization.usage["recordings"]["usage"] = 1100 # Over limit + buffer
assert org_quota_limited_until(self.organization, QuotaResource.RECORDINGS) == 1612137599
+ assert org_quota_limited_until(self.organization, QuotaResource.ROWS_SYNCED) is None
+
+ self.organization.usage["rows_synced"]["usage"] = 101
+ assert org_quota_limited_until(self.organization, QuotaResource.ROWS_SYNCED) == 1612137599
+
def test_over_quota_but_not_dropped_org(self):
self.organization.usage = None
assert org_quota_limited_until(self.organization, QuotaResource.EVENTS) is None
@@ -191,12 +213,14 @@ def test_over_quota_but_not_dropped_org(self):
self.organization.usage = {
"events": {"usage": 100, "limit": 90},
"recordings": {"usage": 100, "limit": 90},
+ "rows_synced": {"usage": 100, "limit": 90},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
self.organization.never_drop_data = True
assert org_quota_limited_until(self.organization, QuotaResource.EVENTS) is None
assert org_quota_limited_until(self.organization, QuotaResource.RECORDINGS) is None
+ assert org_quota_limited_until(self.organization, QuotaResource.ROWS_SYNCED) is None
# reset for subsequent tests
self.organization.never_drop_data = False
@@ -208,21 +232,32 @@ def test_sync_org_quota_limits(self):
now = timezone.now().timestamp()
replace_limited_team_tokens(QuotaResource.EVENTS, {"1234": now + 10000})
+ replace_limited_team_tokens(QuotaResource.ROWS_SYNCED, {"1337": now + 10000})
self.organization.usage = {
"events": {"usage": 99, "limit": 100},
"recordings": {"usage": 1, "limit": 100},
+ "rows_synced": {"usage": 35, "limit": 100},
"period": ["2021-01-01T00:00:00Z", "2021-01-31T23:59:59Z"],
}
sync_org_quota_limits(self.organization)
- assert list_limited_team_tokens(QuotaResource.EVENTS) == ["1234"]
+ assert list_limited_team_attributes(QuotaResource.EVENTS) == ["1234"]
+ assert list_limited_team_attributes(QuotaResource.ROWS_SYNCED) == ["1337"]
self.organization.usage["events"]["usage"] = 120
+ self.organization.usage["rows_synced"]["usage"] = 120
sync_org_quota_limits(self.organization)
- assert sorted(list_limited_team_tokens(QuotaResource.EVENTS)) == sorted(
+ assert sorted(list_limited_team_attributes(QuotaResource.EVENTS)) == sorted(
["1234", self.team.api_token, other_team.api_token]
)
+ # rows_synced uses teams, not tokens
+ assert sorted(list_limited_team_attributes(QuotaResource.ROWS_SYNCED)) == sorted(
+ ["1337", str(self.team.pk), str(other_team.pk)]
+ )
+
self.organization.usage["events"]["usage"] = 80
+ self.organization.usage["rows_synced"]["usage"] = 36
sync_org_quota_limits(self.organization)
- assert sorted(list_limited_team_tokens(QuotaResource.EVENTS)) == sorted(["1234"])
+ assert sorted(list_limited_team_attributes(QuotaResource.EVENTS)) == sorted(["1234"])
+ assert sorted(list_limited_team_attributes(QuotaResource.ROWS_SYNCED)) == sorted(["1337"])
diff --git a/ee/clickhouse/queries/test/__snapshots__/test_lifecycle.ambr b/ee/clickhouse/queries/test/__snapshots__/test_lifecycle.ambr
index 29eb93b4ae929..5acb951590251 100644
--- a/ee/clickhouse/queries/test/__snapshots__/test_lifecycle.ambr
+++ b/ee/clickhouse/queries/test/__snapshots__/test_lifecycle.ambr
@@ -352,7 +352,7 @@
AND event = '$pageview'
AND timestamp >= toDateTime(dateTrunc('day', toDateTime('2021-04-28 00:00:00', 'UTC'))) - INTERVAL 1 day
AND timestamp < toDateTime(dateTrunc('day', toDateTime('2021-05-05 23:59:59', 'UTC'))) + INTERVAL 1 day
- AND (and(like(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, '$current_url'), ''), 'null'), '^"|"$', ''), '%example%'), 1))
+ AND (and(ifNull(like(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, '$current_url'), ''), 'null'), '^"|"$', ''), '%example%'), 0), 1))
GROUP BY pdi.person_id)
GROUP BY start_of_period,
status)
@@ -426,7 +426,7 @@
AND event = '$pageview'
AND timestamp >= toDateTime(dateTrunc('day', toDateTime('2021-04-28 00:00:00', 'UTC'))) - INTERVAL 1 day
AND timestamp < toDateTime(dateTrunc('day', toDateTime('2021-05-05 23:59:59', 'UTC'))) + INTERVAL 1 day
- AND (and(like(nullIf(nullIf(events.`mat_$current_url`, ''), 'null'), '%example%'), 1))
+ AND (and(ifNull(like(nullIf(nullIf(events.`mat_$current_url`, ''), 'null'), '%example%'), 0), 1))
GROUP BY pdi.person_id)
GROUP BY start_of_period,
status)
@@ -501,7 +501,7 @@
AND event = '$pageview'
AND timestamp >= toDateTime(dateTrunc('day', toDateTime('2021-04-28 00:00:00', 'UTC'))) - INTERVAL 1 day
AND timestamp < toDateTime(dateTrunc('day', toDateTime('2021-05-05 23:59:59', 'UTC'))) + INTERVAL 1 day
- AND (like(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person_properties, 'email'), ''), 'null'), '^"|"$', ''), '%test.com'))
+ AND (ifNull(like(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person_properties, 'email'), ''), 'null'), '^"|"$', ''), '%test.com'), 0))
GROUP BY pdi.person_id)
GROUP BY start_of_period,
status)
@@ -576,7 +576,7 @@
AND event = '$pageview'
AND timestamp >= toDateTime(dateTrunc('day', toDateTime('2021-04-28 00:00:00', 'UTC'))) - INTERVAL 1 day
AND timestamp < toDateTime(dateTrunc('day', toDateTime('2021-05-05 23:59:59', 'UTC'))) + INTERVAL 1 day
- AND (like(nullIf(nullIf(mat_pp_email, ''), 'null'), '%test.com'))
+ AND (ifNull(like(nullIf(nullIf(mat_pp_email, ''), 'null'), '%test.com'), 0))
GROUP BY pdi.person_id)
GROUP BY start_of_period,
status)
diff --git a/ee/clickhouse/test/test_client.py b/ee/clickhouse/test/test_client.py
deleted file mode 100644
index ab5ba1b4a53e0..0000000000000
--- a/ee/clickhouse/test/test_client.py
+++ /dev/null
@@ -1,129 +0,0 @@
-from unittest.mock import patch
-
-import fakeredis
-from clickhouse_driver.errors import ServerException
-from django.test import TestCase
-
-from posthog.clickhouse.client import execute_async as client
-from posthog.client import sync_execute
-from posthog.test.base import ClickhouseTestMixin
-
-
-class ClickhouseClientTestCase(TestCase, ClickhouseTestMixin):
- def setUp(self):
- self.redis_client = fakeredis.FakeStrictRedis()
-
- def test_async_query_client(self):
- query = "SELECT 1+1"
- team_id = 2
- query_id = client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
- result = client.get_status_or_results(team_id, query_id)
- self.assertFalse(result.error)
- self.assertTrue(result.complete)
- self.assertEqual(result.results, [[2]])
-
- def test_async_query_client_errors(self):
- query = "SELECT WOW SUCH DATA FROM NOWHERE THIS WILL CERTAINLY WORK"
- team_id = 2
- self.assertRaises(
- ServerException,
- client.enqueue_execute_with_progress,
- **{"team_id": team_id, "query": query, "bypass_celery": True},
- )
- try:
- query_id = client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
- except Exception:
- pass
-
- result = client.get_status_or_results(team_id, query_id)
- self.assertTrue(result.error)
- self.assertRegex(result.error_message, "Code: 62.\nDB::Exception: Syntax error:")
-
- def test_async_query_client_does_not_leak(self):
- query = "SELECT 1+1"
- team_id = 2
- wrong_team = 5
- query_id = client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
- result = client.get_status_or_results(wrong_team, query_id)
- self.assertTrue(result.error)
- self.assertEqual(result.error_message, "Requesting team is not executing team")
-
- @patch("posthog.clickhouse.client.execute_async.enqueue_clickhouse_execute_with_progress")
- def test_async_query_client_is_lazy(self, execute_sync_mock):
- query = "SELECT 4 + 4"
- team_id = 2
- client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
-
- # Try the same query again
- client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
-
- # Try the same query again (for good measure!)
- client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
-
- # Assert that we only called clickhouse once
- execute_sync_mock.assert_called_once()
-
- @patch("posthog.clickhouse.client.execute_async.enqueue_clickhouse_execute_with_progress")
- def test_async_query_client_is_lazy_but_not_too_lazy(self, execute_sync_mock):
- query = "SELECT 8 + 8"
- team_id = 2
- client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
-
- # Try the same query again, but with force
- client.enqueue_execute_with_progress(team_id, query, bypass_celery=True, force=True)
-
- # Try the same query again (for good measure!)
- client.enqueue_execute_with_progress(team_id, query, bypass_celery=True)
-
- # Assert that we called clickhouse twice
- self.assertEqual(execute_sync_mock.call_count, 2)
-
- @patch("posthog.clickhouse.client.execute_async.enqueue_clickhouse_execute_with_progress")
- def test_async_query_client_manual_query_uuid(self, execute_sync_mock):
- # This is a unique test because technically in the test pattern `SELECT 8 + 8` is already
- # in redis. This tests to make sure it is treated as a unique run of that query
- query = "SELECT 8 + 8"
- team_id = 2
- query_id = "I'm so unique"
- client.enqueue_execute_with_progress(team_id, query, query_id=query_id, bypass_celery=True)
-
- # Try the same query again, but with force
- client.enqueue_execute_with_progress(team_id, query, query_id=query_id, bypass_celery=True, force=True)
-
- # Try the same query again (for good measure!)
- client.enqueue_execute_with_progress(team_id, query, query_id=query_id, bypass_celery=True)
-
- # Assert that we called clickhouse twice
- self.assertEqual(execute_sync_mock.call_count, 2)
-
- def test_client_strips_comments_from_request(self):
- """
- To ensure we can easily copy queries from `system.query_log` in e.g.
- Metabase, we strip comments from the query we send. Metabase doesn't
- display multilined output.
-
- See https://github.com/metabase/metabase/issues/14253
-
- Note I'm not really testing much complexity, I trust that those will
- come out as failures in other tests.
- """
- from posthog.clickhouse.query_tagging import tag_queries
-
- # First add in the request information that should be added to the sql.
- # We check this to make sure it is not removed by the comment stripping
- with self.capture_select_queries() as sqls:
- tag_queries(kind="request", id="1")
- sync_execute(
- query="""
- -- this request returns 1
- SELECT 1
- """
- )
- self.assertEqual(len(sqls), 1)
- first_query = sqls[0]
- self.assertIn(f"SELECT 1", first_query)
- self.assertNotIn("this request returns", first_query)
-
- # Make sure it still includes the "annotation" comment that includes
- # request routing information for debugging purposes
- self.assertIn("/* request:1 */", first_query)
diff --git a/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr b/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr
index f039a2994204e..3474ae77b858f 100644
--- a/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr
+++ b/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiment_secondary_results.ambr
@@ -1,6 +1,6 @@
# name: ClickhouseTestExperimentSecondaryResults.test_basic_secondary_metric_results
'
- /* user_id:126 celery:posthog.celery.sync_insight_caching_state */
+ /* user_id:131 celery:posthog.celery.sync_insight_caching_state */
SELECT team_id,
date_diff('second', max(timestamp), now()) AS age
FROM events
diff --git a/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiments.ambr b/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiments.ambr
index d185a7a063790..09cddbe7f6756 100644
--- a/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiments.ambr
+++ b/ee/clickhouse/views/test/__snapshots__/test_clickhouse_experiments.ambr
@@ -1613,8 +1613,7 @@
AND toTimeZone(timestamp, 'UTC') >= toDateTime('2020-01-01 00:00:00', 'UTC')
AND toTimeZone(timestamp, 'UTC') <= toDateTime('2020-01-06 00:00:00', 'UTC')
AND ((has(['control', 'test'], replaceRegexpAll(JSONExtractRaw(e.properties, '$feature/a-b-test'), '^"|"$', '')))
- AND (ifNull(ilike(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, 'hogql'), ''), 'null'), '^"|"$', ''), 'true'), isNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, 'hogql'), ''), 'null'), '^"|"$', ''))
- and isNull('true'))))
+ AND (ifNull(ilike(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, 'hogql'), ''), 'null'), '^"|"$', ''), 'true'), 0)))
GROUP BY value
ORDER BY count DESC, value DESC
LIMIT 25
@@ -1655,8 +1654,7 @@
WHERE e.team_id = 2
AND event = '$pageview'
AND ((has(['control', 'test'], replaceRegexpAll(JSONExtractRaw(e.properties, '$feature/a-b-test'), '^"|"$', '')))
- AND (ifNull(ilike(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, 'hogql'), ''), 'null'), '^"|"$', ''), 'true'), isNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, 'hogql'), ''), 'null'), '^"|"$', ''))
- and isNull('true'))))
+ AND (ifNull(ilike(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(properties, 'hogql'), ''), 'null'), '^"|"$', ''), 'true'), 0)))
AND toTimeZone(timestamp, 'UTC') >= toDateTime('2020-01-01 00:00:00', 'UTC')
AND toTimeZone(timestamp, 'UTC') <= toDateTime('2020-01-06 00:00:00', 'UTC')
AND replaceRegexpAll(JSONExtractRaw(properties, '$feature/a-b-test'), '^"|"$', '') in (['test', 'control'])
diff --git a/ee/clickhouse/views/test/test_clickhouse_trends.py b/ee/clickhouse/views/test/test_clickhouse_trends.py
index 75ab015e39a15..8bf86c1524006 100644
--- a/ee/clickhouse/views/test/test_clickhouse_trends.py
+++ b/ee/clickhouse/views/test/test_clickhouse_trends.py
@@ -118,7 +118,7 @@ def test_includes_only_intervals_within_range(client: Client):
{
"action": ANY,
"breakdown_value": cohort["id"],
- "label": "$pageview - test cohort",
+ "label": "test cohort",
"count": 3.0,
"data": [1.0, 1.0, 1.0],
# Prior to the fix this would also include '29-Aug-2021'
@@ -827,14 +827,12 @@ def test_insight_trends_cumulative(self):
],
)
data_response = get_trends_time_series_ok(self.client, request, self.team)
- person_response = get_people_from_url_ok(
- self.client, data_response["$pageview - val"]["2012-01-14"].person_url
- )
+ person_response = get_people_from_url_ok(self.client, data_response["val"]["2012-01-14"].person_url)
- assert data_response["$pageview - val"]["2012-01-13"].value == 1
- assert data_response["$pageview - val"]["2012-01-13"].breakdown_value == "val"
- assert data_response["$pageview - val"]["2012-01-14"].value == 3
- assert data_response["$pageview - val"]["2012-01-14"].label == "14-Jan-2012"
+ assert data_response["val"]["2012-01-13"].value == 1
+ assert data_response["val"]["2012-01-13"].breakdown_value == "val"
+ assert data_response["val"]["2012-01-14"].value == 3
+ assert data_response["val"]["2012-01-14"].label == "14-Jan-2012"
assert sorted([p["id"] for p in person_response]) == sorted(
[str(created_people["p1"].uuid), str(created_people["p3"].uuid)]
@@ -862,12 +860,12 @@ def test_insight_trends_cumulative(self):
properties=[{"type": "person", "key": "key", "value": "some_val"}],
)
data_response = get_trends_time_series_ok(self.client, request, self.team)
- people = get_people_from_url_ok(self.client, data_response["$pageview - val"]["2012-01-14"].person_url)
+ people = get_people_from_url_ok(self.client, data_response["val"]["2012-01-14"].person_url)
- assert data_response["$pageview - val"]["2012-01-13"].value == 1
- assert data_response["$pageview - val"]["2012-01-13"].breakdown_value == "val"
- assert data_response["$pageview - val"]["2012-01-14"].value == 3
- assert data_response["$pageview - val"]["2012-01-14"].label == "14-Jan-2012"
+ assert data_response["val"]["2012-01-13"].value == 1
+ assert data_response["val"]["2012-01-13"].breakdown_value == "val"
+ assert data_response["val"]["2012-01-14"].value == 3
+ assert data_response["val"]["2012-01-14"].label == "14-Jan-2012"
assert sorted([p["id"] for p in people]) == sorted(
[str(created_people["p1"].uuid), str(created_people["p3"].uuid)]
@@ -894,12 +892,12 @@ def test_insight_trends_cumulative(self):
],
)
data_response = get_trends_time_series_ok(self.client, request, self.team)
- people = get_people_from_url_ok(self.client, data_response["$pageview - val"]["2012-01-14"].person_url)
+ people = get_people_from_url_ok(self.client, data_response["val"]["2012-01-14"].person_url)
- assert data_response["$pageview - val"]["2012-01-13"].value == 1
- assert data_response["$pageview - val"]["2012-01-13"].breakdown_value == "val"
- assert data_response["$pageview - val"]["2012-01-14"].value == 2
- assert data_response["$pageview - val"]["2012-01-14"].label == "14-Jan-2012"
+ assert data_response["val"]["2012-01-13"].value == 1
+ assert data_response["val"]["2012-01-13"].breakdown_value == "val"
+ assert data_response["val"]["2012-01-14"].value == 2
+ assert data_response["val"]["2012-01-14"].label == "14-Jan-2012"
assert sorted([p["id"] for p in people]) == sorted(
[str(created_people["p1"].uuid), str(created_people["p3"].uuid)]
@@ -933,12 +931,10 @@ def test_breakdown_with_filter(self):
properties=[{"key": "key", "value": "oh", "operator": "not_icontains"}],
)
data_response = get_trends_time_series_ok(self.client, params, self.team)
- person_response = get_people_from_url_ok(
- self.client, data_response["sign up - val"]["2012-01-13"].person_url
- )
+ person_response = get_people_from_url_ok(self.client, data_response["val"]["2012-01-13"].person_url)
- assert data_response["sign up - val"]["2012-01-13"].value == 1
- assert data_response["sign up - val"]["2012-01-13"].breakdown_value == "val"
+ assert data_response["val"]["2012-01-13"].value == 1
+ assert data_response["val"]["2012-01-13"].breakdown_value == "val"
assert sorted([p["id"] for p in person_response]) == sorted([str(created_people["person1"].uuid)])
@@ -950,11 +946,9 @@ def test_breakdown_with_filter(self):
events=[{"id": "sign up", "name": "sign up", "type": "events", "order": 0}],
)
aggregate_response = get_trends_aggregate_ok(self.client, params, self.team)
- aggregate_person_response = get_people_from_url_ok(
- self.client, aggregate_response["sign up - val"].person_url
- )
+ aggregate_person_response = get_people_from_url_ok(self.client, aggregate_response["val"].person_url)
- assert aggregate_response["sign up - val"].value == 1
+ assert aggregate_response["val"].value == 1
assert sorted([p["id"] for p in aggregate_person_response]) == sorted([str(created_people["person1"].uuid)])
def test_insight_trends_compare(self):
diff --git a/frontend/__snapshots__/components-cards-insight-card--insight-card.png b/frontend/__snapshots__/components-cards-insight-card--insight-card.png
index 3c8919af6eeb8..eaa0ed7df25ed 100644
Binary files a/frontend/__snapshots__/components-cards-insight-card--insight-card.png and b/frontend/__snapshots__/components-cards-insight-card--insight-card.png differ
diff --git a/frontend/__snapshots__/components-cards-text-card--template.png b/frontend/__snapshots__/components-cards-text-card--template.png
index 4eee8836ab698..3c045b8354ba6 100644
Binary files a/frontend/__snapshots__/components-cards-text-card--template.png and b/frontend/__snapshots__/components-cards-text-card--template.png differ
diff --git a/frontend/__snapshots__/components-command-bar--actions.png b/frontend/__snapshots__/components-command-bar--actions.png
new file mode 100644
index 0000000000000..a1c3b448c6a2e
Binary files /dev/null and b/frontend/__snapshots__/components-command-bar--actions.png differ
diff --git a/frontend/__snapshots__/components-command-bar--search.png b/frontend/__snapshots__/components-command-bar--search.png
new file mode 100644
index 0000000000000..d155d92fac149
Binary files /dev/null and b/frontend/__snapshots__/components-command-bar--search.png differ
diff --git a/frontend/__snapshots__/components-command-bar--shortcuts.png b/frontend/__snapshots__/components-command-bar--shortcuts.png
new file mode 100644
index 0000000000000..32f4e7ff34955
Binary files /dev/null and b/frontend/__snapshots__/components-command-bar--shortcuts.png differ
diff --git a/frontend/__snapshots__/components-compact-list--compact-list.png b/frontend/__snapshots__/components-compact-list--compact-list.png
index 4a4b5e8704410..49cbfb2048571 100644
Binary files a/frontend/__snapshots__/components-compact-list--compact-list.png and b/frontend/__snapshots__/components-compact-list--compact-list.png differ
diff --git a/frontend/__snapshots__/components-editable-field--default.png b/frontend/__snapshots__/components-editable-field--default.png
index 2d16114431388..f68ba65618170 100644
Binary files a/frontend/__snapshots__/components-editable-field--default.png and b/frontend/__snapshots__/components-editable-field--default.png differ
diff --git a/frontend/__snapshots__/components-networkrequesttiming--basic.png b/frontend/__snapshots__/components-networkrequesttiming--basic.png
index ff34c2d27d479..effc91c21a0a6 100644
Binary files a/frontend/__snapshots__/components-networkrequesttiming--basic.png and b/frontend/__snapshots__/components-networkrequesttiming--basic.png differ
diff --git a/frontend/__snapshots__/components-product-empty-state--empty-with-action.png b/frontend/__snapshots__/components-product-empty-state--empty-with-action.png
index dd10594e21d1c..4c6bc2766b5e4 100644
Binary files a/frontend/__snapshots__/components-product-empty-state--empty-with-action.png and b/frontend/__snapshots__/components-product-empty-state--empty-with-action.png differ
diff --git a/frontend/__snapshots__/components-product-empty-state--not-empty-with-action.png b/frontend/__snapshots__/components-product-empty-state--not-empty-with-action.png
index d9ed865218733..a93edc4abb8e1 100644
Binary files a/frontend/__snapshots__/components-product-empty-state--not-empty-with-action.png and b/frontend/__snapshots__/components-product-empty-state--not-empty-with-action.png differ
diff --git a/frontend/__snapshots__/components-product-empty-state--product-introduction.png b/frontend/__snapshots__/components-product-empty-state--product-introduction.png
index dd10594e21d1c..4c6bc2766b5e4 100644
Binary files a/frontend/__snapshots__/components-product-empty-state--product-introduction.png and b/frontend/__snapshots__/components-product-empty-state--product-introduction.png differ
diff --git a/frontend/__snapshots__/components-properties-table--properties-table.png b/frontend/__snapshots__/components-properties-table--properties-table.png
new file mode 100644
index 0000000000000..0ebb3a71ccb83
Binary files /dev/null and b/frontend/__snapshots__/components-properties-table--properties-table.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--funnel-historical-trends-insight.png b/frontend/__snapshots__/exporter-exporter--funnel-historical-trends-insight.png
index cf79e173859f2..f0559ae34642d 100644
Binary files a/frontend/__snapshots__/exporter-exporter--funnel-historical-trends-insight.png and b/frontend/__snapshots__/exporter-exporter--funnel-historical-trends-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-breakdown-insight.png
index 38244e35ae9d8..aa5a9eab7354f 100644
Binary files a/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-insight.png b/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-insight.png
index 4a04621ca44de..dd92bf6b0ef79 100644
Binary files a/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-insight.png and b/frontend/__snapshots__/exporter-exporter--funnel-left-to-right-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--funnel-time-to-convert-insight.png b/frontend/__snapshots__/exporter-exporter--funnel-time-to-convert-insight.png
index c403c659e15df..e97ac272bc3b5 100644
Binary files a/frontend/__snapshots__/exporter-exporter--funnel-time-to-convert-insight.png and b/frontend/__snapshots__/exporter-exporter--funnel-time-to-convert-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-breakdown-insight.png
index ec9d14b04e8ca..20d72c16238e4 100644
Binary files a/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-insight.png b/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-insight.png
index 6f5b39c1f9d3e..c7f2676ae1bf2 100644
Binary files a/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-insight.png and b/frontend/__snapshots__/exporter-exporter--funnel-top-to-bottom-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--lifecycle-insight.png b/frontend/__snapshots__/exporter-exporter--lifecycle-insight.png
index fdcbbd24236f1..49e132b82db76 100644
Binary files a/frontend/__snapshots__/exporter-exporter--lifecycle-insight.png and b/frontend/__snapshots__/exporter-exporter--lifecycle-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--retention-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--retention-breakdown-insight.png
index 082bdb9907417..7185efea76ab6 100644
Binary files a/frontend/__snapshots__/exporter-exporter--retention-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--retention-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--retention-insight.png b/frontend/__snapshots__/exporter-exporter--retention-insight.png
index c62fc70ac088b..e91b842102b86 100644
Binary files a/frontend/__snapshots__/exporter-exporter--retention-insight.png and b/frontend/__snapshots__/exporter-exporter--retention-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--stickiness-insight.png b/frontend/__snapshots__/exporter-exporter--stickiness-insight.png
index 1c1e95908112f..3fc3e03143c98 100644
Binary files a/frontend/__snapshots__/exporter-exporter--stickiness-insight.png and b/frontend/__snapshots__/exporter-exporter--stickiness-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-area-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--trends-area-breakdown-insight.png
index 24ffc71713a28..7de2045284f44 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-area-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-area-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-area-insight.png b/frontend/__snapshots__/exporter-exporter--trends-area-insight.png
index 56ac86a94a237..41d262d023141 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-area-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-area-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-bar-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--trends-bar-breakdown-insight.png
index 3c95a30cc395a..e197249c208ce 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-bar-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-bar-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-bar-insight.png b/frontend/__snapshots__/exporter-exporter--trends-bar-insight.png
index 56ac86a94a237..41d262d023141 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-bar-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-bar-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-line-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--trends-line-breakdown-insight.png
index 3c95a30cc395a..e197249c208ce 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-line-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-line-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-line-insight.png b/frontend/__snapshots__/exporter-exporter--trends-line-insight.png
index 56ac86a94a237..41d262d023141 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-line-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-line-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-line-multi-insight.png b/frontend/__snapshots__/exporter-exporter--trends-line-multi-insight.png
index 75529341446f0..93c140d75f49a 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-line-multi-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-line-multi-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-number-insight.png b/frontend/__snapshots__/exporter-exporter--trends-number-insight.png
index ec6d628426da3..67b2a70ddeb75 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-number-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-number-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-pie-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--trends-pie-breakdown-insight.png
index 7a1f9dfceee8c..61ac574a3c443 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-pie-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-pie-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-pie-insight.png b/frontend/__snapshots__/exporter-exporter--trends-pie-insight.png
index 825a772994d7d..03e5f0a529a8a 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-pie-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-pie-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-table-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--trends-table-breakdown-insight.png
index 036f84e322323..282daf6b30543 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-table-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-table-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-table-insight.png b/frontend/__snapshots__/exporter-exporter--trends-table-insight.png
index 21d2a42f9eaf2..5223b75398630 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-table-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-table-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-value-breakdown-insight.png b/frontend/__snapshots__/exporter-exporter--trends-value-breakdown-insight.png
index 3fff287337545..3575438a7ad30 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-value-breakdown-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-value-breakdown-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-value-insight.png b/frontend/__snapshots__/exporter-exporter--trends-value-insight.png
index 56ac86a94a237..41d262d023141 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-value-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-value-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--trends-world-map-insight.png b/frontend/__snapshots__/exporter-exporter--trends-world-map-insight.png
index d4b629b6536ad..7654fa3f75324 100644
Binary files a/frontend/__snapshots__/exporter-exporter--trends-world-map-insight.png and b/frontend/__snapshots__/exporter-exporter--trends-world-map-insight.png differ
diff --git a/frontend/__snapshots__/exporter-exporter--user-paths-insight.png b/frontend/__snapshots__/exporter-exporter--user-paths-insight.png
index 79f1711336dbf..19977a7a1bd22 100644
Binary files a/frontend/__snapshots__/exporter-exporter--user-paths-insight.png and b/frontend/__snapshots__/exporter-exporter--user-paths-insight.png differ
diff --git a/frontend/__snapshots__/insights-insightstable--embedded.png b/frontend/__snapshots__/insights-insightstable--embedded.png
index 3f9234e5b9d3a..180bab30a3d06 100644
Binary files a/frontend/__snapshots__/insights-insightstable--embedded.png and b/frontend/__snapshots__/insights-insightstable--embedded.png differ
diff --git a/frontend/__snapshots__/layout-navigation--app-page-with-side-bar-shown.png b/frontend/__snapshots__/layout-navigation--app-page-with-side-bar-shown.png
index b49b6fc4bd341..b2ae49cd91f5b 100644
Binary files a/frontend/__snapshots__/layout-navigation--app-page-with-side-bar-shown.png and b/frontend/__snapshots__/layout-navigation--app-page-with-side-bar-shown.png differ
diff --git a/frontend/__snapshots__/lemon-ui-colors--all-three-thousand-color-options.png b/frontend/__snapshots__/lemon-ui-colors--all-three-thousand-color-options.png
index 2038fbe5c8bb2..02abe5eaa23a3 100644
Binary files a/frontend/__snapshots__/lemon-ui-colors--all-three-thousand-color-options.png and b/frontend/__snapshots__/lemon-ui-colors--all-three-thousand-color-options.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-banner--closable.png b/frontend/__snapshots__/lemon-ui-lemon-banner--closable.png
index a05dd78b3e3e7..a7a8ac55c5061 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-banner--closable.png and b/frontend/__snapshots__/lemon-ui-lemon-banner--closable.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-banner--dismissable.png b/frontend/__snapshots__/lemon-ui-lemon-banner--dismissable.png
index be2ef2e5a884b..540a8a3ef2c39 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-banner--dismissable.png and b/frontend/__snapshots__/lemon-ui-lemon-banner--dismissable.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-banner--error.png b/frontend/__snapshots__/lemon-ui-lemon-banner--error.png
index 7db8c557495b9..9389cfa4ea1b2 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-banner--error.png and b/frontend/__snapshots__/lemon-ui-lemon-banner--error.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-banner--info.png b/frontend/__snapshots__/lemon-ui-lemon-banner--info.png
index 7c6e78d57caf2..6848c05f89a32 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-banner--info.png and b/frontend/__snapshots__/lemon-ui-lemon-banner--info.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-banner--success.png b/frontend/__snapshots__/lemon-ui-lemon-banner--success.png
index 2053ce5ccc6de..f3b58cb98363a 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-banner--success.png and b/frontend/__snapshots__/lemon-ui-lemon-banner--success.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-banner--warning.png b/frontend/__snapshots__/lemon-ui-lemon-banner--warning.png
index bf8c975d7385b..3c41933fb5078 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-banner--warning.png and b/frontend/__snapshots__/lemon-ui-lemon-banner--warning.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-button--as-links.png b/frontend/__snapshots__/lemon-ui-lemon-button--as-links.png
index 24ae6fe59d181..292f9ce7d0a99 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-button--as-links.png and b/frontend/__snapshots__/lemon-ui-lemon-button--as-links.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-skeleton--presets.png b/frontend/__snapshots__/lemon-ui-lemon-skeleton--presets.png
index d26a679f4fd68..18ea3052167f0 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-skeleton--presets.png and b/frontend/__snapshots__/lemon-ui-lemon-skeleton--presets.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-table--empty-loading.png b/frontend/__snapshots__/lemon-ui-lemon-table--empty-loading.png
index b6109c6884322..90ae77d5ca04a 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-table--empty-loading.png and b/frontend/__snapshots__/lemon-ui-lemon-table--empty-loading.png differ
diff --git a/frontend/__snapshots__/lemon-ui-lemon-table--loading.png b/frontend/__snapshots__/lemon-ui-lemon-table--loading.png
index e5852c23bda01..f3f2287fcdb4c 100644
Binary files a/frontend/__snapshots__/lemon-ui-lemon-table--loading.png and b/frontend/__snapshots__/lemon-ui-lemon-table--loading.png differ
diff --git a/frontend/__snapshots__/lemon-ui-textfit--basic.png b/frontend/__snapshots__/lemon-ui-textfit--basic.png
new file mode 100644
index 0000000000000..269bfc9cfad86
Binary files /dev/null and b/frontend/__snapshots__/lemon-ui-textfit--basic.png differ
diff --git a/frontend/__snapshots__/posthog-3000-keyboard-shortcut--default.png b/frontend/__snapshots__/posthog-3000-keyboard-shortcut--default.png
new file mode 100644
index 0000000000000..995c1bc753ad1
Binary files /dev/null and b/frontend/__snapshots__/posthog-3000-keyboard-shortcut--default.png differ
diff --git a/frontend/__snapshots__/posthog-3000-keyboard-shortcut--muted.png b/frontend/__snapshots__/posthog-3000-keyboard-shortcut--muted.png
new file mode 100644
index 0000000000000..995c1bc753ad1
Binary files /dev/null and b/frontend/__snapshots__/posthog-3000-keyboard-shortcut--muted.png differ
diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png
index 3829c37b8d852..cb3513e97394d 100644
Binary files a/frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png and b/frontend/__snapshots__/posthog-3000-navigation--navigation-3000.png differ
diff --git a/frontend/__snapshots__/posthog-3000-navigation--navigation-base.png b/frontend/__snapshots__/posthog-3000-navigation--navigation-base.png
index 827ca87dda7ee..d42c385e3c023 100644
Binary files a/frontend/__snapshots__/posthog-3000-navigation--navigation-base.png and b/frontend/__snapshots__/posthog-3000-navigation--navigation-base.png differ
diff --git a/frontend/__snapshots__/scenes-app-batchexports--create-export.png b/frontend/__snapshots__/scenes-app-batchexports--create-export.png
index 5812443d7cc01..51889a6cdcc34 100644
Binary files a/frontend/__snapshots__/scenes-app-batchexports--create-export.png and b/frontend/__snapshots__/scenes-app-batchexports--create-export.png differ
diff --git a/frontend/__snapshots__/scenes-app-dashboards--edit.png b/frontend/__snapshots__/scenes-app-dashboards--edit.png
index 6389702cb99c5..0bd4f10c2b233 100644
Binary files a/frontend/__snapshots__/scenes-app-dashboards--edit.png and b/frontend/__snapshots__/scenes-app-dashboards--edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-dashboards--show.png b/frontend/__snapshots__/scenes-app-dashboards--show.png
index 4aaadd263a2a6..9f1dac8d8c809 100644
Binary files a/frontend/__snapshots__/scenes-app-dashboards--show.png and b/frontend/__snapshots__/scenes-app-dashboards--show.png differ
diff --git a/frontend/__snapshots__/scenes-app-events--event-explorer.png b/frontend/__snapshots__/scenes-app-events--event-explorer.png
index 4ed82b3bdbbdd..7d3287e05481b 100644
Binary files a/frontend/__snapshots__/scenes-app-events--event-explorer.png and b/frontend/__snapshots__/scenes-app-events--event-explorer.png differ
diff --git a/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png b/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png
index 8feeeb95edc07..0c9084824591a 100644
Binary files a/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png and b/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png differ
diff --git a/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png b/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png
index fd9d704276d4c..683e286506729 100644
Binary files a/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png and b/frontend/__snapshots__/scenes-app-experiments--experiments-list-pay-gate.png differ
diff --git a/frontend/__snapshots__/scenes-app-experiments--experiments-list.png b/frontend/__snapshots__/scenes-app-experiments--experiments-list.png
index f6760a46e6b69..4072657487cb8 100644
Binary files a/frontend/__snapshots__/scenes-app-experiments--experiments-list.png and b/frontend/__snapshots__/scenes-app-experiments--experiments-list.png differ
diff --git a/frontend/__snapshots__/scenes-app-experiments--running-trend-experiment.png b/frontend/__snapshots__/scenes-app-experiments--running-trend-experiment.png
index aab6a5a84f625..766de1662f8ae 100644
Binary files a/frontend/__snapshots__/scenes-app-experiments--running-trend-experiment.png and b/frontend/__snapshots__/scenes-app-experiments--running-trend-experiment.png differ
diff --git a/frontend/__snapshots__/scenes-app-feature-flags--edit-feature-flag.png b/frontend/__snapshots__/scenes-app-feature-flags--edit-feature-flag.png
index 0d7d6dd72c02b..9fe8b83975eb5 100644
Binary files a/frontend/__snapshots__/scenes-app-feature-flags--edit-feature-flag.png and b/frontend/__snapshots__/scenes-app-feature-flags--edit-feature-flag.png differ
diff --git a/frontend/__snapshots__/scenes-app-feature-flags--edit-multi-variate-feature-flag.png b/frontend/__snapshots__/scenes-app-feature-flags--edit-multi-variate-feature-flag.png
index 45cc7c6c7b4d5..4638e3c252629 100644
Binary files a/frontend/__snapshots__/scenes-app-feature-flags--edit-multi-variate-feature-flag.png and b/frontend/__snapshots__/scenes-app-feature-flags--edit-multi-variate-feature-flag.png differ
diff --git a/frontend/__snapshots__/scenes-app-feature-flags--new-feature-flag.png b/frontend/__snapshots__/scenes-app-feature-flags--new-feature-flag.png
index c640e778e8505..2d6a0dd22fbb2 100644
Binary files a/frontend/__snapshots__/scenes-app-feature-flags--new-feature-flag.png and b/frontend/__snapshots__/scenes-app-feature-flags--new-feature-flag.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends--webkit.png
index 015ec328151a8..a36d7365e7344 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit--webkit.png
index dd9c31998e7e4..613e89cdbc0d8 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit.png b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit.png
index 50f36a4871650..d2c639e108166 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends.png b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends.png
index edc1d0829245e..bcd656dcc26a3 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends.png and b/frontend/__snapshots__/scenes-app-insights--funnel-historical-trends.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right--webkit.png
index 73ef96ff35115..93a2510edbd3e 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown--webkit.png
index 47ef343bc3320..88fce2b75ec39 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit--webkit.png
index 83e9c3fa63d99..234167ed34ceb 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit.png
index e379604a2591b..8be9ffc926019 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown.png
index 7cd7d0f64cc9a..8eaedc5c1d3fa 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit--webkit.png
index e06956a47c809..87320f1ad5b19 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit.png
index 07f7cfe1b6935..92811307a20d4 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right.png b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right.png
index db6f0a7f56163..ee0abcee40c6b 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right.png and b/frontend/__snapshots__/scenes-app-insights--funnel-left-to-right.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert--webkit.png
index 226edac304a58..cd77f1bbd8447 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit--webkit.png
index 656cf46515e6e..b0c052e1b37ff 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit.png b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit.png
index 486d89f6bd7ca..62ab313160740 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert.png b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert.png
index 036c2bc3b587d..0f65f00462135 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert.png and b/frontend/__snapshots__/scenes-app-insights--funnel-time-to-convert.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom--webkit.png
index 69d5bf0584241..20f8540e7af66 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown--webkit.png
index d26c9a76aad35..5ba4dd941fcbf 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--webkit.png
index 59d35f7d7b1da..64b2955db1cfe 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit.png
index db0e0dc5d29be..7fde8e692b299 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown.png
index f4bdbb0d8c2cb..67d55e396a376 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit--webkit.png
index ad94cc04a4881..a41c083a673a9 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit.png
index 896a7623a9071..10a781cafc5d0 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom.png
index fbdf18896ae06..8760764ed3a04 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--lifecycle--webkit.png b/frontend/__snapshots__/scenes-app-insights--lifecycle--webkit.png
index ee1307cd8d1ba..c4212fc4ab28d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--lifecycle--webkit.png and b/frontend/__snapshots__/scenes-app-insights--lifecycle--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--lifecycle-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--lifecycle-edit--webkit.png
index 373e3e0e19c98..4f11382fa8bb4 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--lifecycle-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--lifecycle-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--lifecycle-edit.png b/frontend/__snapshots__/scenes-app-insights--lifecycle-edit.png
index 15c56dfa56a59..a4c4a82e5d207 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--lifecycle-edit.png and b/frontend/__snapshots__/scenes-app-insights--lifecycle-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--lifecycle.png b/frontend/__snapshots__/scenes-app-insights--lifecycle.png
index 8fda2317ec4d0..b5af8e303507d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--lifecycle.png and b/frontend/__snapshots__/scenes-app-insights--lifecycle.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention--webkit.png b/frontend/__snapshots__/scenes-app-insights--retention--webkit.png
index 87c46c2fab5ab..3f6259a8a2428 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention--webkit.png and b/frontend/__snapshots__/scenes-app-insights--retention--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--retention-breakdown--webkit.png
index fd40f5ea3d016..8e6390a225b40 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--retention-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit--webkit.png
index f599ea59d602b..998fedb12e86e 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit.png
index 97fa118d79f56..6262a5918f1f1 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--retention-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention-breakdown.png b/frontend/__snapshots__/scenes-app-insights--retention-breakdown.png
index 121d0b324adcd..62dd6f95bbd41 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--retention-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--retention-edit--webkit.png
index c8ede7b9fd30c..0a8e1c20fdb87 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--retention-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention-edit.png b/frontend/__snapshots__/scenes-app-insights--retention-edit.png
index ae71eec088987..cd3d9f866c7f4 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention-edit.png and b/frontend/__snapshots__/scenes-app-insights--retention-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--retention.png b/frontend/__snapshots__/scenes-app-insights--retention.png
index e90937f466eef..5df60b1e00204 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--retention.png and b/frontend/__snapshots__/scenes-app-insights--retention.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--stickiness--webkit.png b/frontend/__snapshots__/scenes-app-insights--stickiness--webkit.png
index 4125f299a358e..d226c57fe43df 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--stickiness--webkit.png and b/frontend/__snapshots__/scenes-app-insights--stickiness--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--stickiness-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--stickiness-edit--webkit.png
index 8eefb8a637100..c458ce60c87b2 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--stickiness-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--stickiness-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--stickiness-edit.png b/frontend/__snapshots__/scenes-app-insights--stickiness-edit.png
index 29db39c34e2c8..80e20f0a84a3e 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--stickiness-edit.png and b/frontend/__snapshots__/scenes-app-insights--stickiness-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--stickiness.png b/frontend/__snapshots__/scenes-app-insights--stickiness.png
index de3afbf8cc7af..5f6daca8e6c78 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--stickiness.png and b/frontend/__snapshots__/scenes-app-insights--stickiness.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-area--webkit.png
index 21aa9bc7551f8..451decec4637d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-area--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown--webkit.png
index b5c8307dea666..77b2e0087b84b 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit--webkit.png
index 9905ed61d7a89..39cb74dee61dd 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit.png
index 18e8183ddefb1..85107049f853f 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown.png
index f412b05f949a1..41ba6d59e1550 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-area-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-area-edit--webkit.png
index 1c9bae1872eee..f70af9d2e782c 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-area-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-area-edit.png
index 2513bc614a783..f57645211428a 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-area-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-area.png b/frontend/__snapshots__/scenes-app-insights--trends-area.png
index 693bb117d362c..fdd0315060948 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-area.png and b/frontend/__snapshots__/scenes-app-insights--trends-area.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-bar--webkit.png
index 029db225e47ab..5d60dee4f60b7 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown--webkit.png
index 7a047299abaef..8df383d36fc1b 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit--webkit.png
index aa1a85fbbf26f..3a7274819f516 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit.png
index 42115a622a205..e32072ec0780d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown.png
index b76b6e7a17d98..03c62e056870b 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-bar-edit--webkit.png
index adb88102026c6..c9bd130f6cdab 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-bar-edit.png
index 1b81ed4977ff1..ffaa1c4bf1988 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-bar.png b/frontend/__snapshots__/scenes-app-insights--trends-bar.png
index cb863bb9c9bb6..74a5209277252 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-bar.png and b/frontend/__snapshots__/scenes-app-insights--trends-bar.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line--webkit.png
index 8aed583ad4064..81275e0a9df95 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown--webkit.png
index a57438bd749a9..ab2904ba751e9 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit--webkit.png
index 2779891938055..966b934574728 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit.png
index 370cd4a4c10a2..ca3343a84046c 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-labels--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-labels--webkit.png
new file mode 100644
index 0000000000000..8f97eb8c1a01c
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-labels--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-labels.png b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-labels.png
new file mode 100644
index 0000000000000..48a045de1d451
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown-labels.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown.png
index 1ec537b3468ad..d4873d617014e 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-edit--webkit.png
index e14d719a073e2..a158e442de8ff 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-edit.png
index fbeb271f50cf0..5e1fb2d08feb2 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-multi--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-multi--webkit.png
index 6015dabcec713..225acef8aacb3 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-multi--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-multi--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit--webkit.png
index 3f2231d07737c..c036f5a792f9e 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit.png
index 649c945bdf267..ca3654b2fd11d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-multi-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line-multi.png b/frontend/__snapshots__/scenes-app-insights--trends-line-multi.png
index 9fc201861aa47..d2c5a5a81dcc9 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line-multi.png and b/frontend/__snapshots__/scenes-app-insights--trends-line-multi.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-line.png b/frontend/__snapshots__/scenes-app-insights--trends-line.png
index e1b4848578966..49bbad9f70249 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-line.png and b/frontend/__snapshots__/scenes-app-insights--trends-line.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-number--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-number--webkit.png
index 17a8821fb39ed..2615d368706cd 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-number--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-number--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-number-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-number-edit--webkit.png
index 796e6548e08c8..635203fb3d413 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-number-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-number-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-number-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-number-edit.png
index 25d7659b28b81..6924135553179 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-number-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-number-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-number.png b/frontend/__snapshots__/scenes-app-insights--trends-number.png
index 48d95207dd24d..693dd022b93e9 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-number.png and b/frontend/__snapshots__/scenes-app-insights--trends-number.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie--webkit.png
index 846479f3753fe..660bb356237ca 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown--webkit.png
index 983851141af8d..cadbd8a861f31 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit--webkit.png
index 5163ac5fdb238..646050c69e70b 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit.png
index e020cb76a7760..bd1f3ed00e233 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-labels--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-labels--webkit.png
new file mode 100644
index 0000000000000..082bca2e23f47
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-labels--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-labels.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-labels.png
new file mode 100644
index 0000000000000..7a1c58bf02c1d
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown-labels.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown.png
index e396c60572415..bc2f9c129b6f9 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-edit--webkit.png
index af5c8b64103fe..3e784f8c855d5 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-pie-edit.png
index 0a8ebe4751399..886c9d33a0add 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-pie.png b/frontend/__snapshots__/scenes-app-insights--trends-pie.png
index 5f83bed8ef407..c6000ed1654c6 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-pie.png and b/frontend/__snapshots__/scenes-app-insights--trends-pie.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-table--webkit.png
index 2ba75da1d8204..cee544d679cc5 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-table--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown--webkit.png
index 063e78dd5feaf..4a32c1bf8df36 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit--webkit.png
index 4196d96dfbd67..dc9333bb1780d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit.png
index 8ae256c8199bf..f9e6a6f710268 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png
index a3a2a9a805370..ed70303f61142 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-table-edit--webkit.png
index fb0e1de7e7310..d71a4ba3b777d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-table-edit.png
index 4ca89e34bfd22..43417b1c2f0ac 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-table-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-table.png b/frontend/__snapshots__/scenes-app-insights--trends-table.png
index e36f384700aee..2507ecadf9e8f 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-table.png and b/frontend/__snapshots__/scenes-app-insights--trends-table.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-value--webkit.png
index a350461bf3689..94e1c6b5604ab 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-value--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown--webkit.png
index 8af97f329f0d5..066eb2c1ac02a 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit--webkit.png
index c626cb8402ae2..63e0e28282346 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit.png
index f45c73c45217e..f3599c707dd15 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown.png b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown.png
index 98d682c860521..a0f6e839e7e60 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown.png and b/frontend/__snapshots__/scenes-app-insights--trends-value-breakdown.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-value-edit--webkit.png
index 48b1f53b59bfb..140d24237944a 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-value-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-value-edit.png
index bdb269d4562ee..c908b3c0a5d9e 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-value-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-value.png b/frontend/__snapshots__/scenes-app-insights--trends-value.png
index 24e25225e9902..ea8fd3d8fd413 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-value.png and b/frontend/__snapshots__/scenes-app-insights--trends-value.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-world-map--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-world-map--webkit.png
index 1ae8bc9fccb15..24462204e7738 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-world-map--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-world-map--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit--webkit.png
index 709a2698bae3b..e11671b67ea0a 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit.png b/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit.png
index 0462e9cfedd78..9fbed136e738d 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit.png and b/frontend/__snapshots__/scenes-app-insights--trends-world-map-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--trends-world-map.png b/frontend/__snapshots__/scenes-app-insights--trends-world-map.png
index e76857963a4de..cbb62ce7deb40 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--trends-world-map.png and b/frontend/__snapshots__/scenes-app-insights--trends-world-map.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--user-paths--webkit.png b/frontend/__snapshots__/scenes-app-insights--user-paths--webkit.png
index 8c15340d735f3..bd9ba9dbf8a97 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--user-paths--webkit.png and b/frontend/__snapshots__/scenes-app-insights--user-paths--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--user-paths-edit--webkit.png b/frontend/__snapshots__/scenes-app-insights--user-paths-edit--webkit.png
index 0db6e20f49afb..ea0ad2f69c6ae 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--user-paths-edit--webkit.png and b/frontend/__snapshots__/scenes-app-insights--user-paths-edit--webkit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--user-paths-edit.png b/frontend/__snapshots__/scenes-app-insights--user-paths-edit.png
index df710f4dd46da..af38b73f25636 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--user-paths-edit.png and b/frontend/__snapshots__/scenes-app-insights--user-paths-edit.png differ
diff --git a/frontend/__snapshots__/scenes-app-insights--user-paths.png b/frontend/__snapshots__/scenes-app-insights--user-paths.png
index ca4c44785108f..deec9d37f5b61 100644
Binary files a/frontend/__snapshots__/scenes-app-insights--user-paths.png and b/frontend/__snapshots__/scenes-app-insights--user-paths.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--bullet-list.png b/frontend/__snapshots__/scenes-app-notebooks--bullet-list.png
index d196998a7e56f..2b56395785ef6 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--bullet-list.png and b/frontend/__snapshots__/scenes-app-notebooks--bullet-list.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--empty-notebook.png b/frontend/__snapshots__/scenes-app-notebooks--empty-notebook.png
index 2086ed0aa90aa..c6df20187e100 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--empty-notebook.png and b/frontend/__snapshots__/scenes-app-notebooks--empty-notebook.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--headings.png b/frontend/__snapshots__/scenes-app-notebooks--headings.png
index 3186fed28fd49..1d202bf688da1 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--headings.png and b/frontend/__snapshots__/scenes-app-notebooks--headings.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png b/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png
index 0df1f64e9ec3c..6286e7ae27078 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png and b/frontend/__snapshots__/scenes-app-notebooks--notebook-not-found.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png b/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png
index c9f29c566c2c6..04209a125f40b 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png and b/frontend/__snapshots__/scenes-app-notebooks--notebooks-list.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--numbered-list.png b/frontend/__snapshots__/scenes-app-notebooks--numbered-list.png
index cbe5aefd199ed..de7c9e016a3d0 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--numbered-list.png and b/frontend/__snapshots__/scenes-app-notebooks--numbered-list.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png
index e18ecc8d6a5a5..b69055ad3d2ec 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png and b/frontend/__snapshots__/scenes-app-notebooks--recordings-playlist.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--text-formats.png b/frontend/__snapshots__/scenes-app-notebooks--text-formats.png
index aa872f0a5cfe9..6f7c0b4c36de0 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--text-formats.png and b/frontend/__snapshots__/scenes-app-notebooks--text-formats.png differ
diff --git a/frontend/__snapshots__/scenes-app-notebooks--text-only-notebook.png b/frontend/__snapshots__/scenes-app-notebooks--text-only-notebook.png
index f0ea3f9550997..c475638688418 100644
Binary files a/frontend/__snapshots__/scenes-app-notebooks--text-only-notebook.png and b/frontend/__snapshots__/scenes-app-notebooks--text-only-notebook.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration.png
new file mode 100644
index 0000000000000..4268b9820e627
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-configuration.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs.png
new file mode 100644
index 0000000000000..fc3f054686e53
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-logs.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics.png
new file mode 100644
index 0000000000000..6e4f613841bdf
Binary files /dev/null and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-app-metrics.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page.png
index 2922f7f7736ff..a000f5709360c 100644
Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-filtering-page.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png
index 72113b0438d81..d5df660c362ee 100644
Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-landing-page.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty.png
index b9810d5bf2186..5655e24e12a0c 100644
Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page-empty.png differ
diff --git a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page.png b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page.png
index 80fdf0c1d8632..06bdfb7c4f880 100644
Binary files a/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page.png and b/frontend/__snapshots__/scenes-app-pipeline--pipeline-transformations-page.png differ
diff --git a/frontend/__snapshots__/scenes-app-project-homepage--project-homepage.png b/frontend/__snapshots__/scenes-app-project-homepage--project-homepage.png
index fe614866ab3d3..84eb120b096bf 100644
Binary files a/frontend/__snapshots__/scenes-app-project-homepage--project-homepage.png and b/frontend/__snapshots__/scenes-app-project-homepage--project-homepage.png differ
diff --git a/frontend/__snapshots__/scenes-app-recordings--recordings-play-lists.png b/frontend/__snapshots__/scenes-app-recordings--recordings-play-lists.png
index c4c27f4db817a..7bb41e1837cc3 100644
Binary files a/frontend/__snapshots__/scenes-app-recordings--recordings-play-lists.png and b/frontend/__snapshots__/scenes-app-recordings--recordings-play-lists.png differ
diff --git a/frontend/__snapshots__/scenes-app-saved-insights--card-view.png b/frontend/__snapshots__/scenes-app-saved-insights--card-view.png
index df6c09ca18009..3349db3182ce2 100644
Binary files a/frontend/__snapshots__/scenes-app-saved-insights--card-view.png and b/frontend/__snapshots__/scenes-app-saved-insights--card-view.png differ
diff --git a/frontend/__snapshots__/scenes-app-saved-insights--empty-state.png b/frontend/__snapshots__/scenes-app-saved-insights--empty-state.png
index 7757d243d548c..7952158fdb025 100644
Binary files a/frontend/__snapshots__/scenes-app-saved-insights--empty-state.png and b/frontend/__snapshots__/scenes-app-saved-insights--empty-state.png differ
diff --git a/frontend/__snapshots__/scenes-app-saved-insights--list-view.png b/frontend/__snapshots__/scenes-app-saved-insights--list-view.png
index 520f2c041c0a8..8bfe21cb3985b 100644
Binary files a/frontend/__snapshots__/scenes-app-saved-insights--list-view.png and b/frontend/__snapshots__/scenes-app-saved-insights--list-view.png differ
diff --git a/frontend/__snapshots__/scenes-app-surveys--survey-templates.png b/frontend/__snapshots__/scenes-app-surveys--survey-templates.png
index 069a66dbfbb5b..d888557c99407 100644
Binary files a/frontend/__snapshots__/scenes-app-surveys--survey-templates.png and b/frontend/__snapshots__/scenes-app-surveys--survey-templates.png differ
diff --git a/frontend/__snapshots__/scenes-app-surveys--surveys-list.png b/frontend/__snapshots__/scenes-app-surveys--surveys-list.png
index 012692ee2758d..80ccaa5e006fd 100644
Binary files a/frontend/__snapshots__/scenes-app-surveys--surveys-list.png and b/frontend/__snapshots__/scenes-app-surveys--surveys-list.png differ
diff --git a/frontend/__snapshots__/scenes-other-login--second-factor.png b/frontend/__snapshots__/scenes-other-login--second-factor.png
index 0eda9f6a6d221..d770df97b4345 100644
Binary files a/frontend/__snapshots__/scenes-other-login--second-factor.png and b/frontend/__snapshots__/scenes-other-login--second-factor.png differ
diff --git a/frontend/__snapshots__/scenes-other-login--sso-error.png b/frontend/__snapshots__/scenes-other-login--sso-error.png
index 4bac52c291407..37309681cfb75 100644
Binary files a/frontend/__snapshots__/scenes-other-login--sso-error.png and b/frontend/__snapshots__/scenes-other-login--sso-error.png differ
diff --git a/frontend/__snapshots__/scenes-other-password-reset-complete--default.png b/frontend/__snapshots__/scenes-other-password-reset-complete--default.png
index b08362e5ab1ab..8671219107f0c 100644
Binary files a/frontend/__snapshots__/scenes-other-password-reset-complete--default.png and b/frontend/__snapshots__/scenes-other-password-reset-complete--default.png differ
diff --git a/frontend/__snapshots__/scenes-other-password-reset-complete--invalid-link.png b/frontend/__snapshots__/scenes-other-password-reset-complete--invalid-link.png
index d5f6503dbfa2b..6e928b3ee74ac 100644
Binary files a/frontend/__snapshots__/scenes-other-password-reset-complete--invalid-link.png and b/frontend/__snapshots__/scenes-other-password-reset-complete--invalid-link.png differ
diff --git a/frontend/__snapshots__/scenes-other-settings--settings-organization.png b/frontend/__snapshots__/scenes-other-settings--settings-organization.png
index 05fee3ba22511..0e5752e576d8b 100644
Binary files a/frontend/__snapshots__/scenes-other-settings--settings-organization.png and b/frontend/__snapshots__/scenes-other-settings--settings-organization.png differ
diff --git a/frontend/__snapshots__/scenes-other-settings--settings-project.png b/frontend/__snapshots__/scenes-other-settings--settings-project.png
index 71514ddb64f12..227e1bac41f89 100644
Binary files a/frontend/__snapshots__/scenes-other-settings--settings-project.png and b/frontend/__snapshots__/scenes-other-settings--settings-project.png differ
diff --git a/frontend/__snapshots__/scenes-other-settings--settings-user.png b/frontend/__snapshots__/scenes-other-settings--settings-user.png
index 5574601d11794..7d18a6db46dd5 100644
Binary files a/frontend/__snapshots__/scenes-other-settings--settings-user.png and b/frontend/__snapshots__/scenes-other-settings--settings-user.png differ
diff --git a/frontend/__snapshots__/scenes-other-toolbar-components--flags.png b/frontend/__snapshots__/scenes-other-toolbar-components--flags.png
index 43dd944036a73..10086fc86f5c1 100644
Binary files a/frontend/__snapshots__/scenes-other-toolbar-components--flags.png and b/frontend/__snapshots__/scenes-other-toolbar-components--flags.png differ
diff --git a/frontend/__snapshots__/scenes-other-unsubscribe--unsubscribe-scene.png b/frontend/__snapshots__/scenes-other-unsubscribe--unsubscribe-scene.png
index 4c1e72c47cc86..e0e34f6fbc61b 100644
Binary files a/frontend/__snapshots__/scenes-other-unsubscribe--unsubscribe-scene.png and b/frontend/__snapshots__/scenes-other-unsubscribe--unsubscribe-scene.png differ
diff --git a/frontend/__snapshots__/scenes-other-verify-email--verify-email-invalid.png b/frontend/__snapshots__/scenes-other-verify-email--verify-email-invalid.png
index ea95c8af90bc0..0291a167335d6 100644
Binary files a/frontend/__snapshots__/scenes-other-verify-email--verify-email-invalid.png and b/frontend/__snapshots__/scenes-other-verify-email--verify-email-invalid.png differ
diff --git a/frontend/__snapshots__/scenes-other-verify-email--verify-email-success.png b/frontend/__snapshots__/scenes-other-verify-email--verify-email-success.png
index 45b7e05851b7a..71aad6c351f8b 100644
Binary files a/frontend/__snapshots__/scenes-other-verify-email--verify-email-success.png and b/frontend/__snapshots__/scenes-other-verify-email--verify-email-success.png differ
diff --git a/frontend/__snapshots__/scenes-other-verify-email--verifying-email.png b/frontend/__snapshots__/scenes-other-verify-email--verifying-email.png
index a6efa516c1cda..ecfc94858c28a 100644
Binary files a/frontend/__snapshots__/scenes-other-verify-email--verifying-email.png and b/frontend/__snapshots__/scenes-other-verify-email--verifying-email.png differ
diff --git a/frontend/src/exporter/ExportedInsight/ExportedInsight.scss b/frontend/src/exporter/ExportedInsight/ExportedInsight.scss
index c158e28a7bc55..bb643d8f0d3a9 100644
--- a/frontend/src/exporter/ExportedInsight/ExportedInsight.scss
+++ b/frontend/src/exporter/ExportedInsight/ExportedInsight.scss
@@ -8,6 +8,8 @@
background: var(--bg-light);
display: flex;
flex-direction: column;
+ height: 100%;
+ flex: 1;
.ExportedInsight__header {
padding: 1rem;
@@ -25,22 +27,19 @@
flex: 1;
position: relative;
z-index: 1;
- .FunnelBarChart {
- min-height: 50vw;
+ display: flex;
+ flex-direction: column;
+
+ .LemonTable {
+ border: none;
+ border-radius: 0;
+ background: none;
}
- .InsightViz {
- position: relative;
- display: flex;
+ .InsightCard__viz {
+ // We can't use the viewport height, as the screenshotter will resize the height of the window to capture the full content
+ // Instead we try to make it roughly rectangular
min-height: 50vw;
-
- > * {
- flex: 1;
- }
-
- .ActionsPie {
- position: absolute;
- }
}
}
@@ -49,36 +48,10 @@
right: 0;
top: 0;
z-index: 2;
+
svg {
font-size: 0.75rem;
margin: 0.25rem;
}
}
-
- &.ExportedInsight--fit-screen {
- height: 100vh;
- max-height: 100vh;
-
- .ExportedInsight__content {
- display: flex;
- flex-direction: column;
-
- .FunnelBarChart {
- height: 100%;
- max-height: 100%;
- min-height: auto;
- flex: 1;
- }
-
- .InsightViz {
- flex: 1;
- min-height: 100px;
- max-height: 100%;
- }
-
- &.ExportedInsight__content--with-watermark {
- padding-top: 1rem;
- }
- }
- }
}
diff --git a/frontend/src/exporter/ExportedInsight/ExportedInsight.tsx b/frontend/src/exporter/ExportedInsight/ExportedInsight.tsx
index 24bfe97cab377..d34818193fd4a 100644
--- a/frontend/src/exporter/ExportedInsight/ExportedInsight.tsx
+++ b/frontend/src/exporter/ExportedInsight/ExportedInsight.tsx
@@ -1,18 +1,20 @@
-import { ChartDisplayType, InsightLogicProps, InsightModel } from '~/types'
+import './ExportedInsight.scss'
+
+import clsx from 'clsx'
import { BindLogic } from 'kea'
-import { insightLogic } from 'scenes/insights/insightLogic'
import { FilterBasedCardContent } from 'lib/components/Cards/InsightCard/InsightCard'
-import './ExportedInsight.scss'
-import { Logo } from '~/toolbar/assets/Logo'
+import { QueriesUnsupportedHere } from 'lib/components/Cards/InsightCard/QueriesUnsupportedHere'
+import { TopHeading } from 'lib/components/Cards/InsightCard/TopHeading'
import { InsightLegend } from 'lib/components/InsightLegend/InsightLegend'
-import { ExportOptions, ExportType } from '~/exporter/types'
-import clsx from 'clsx'
import { SINGLE_SERIES_DISPLAY_TYPES } from 'lib/constants'
+import { insightLogic } from 'scenes/insights/insightLogic'
import { isTrendsFilter } from 'scenes/insights/sharedUtils'
-import { isDataTableNode } from '~/queries/utils'
-import { QueriesUnsupportedHere } from 'lib/components/Cards/InsightCard/QueriesUnsupportedHere'
+
+import { ExportOptions, ExportType } from '~/exporter/types'
import { Query } from '~/queries/Query/Query'
-import { TopHeading } from 'lib/components/Cards/InsightCard/TopHeading'
+import { isDataTableNode } from '~/queries/utils'
+import { Logo } from '~/toolbar/assets/Logo'
+import { ChartDisplayType, InsightLogicProps, InsightModel } from '~/types'
export function ExportedInsight({
insight,
@@ -91,11 +93,7 @@ export function ExportedInsight({
)
) : (
-
+
)}
{showLegend ? (
diff --git a/frontend/src/exporter/Exporter.scss b/frontend/src/exporter/Exporter.scss
index db6d2acc6a495..f861f282a2926 100644
--- a/frontend/src/exporter/Exporter.scss
+++ b/frontend/src/exporter/Exporter.scss
@@ -1,35 +1,10 @@
@import '../styles/mixins';
-html.export-type-image {
- // We don't want scrollbars to show in image captures
- ::-webkit-scrollbar {
- display: none;
- }
-
- body {
- // We put Inter first so that rendered images are the same no matter which platform it is rendered on.
- font-family: 'Inter', 'Segoe UI', 'Roboto', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
- 'Segoe UI Symbol';
- }
-}
-
-html.export-type-embed {
- overflow: hidden;
- overflow-y: auto;
-
- .Exporter {
- padding: 0;
-
- // Insights can resize to fit any height, whereas dashboards cannot
- &--insight {
- height: 100vh;
- max-height: 100vh;
- }
- }
-}
-
.Exporter {
padding: 1rem;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
&--recording {
height: 100vh;
@@ -58,3 +33,26 @@ html.export-type-embed {
}
}
}
+
+html.export-type-image {
+ // We don't want scrollbars to show in image captures
+ ::-webkit-scrollbar {
+ display: none;
+ }
+
+ body {
+ // We put Inter first so that rendered images are the same no matter which platform it is rendered on.
+ font-family: Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
+ 'Segoe UI Symbol';
+ }
+}
+
+html.export-type-embed {
+ overflow: hidden;
+ overflow-y: auto;
+
+ .Exporter {
+ padding: 0;
+ min-height: 100vh;
+ }
+}
diff --git a/frontend/src/exporter/Exporter.stories.tsx b/frontend/src/exporter/Exporter.stories.tsx
index 4c5acbd7257aa..95693b3465ad0 100644
--- a/frontend/src/exporter/Exporter.stories.tsx
+++ b/frontend/src/exporter/Exporter.stories.tsx
@@ -1,9 +1,11 @@
-import { useEffect } from 'react'
import { Meta, StoryFn, StoryObj } from '@storybook/react'
-import { Exporter } from './Exporter'
+import { useEffect } from 'react'
+
import { dashboard } from '~/exporter/__mocks__/Exporter.mocks'
import { ExportType } from '~/exporter/types'
+import { Exporter } from './Exporter'
+
type Story = StoryObj
const meta: Meta = {
title: 'Exporter/Exporter',
diff --git a/frontend/src/exporter/Exporter.tsx b/frontend/src/exporter/Exporter.tsx
index 1941637123e83..0ba873c570fe1 100644
--- a/frontend/src/exporter/Exporter.tsx
+++ b/frontend/src/exporter/Exporter.tsx
@@ -1,18 +1,21 @@
import '~/styles'
import './Exporter.scss'
-import { useEffect } from 'react'
-import { ExportedData, ExportType } from '~/exporter/types'
-import { DashboardPlacement } from '~/types'
-import { ExportedInsight } from '~/exporter/ExportedInsight/ExportedInsight'
-import { Logo } from '~/toolbar/assets/Logo'
-import { Dashboard } from 'scenes/dashboard/Dashboard'
-import { useResizeObserver } from 'lib/hooks/useResizeObserver'
-import { Link } from 'lib/lemon-ui/Link'
+
import clsx from 'clsx'
import { useValues } from 'kea'
-import { teamLogic } from 'scenes/teamLogic'
+import { useResizeObserver } from 'lib/hooks/useResizeObserver'
+import { Link } from 'lib/lemon-ui/Link'
+import { useEffect } from 'react'
+import { Dashboard } from 'scenes/dashboard/Dashboard'
import { SessionRecordingPlayer } from 'scenes/session-recordings/player/SessionRecordingPlayer'
import { SessionRecordingPlayerMode } from 'scenes/session-recordings/player/sessionRecordingPlayerLogic'
+import { teamLogic } from 'scenes/teamLogic'
+
+import { ExportedInsight } from '~/exporter/ExportedInsight/ExportedInsight'
+import { ExportedData, ExportType } from '~/exporter/types'
+import { Logo } from '~/toolbar/assets/Logo'
+import { DashboardPlacement } from '~/types'
+
import { exporterViewLogic } from './exporterViewLogic'
export function Exporter(props: ExportedData): JSX.Element {
diff --git a/frontend/src/exporter/__mocks__/Exporter.mocks.tsx b/frontend/src/exporter/__mocks__/Exporter.mocks.tsx
index fdf477f996322..6d2b7e87d1fad 100644
--- a/frontend/src/exporter/__mocks__/Exporter.mocks.tsx
+++ b/frontend/src/exporter/__mocks__/Exporter.mocks.tsx
@@ -1,3 +1,5 @@
+import { FunnelLayout, ShownAsValue } from 'lib/constants'
+
import {
ChartDisplayType,
DashboardTile,
@@ -7,7 +9,6 @@ import {
InsightShortId,
InsightType,
} from '~/types'
-import { FunnelLayout, ShownAsValue } from 'lib/constants'
export const dashboard: DashboardType = {
id: 1,
diff --git a/frontend/src/exporter/exporterViewLogic.ts b/frontend/src/exporter/exporterViewLogic.ts
index e0c36900fc728..dcb6adf2e137c 100644
--- a/frontend/src/exporter/exporterViewLogic.ts
+++ b/frontend/src/exporter/exporterViewLogic.ts
@@ -1,7 +1,7 @@
import { kea, path, props, selectors } from 'kea'
-import { ExportedData } from './types'
import type { exporterViewLogicType } from './exporterViewLogicType'
+import { ExportedData } from './types'
// This is a simple logic that is mounted by the Exporter view and then can be found by any nested callers
// This simplifies passing props everywhere.
diff --git a/frontend/src/exporter/index.tsx b/frontend/src/exporter/index.tsx
index df1660537cb44..995334d949021 100644
--- a/frontend/src/exporter/index.tsx
+++ b/frontend/src/exporter/index.tsx
@@ -1,10 +1,13 @@
import '~/styles'
import './Exporter.scss'
+
import { createRoot } from 'react-dom/client'
-import { loadPostHogJS } from '~/loadPostHogJS'
-import { initKea } from '~/initKea'
+
import { Exporter } from '~/exporter/Exporter'
import { ExportedData } from '~/exporter/types'
+import { initKea } from '~/initKea'
+import { loadPostHogJS } from '~/loadPostHogJS'
+
import { ErrorBoundary } from '../layout/ErrorBoundary'
// Disable tracking for all exports and embeds.
diff --git a/frontend/src/globals.d.ts b/frontend/src/globals.d.ts
index 17bc65680725a..b03852c10a890 100644
--- a/frontend/src/globals.d.ts
+++ b/frontend/src/globals.d.ts
@@ -1,4 +1,5 @@
import posthog from 'posthog-js'
+
import { ExportedData } from '~/exporter/types'
declare global {
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 42746c188f0ea..272a61f785e3d 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -1,16 +1,14 @@
import '~/styles'
-import { createRoot } from 'react-dom/client'
import { getContext } from 'kea'
-
+import posthog from 'posthog-js'
+import { PostHogProvider } from 'posthog-js/react'
+import { createRoot } from 'react-dom/client'
import { App } from 'scenes/App'
-import { initKea } from './initKea'
-import { loadPostHogJS } from './loadPostHogJS'
+import { initKea } from './initKea'
import { ErrorBoundary } from './layout/ErrorBoundary'
-
-import { PostHogProvider } from 'posthog-js/react'
-import posthog from 'posthog-js'
+import { loadPostHogJS } from './loadPostHogJS'
loadPostHogJS()
initKea()
diff --git a/frontend/src/initKea.ts b/frontend/src/initKea.ts
index 79d727740a4dc..bb5b0af3e5525 100644
--- a/frontend/src/initKea.ts
+++ b/frontend/src/initKea.ts
@@ -1,13 +1,13 @@
import { KeaPlugin, resetContext } from 'kea'
+import { formsPlugin } from 'kea-forms'
+import { loadersPlugin } from 'kea-loaders'
import { localStoragePlugin } from 'kea-localstorage'
import { routerPlugin } from 'kea-router'
-import { loadersPlugin } from 'kea-loaders'
-import { windowValuesPlugin } from 'kea-window-values'
-import { identifierToHuman } from 'lib/utils'
+import { subscriptionsPlugin } from 'kea-subscriptions'
import { waitForPlugin } from 'kea-waitfor'
+import { windowValuesPlugin } from 'kea-window-values'
import { lemonToast } from 'lib/lemon-ui/lemonToast'
-import { subscriptionsPlugin } from 'kea-subscriptions'
-import { formsPlugin } from 'kea-forms'
+import { identifierToHuman } from 'lib/utils'
/*
Actions for which we don't want to show error alerts,
diff --git a/frontend/src/layout/ErrorBoundary/ErrorBoundary.scss b/frontend/src/layout/ErrorBoundary/ErrorBoundary.scss
index c98425d731956..be9ac8887a160 100644
--- a/frontend/src/layout/ErrorBoundary/ErrorBoundary.scss
+++ b/frontend/src/layout/ErrorBoundary/ErrorBoundary.scss
@@ -5,20 +5,24 @@
padding: 0.75rem 1rem 1rem;
min-width: 0;
height: fit-content;
+
.main-app-content > & {
margin: 1.5rem 0;
}
+
h2 {
margin-bottom: 0.75rem;
color: var(--danger);
font-weight: 600;
}
+
pre {
margin-bottom: 0.75rem;
background: var(--border-light);
border-radius: var(--radius);
padding: 0.75rem 1rem;
}
+
.help-button {
margin-top: 0.75rem;
}
diff --git a/frontend/src/layout/ErrorBoundary/ErrorBoundary.tsx b/frontend/src/layout/ErrorBoundary/ErrorBoundary.tsx
index 456b89a8ab65b..78dde9a6d6b3a 100644
--- a/frontend/src/layout/ErrorBoundary/ErrorBoundary.tsx
+++ b/frontend/src/layout/ErrorBoundary/ErrorBoundary.tsx
@@ -1,8 +1,9 @@
-import { getCurrentHub, ErrorBoundary as SentryErrorBoundary } from '@sentry/react'
+import './ErrorBoundary.scss'
+
+import { ErrorBoundary as SentryErrorBoundary, getCurrentHub } from '@sentry/react'
import { HelpButton } from 'lib/components/HelpButton/HelpButton'
import { IconArrowDropDown } from 'lib/lemon-ui/icons'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
-import './ErrorBoundary.scss'
export function ErrorBoundary({ children }: { children: React.ReactElement }): JSX.Element {
const isSentryInitialized = !!getCurrentHub().getClient()
diff --git a/frontend/src/layout/ErrorNetwork.tsx b/frontend/src/layout/ErrorNetwork.tsx
index 01473440a0801..a415d1fc8028d 100644
--- a/frontend/src/layout/ErrorNetwork.tsx
+++ b/frontend/src/layout/ErrorNetwork.tsx
@@ -1,5 +1,5 @@
-import { LemonButton } from 'lib/lemon-ui/LemonButton'
import { IconRefresh } from 'lib/lemon-ui/icons'
+import { LemonButton } from 'lib/lemon-ui/LemonButton'
export function ErrorNetwork(): JSX.Element {
return (
diff --git a/frontend/src/layout/ErrorProjectUnavailable.tsx b/frontend/src/layout/ErrorProjectUnavailable.tsx
index a3660e42c37cc..29a178c490b05 100644
--- a/frontend/src/layout/ErrorProjectUnavailable.tsx
+++ b/frontend/src/layout/ErrorProjectUnavailable.tsx
@@ -1,5 +1,6 @@
-import { PageHeader } from 'lib/components/PageHeader'
import { useValues } from 'kea'
+import { PageHeader } from 'lib/components/PageHeader'
+
import { organizationLogic } from '../scenes/organizationLogic'
export function ErrorProjectUnavailable(): JSX.Element {
diff --git a/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.stories.tsx b/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.stories.tsx
index 45025c5d8132c..8853e4812c90a 100644
--- a/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.stories.tsx
+++ b/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.stories.tsx
@@ -1,9 +1,11 @@
import { Meta, StoryFn, StoryObj } from '@storybook/react'
-import { FeaturePreviewsModal as FeaturePreviewsModalComponent } from './FeaturePreviewsModal'
-import { setFeatureFlags, useStorybookMocks } from '~/mocks/browser'
+import { FeatureFlagKey } from 'lib/constants'
import { EarlyAccessFeature } from 'posthog-js'
+
+import { setFeatureFlags, useStorybookMocks } from '~/mocks/browser'
+
import { CONSTRAINED_PREVIEWS } from './featurePreviewsLogic'
-import { FeatureFlagKey } from 'lib/constants'
+import { FeaturePreviewsModal as FeaturePreviewsModalComponent } from './FeaturePreviewsModal'
interface StoryProps {
earlyAccessFeatures: EarlyAccessFeature[]
diff --git a/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.tsx b/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.tsx
index cb120f597a5b1..5899f59b82d47 100644
--- a/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.tsx
+++ b/frontend/src/layout/FeaturePreviews/FeaturePreviewsModal.tsx
@@ -1,9 +1,10 @@
import { LemonButton, LemonDivider, LemonModal, LemonSwitch, LemonTextArea, Link } from '@posthog/lemon-ui'
-import { useActions, useValues, useAsyncActions } from 'kea'
+import clsx from 'clsx'
+import { useActions, useAsyncActions, useValues } from 'kea'
import { SpinnerOverlay } from 'lib/lemon-ui/Spinner'
import { useLayoutEffect, useState } from 'react'
+
import { EnrichedEarlyAccessFeature, featurePreviewsLogic } from './featurePreviewsLogic'
-import clsx from 'clsx'
export function FeaturePreviewsModal({
inline,
@@ -120,9 +121,10 @@ function FeaturePreview({ feature }: { feature: EnrichedEarlyAccessFeature }): J
/>
{
- await submitEarlyAccessFeatureFeedback(feedback)
- setFeedback('')
+ onClick={() => {
+ void submitEarlyAccessFeatureFeedback(feedback).then(() => {
+ setFeedback('')
+ })
}}
loading={activeFeedbackFlagKeyLoading}
fullWidth
diff --git a/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx b/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx
index 40c2e201be346..1dc54a618c214 100644
--- a/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx
+++ b/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx
@@ -1,12 +1,13 @@
-import { actions, kea, reducers, path, selectors, connect, listeners } from 'kea'
-import { EarlyAccessFeature, posthog } from 'posthog-js'
+import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea'
import { loaders } from 'kea-loaders'
-import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
+import { actionToUrl, router, urlToAction } from 'kea-router'
import { supportLogic } from 'lib/components/Support/supportLogic'
-import { userLogic } from 'scenes/userLogic'
import { FEATURE_FLAGS, FeatureFlagKey } from 'lib/constants'
+import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
+import { EarlyAccessFeature, posthog } from 'posthog-js'
+import { userLogic } from 'scenes/userLogic'
+
import type { featurePreviewsLogicType } from './featurePreviewsLogicType'
-import { actionToUrl, router, urlToAction } from 'kea-router'
/** Features that can only be toggled if you fall under the `${flagKey}-preview` flag */
export const CONSTRAINED_PREVIEWS: Set = new Set([FEATURE_FLAGS.POSTHOG_3000])
diff --git a/frontend/src/layout/FeaturePreviews/index.ts b/frontend/src/layout/FeaturePreviews/index.ts
index 08a91428b164b..6101040e9e9f2 100644
--- a/frontend/src/layout/FeaturePreviews/index.ts
+++ b/frontend/src/layout/FeaturePreviews/index.ts
@@ -1,2 +1,2 @@
-export { FeaturePreviewsModal } from './FeaturePreviewsModal'
export { featurePreviewsLogic } from './featurePreviewsLogic'
+export { FeaturePreviewsModal } from './FeaturePreviewsModal'
diff --git a/frontend/src/layout/GlobalModals.tsx b/frontend/src/layout/GlobalModals.tsx
index 83e61a3476da0..e2041d0f72dc8 100644
--- a/frontend/src/layout/GlobalModals.tsx
+++ b/frontend/src/layout/GlobalModals.tsx
@@ -1,18 +1,19 @@
-import { kea, path, actions, reducers, useActions, useValues } from 'kea'
-import { CreateOrganizationModal } from 'scenes/organization/CreateOrganizationModal'
-import { CreateProjectModal } from 'scenes/project/CreateProjectModal'
-
-import type { globalModalsLogicType } from './GlobalModalsType'
-import { FeaturePreviewsModal } from './FeaturePreviews'
-import { UpgradeModal } from 'scenes/UpgradeModal'
import { LemonModal } from '@posthog/lemon-ui'
-import { Setup2FA } from 'scenes/authentication/Setup2FA'
-import { userLogic } from 'scenes/userLogic'
-import { membersLogic } from 'scenes/organization/membersLogic'
+import { actions, kea, path, reducers, useActions, useValues } from 'kea'
import { FlaggedFeature } from 'lib/components/FlaggedFeature'
+import { HedgehogBuddyWithLogic } from 'lib/components/HedgehogBuddy/HedgehogBuddy'
import { Prompt } from 'lib/logic/newPrompt/Prompt'
+import { Setup2FA } from 'scenes/authentication/Setup2FA'
+import { CreateOrganizationModal } from 'scenes/organization/CreateOrganizationModal'
+import { membersLogic } from 'scenes/organization/membersLogic'
+import { CreateProjectModal } from 'scenes/project/CreateProjectModal'
import { inviteLogic } from 'scenes/settings/organization/inviteLogic'
import { InviteModal } from 'scenes/settings/organization/InviteModal'
+import { UpgradeModal } from 'scenes/UpgradeModal'
+import { userLogic } from 'scenes/userLogic'
+
+import { FeaturePreviewsModal } from './FeaturePreviews'
+import type { globalModalsLogicType } from './GlobalModalsType'
export const globalModalsLogic = kea([
path(['layout', 'navigation', 'globalModalsLogic']),
@@ -76,6 +77,7 @@ export function GlobalModals(): JSX.Element {
+
>
)
}
diff --git a/frontend/src/layout/navigation-3000/Navigation.scss b/frontend/src/layout/navigation-3000/Navigation.scss
index a4c8e0bbffeb4..74236f4e9a7fc 100644
--- a/frontend/src/layout/navigation-3000/Navigation.scss
+++ b/frontend/src/layout/navigation-3000/Navigation.scss
@@ -15,6 +15,12 @@
min-width: 0;
overflow: auto;
}
+
+ .BridgePage {
+ background: none;
+ height: 100%;
+ overflow: visible;
+ }
}
.Navigation3000__scene {
@@ -22,9 +28,11 @@
position: relative;
margin: var(--scene-padding-y) var(--scene-padding-x);
min-height: calc(100vh - var(--breadcrumbs-height-full) - var(--scene-padding-y) * 2);
+
&.Navigation3000__scene--raw {
--scene-padding-y: 0px;
--scene-padding-x: 0px;
+
display: flex;
flex-direction: column;
}
@@ -49,8 +57,10 @@
z-index: var(--z-main-nav);
.LemonButton {
- min-height: 2.25rem !important; // Reduce minimum height
- padding: 0.375rem !important; // Use a custom padding for the navbar only
+ .LemonButton__chrome {
+ padding: 0.25rem !important;
+ font-size: 0.8125rem;
+ }
}
ul {
@@ -62,16 +72,18 @@
}
li + li {
- margin-top: 1px;
+ margin-top: -1px;
}
}
}
.NavbarButton {
position: relative;
+
.LemonButton__icon {
transition: color 100ms ease, transform 100ms ease;
}
+
&.NavbarButton--here {
&::after {
content: '•';
@@ -84,6 +96,7 @@
line-height: 0.5625rem;
color: var(--default);
}
+
.LemonButton__icon {
color: var(--default);
transform: translateY(-0.25rem);
@@ -98,7 +111,9 @@
--sidebar-horizontal-padding: 0.5rem;
--sidebar-row-height: 2rem;
--sidebar-background: var(--bg-3000);
+
position: relative;
+
// This border is just for sizing, the visible border is on the content and slider
// Hidden when the sidebar is closed
border-right: min(1px, var(--sidebar-width)) solid transparent;
@@ -122,23 +137,27 @@
margin: 0;
line-height: inherit;
}
+
h3 {
font-weight: 600;
line-height: 2rem;
font-size: 0.75rem;
}
+
h4 {
font-weight: 600;
line-height: 1.75rem;
font-size: 0.6875rem;
flex-grow: 1;
}
+
h5 {
font-weight: 400;
font-size: 0.75rem;
text-transform: none;
letter-spacing: normal;
}
+
b {
font-weight: 700;
}
@@ -164,6 +183,7 @@
white-space: nowrap;
overflow: hidden;
background: var(--sidebar-background);
+
// Extend the border into viewport overscroll
border-right: min(1px, var(--sidebar-width)) solid var(--border);
@@ -182,8 +202,7 @@
flex-direction: column;
align-items: stretch;
flex-grow: 1;
- overflow-x: hidden;
- overflow-y: auto;
+ overflow: hidden auto;
}
.Sidebar3000__hint {
@@ -206,6 +225,7 @@
right: calc(
-1 * var(--sidebar-slider-padding) - min(1px, var(--sidebar-width))
); // Center around the original sidebar border
+
width: calc(2 * var(--sidebar-slider-padding) + 1px); // The interactive area is enlarged for easier interaction
cursor: col-resize;
user-select: none; // Fixes inadvertent selection of scene text when resizing
@@ -222,23 +242,28 @@
width: 1px;
pointer-events: none;
}
+
&::before {
transition: 100ms ease transform;
background: var(--border);
}
+
&::after {
transition: 100ms ease transform;
background: var(--text-3000);
opacity: 0;
}
+
&:hover::after,
.Sidebar3000--resizing &::after {
opacity: 0.25;
}
+
.Sidebar3000--resizing &::before,
.Sidebar3000--resizing &::after {
transform: scaleX(3);
}
+
.Sidebar3000[aria-hidden='true'] & {
cursor: e-resize;
}
@@ -260,20 +285,25 @@
--accordion-inset-expandable: 1.25rem;
--accordion-header-background: var(--accent-3000);
--accordion-inset: 0rem;
+
min-height: var(--accordion-row-height);
flex-shrink: 0;
flex-basis: 0;
display: flex;
flex-direction: column;
+
[theme='dark'] & {
--accordion-header-background: var(--bg-3000);
}
+
&[aria-expanded] {
// This means: if accordion is expandable
--accordion-inset: var(--accordion-inset-expandable);
}
+
&:not([aria-expanded='false']) {
flex-grow: 1;
+
&:not(:last-child) {
border-bottom-width: 1px;
}
@@ -283,10 +313,12 @@
.Accordion[aria-disabled='true'] {
.Accordion__header {
cursor: default;
+
&:hover {
background: var(--accordion-header-background);
}
}
+
&:not([aria-busy='true']) .Accordion__header .LemonIcon {
visibility: hidden;
}
@@ -302,14 +334,17 @@
border-bottom-width: 1px;
cursor: pointer;
user-select: none;
+
&:hover {
background: var(--border-3000);
}
+
> .LemonIcon {
transition: 50ms ease transform;
font-size: var(--accordion-arrow-size);
flex-shrink: 0;
margin-right: calc(var(--accordion-inset-expandable) - var(--accordion-arrow-size));
+
.Accordion[aria-expanded='true'] & {
transform: rotate(90deg);
}
@@ -321,6 +356,7 @@
--sidebar-list-item-fold-size: 0.5rem;
--sidebar-list-item-ribbon-width: 0.1875rem;
--sidebar-list-item-background: var(--sidebar-background);
+
position: relative;
color: var(--muted);
line-height: 1.125rem;
@@ -333,8 +369,10 @@
&[aria-current='page'],
&.SidebarListItem--is-renaming {
opacity: 1;
+
--sidebar-list-item-background: var(--border-3000);
}
+
&:hover,
&:focus-within,
&[aria-current='page'],
@@ -343,14 +381,17 @@
.SidebarListItem__actions {
display: flex;
}
+
// Accommodate menu button by moving stuff out of the way
&.SidebarListItem--has-menu:not(.SidebarListItem--extended) .SidebarListItem__link {
padding-right: calc(var(--sidebar-horizontal-padding) + 1.25rem);
}
+
&.SidebarListItem--has-menu.SidebarListItem--extended {
&::after {
content: '';
position: absolute;
+
// Position 1px away so that the :focus-visible border isn't overlaid
top: 1px;
right: 1px;
@@ -377,6 +418,7 @@
z-index: 1;
}
}
+
&.SidebarListItem--marker-fold {
&::before {
width: 0;
@@ -385,23 +427,29 @@
border-bottom: var(--sidebar-list-item-fold-size) solid transparent;
}
}
+
&.SidebarListItem--marker-ribbon {
--sidebar-list-item-marker-offset: var(--sidebar-list-item-ribbon-width);
+
&::before {
width: var(--sidebar-list-item-ribbon-width);
height: 100%;
background: var(--sidebar-list-item-status-color);
}
}
+
&.SidebarListItem--marker-status-success {
--sidebar-list-item-status-color: var(--success);
}
+
&.SidebarListItem--marker-status-warning {
--sidebar-list-item-status-color: var(--warning);
}
+
&.SidebarListItem--marker-status-danger {
--sidebar-list-item-status-color: var(--danger);
}
+
&.SidebarListItem--marker-status-completion {
--sidebar-list-item-status-color: var(--purple);
}
@@ -412,6 +460,7 @@
--sidebar-list-item-inset: calc(
var(--accordion-inset, 0px) + var(--sidebar-horizontal-padding) + var(--sidebar-list-item-marker-offset, 0px)
);
+
position: relative;
display: flex;
flex-direction: column;
@@ -419,13 +468,11 @@
width: 100%;
height: 100%;
color: inherit;
+
&:focus-visible::after {
content: '';
position: absolute;
- top: 0;
- left: 0;
- bottom: -1px;
- right: 0;
+ inset: 0 0 -1px;
border: 1px solid var(--default);
pointer-events: none;
}
@@ -443,6 +490,7 @@
.SidebarListItem__rename {
// Pseudo-elements don't work on inputs, so we use a wrapper div
background: var(--bg-light);
+
input {
outline: none;
height: 100%;
@@ -452,15 +500,14 @@
padding: 0 calc(var(--sidebar-horizontal-padding) + 2.5rem) 0 var(--sidebar-list-item-inset);
background: none;
}
+
&::after {
content: '';
position: absolute;
- top: 0;
- left: 0;
- bottom: -1px;
- right: 0;
+ inset: 0 0 -1px;
border: 1px solid var(--default);
pointer-events: none;
+
.SidebarListItem[aria-invalid='true'] & {
border-color: var(--danger);
}
@@ -477,6 +524,7 @@
background: var(--danger);
color: #fff;
white-space: normal;
+
&::before {
display: block;
content: '';
diff --git a/frontend/src/layout/navigation-3000/Navigation.stories.tsx b/frontend/src/layout/navigation-3000/Navigation.stories.tsx
index 73d7298878007..bc31a2d8079d3 100644
--- a/frontend/src/layout/navigation-3000/Navigation.stories.tsx
+++ b/frontend/src/layout/navigation-3000/Navigation.stories.tsx
@@ -1,11 +1,12 @@
import { Meta } from '@storybook/react'
-import { mswDecorator, setFeatureFlags } from '~/mocks/browser'
-import { useEffect } from 'react'
import { router } from 'kea-router'
-import { urls } from 'scenes/urls'
+import { FEATURE_FLAGS } from 'lib/constants'
+import { useEffect } from 'react'
import { App } from 'scenes/App'
+import { urls } from 'scenes/urls'
+
+import { mswDecorator, setFeatureFlags } from '~/mocks/browser'
import { EMPTY_PAGINATED_RESPONSE } from '~/mocks/handlers'
-import { FEATURE_FLAGS } from 'lib/constants'
const meta: Meta = {
title: 'PostHog 3000/Navigation',
diff --git a/frontend/src/layout/navigation-3000/Navigation.tsx b/frontend/src/layout/navigation-3000/Navigation.tsx
index 851a3fe2b86ab..dff2a25ec7ca4 100644
--- a/frontend/src/layout/navigation-3000/Navigation.tsx
+++ b/frontend/src/layout/navigation-3000/Navigation.tsx
@@ -1,37 +1,45 @@
-import { CommandPalette } from 'lib/components/CommandPalette/CommandPalette'
+import './Navigation.scss'
+
+import clsx from 'clsx'
import { useMountedLogic, useValues } from 'kea'
+import { CommandPalette } from 'lib/components/CommandPalette/CommandPalette'
+import { FlaggedFeature } from 'lib/components/FlaggedFeature'
+import { FEATURE_FLAGS } from 'lib/constants'
import { ReactNode, useEffect } from 'react'
+import { SceneConfig } from 'scenes/sceneTypes'
+
import { Breadcrumbs } from './components/Breadcrumbs'
+import { MinimalNavigation } from './components/MinimalNavigation'
import { Navbar } from './components/Navbar'
import { Sidebar } from './components/Sidebar'
-import './Navigation.scss'
-import { themeLogic } from './themeLogic'
import { navigation3000Logic } from './navigationLogic'
-import clsx from 'clsx'
-import { Scene, SceneConfig } from 'scenes/sceneTypes'
-import { FlaggedFeature } from 'lib/components/FlaggedFeature'
-import { FEATURE_FLAGS } from 'lib/constants'
import { SidePanel } from './sidepanel/SidePanel'
+import { themeLogic } from './themeLogic'
export function Navigation({
children,
sceneConfig,
}: {
children: ReactNode
- scene: Scene | null
sceneConfig: SceneConfig | null
}): JSX.Element {
useMountedLogic(themeLogic)
- const { activeNavbarItem } = useValues(navigation3000Logic)
+ const { activeNavbarItem, mode } = useValues(navigation3000Logic)
useEffect(() => {
// FIXME: Include debug notice in a non-obstructing way
document.getElementById('bottom-notice')?.remove()
}, [])
- if (sceneConfig?.layout === 'plain') {
- return <>{children}>
+ if (mode !== 'full') {
+ return (
+