Skip to content

Commit

Permalink
Merge branch 'master' into feat/toolbar-3000
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldambra committed Sep 10, 2023
2 parents 5857e10 + 0747e00 commit ff797d2
Show file tree
Hide file tree
Showing 54 changed files with 2,152 additions and 775 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
cypress:
name: Cypress E2E tests (${{ strategy.job-index }})
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 60
needs: [chunks, changes]
permissions:
id-token: write # allow issuing OIDC tokens for this workflow run
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const TheHedgehog: StoryFn<typeof HedgehogBuddy> = () => {
// eslint-disable-next-line no-console
console.log('should close')
}}
isDarkModeOn={false}
/>
</div>
)
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/HedgehogBuddy/HedgehogBuddy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ export function HedgehogBuddy({
onPositionChange?: (actor: HedgehogActor) => void
popoverOverlay?: React.ReactNode
// passed in as this might need to be the app's global dark mode setting or the toolbar's local one
isDarkModeOn?: boolean
isDarkModeOn: boolean
}): JSX.Element {
const actorRef = useRef<HedgehogActor>()

Expand All @@ -423,7 +423,7 @@ export function HedgehogBuddy({
}, [accessories])

useEffect(() => {
actor.darkMode = !!isDarkModeOn
actor.darkMode = isDarkModeOn
}, [isDarkModeOn])

useEffect(() => {
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,13 @@ export function HogQLQueryEditor(props: HogQLQueryEditorProps): JSX.Element {
onClick={saveAsView}
type="primary"
center
disabledReason={!isValidView && 'All fields must have an alias'}
disabledReason={
hasErrors
? error ?? 'Query has errors'
: !isValidView
? 'All fields must have an alias'
: ''
}
data-attr="hogql-query-editor-save-as-view"
>
{'Save as View'}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/queries/nodes/SavedInsight/SavedInsight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function SavedInsight({ query, context, cachedResults }: InsightProps): J

return (
<Query
query={{ kind: NodeKind.InsightVizNode, source: filtersToQueryNode(insight.filters) }}
query={{ ...query, kind: NodeKind.InsightVizNode, source: filtersToQueryNode(insight.filters) }}
context={{ ...context, insightProps }}
/>
)
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1888,12 +1888,41 @@
"SavedInsightNode": {
"additionalProperties": false,
"properties": {
"embedded": {
"description": "Query is embedded inside another bordered component",
"type": "boolean"
},
"full": {
"description": "Show with most visual options enabled. Used in insight scene.",
"type": "boolean"
},
"kind": {
"const": "SavedInsightNode",
"type": "string"
},
"shortId": {
"$ref": "#/definitions/InsightShortId"
},
"showCorrelationTable": {
"type": "boolean"
},
"showFilters": {
"type": "boolean"
},
"showHeader": {
"type": "boolean"
},
"showLastComputation": {
"type": "boolean"
},
"showLastComputationRefresh": {
"type": "boolean"
},
"showResults": {
"type": "boolean"
},
"showTable": {
"type": "boolean"
}
},
"required": ["kind", "shortId"],
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,17 +326,19 @@ export interface DataTableNode extends Node {

// Saved insight node

export interface SavedInsightNode extends Node {
export interface SavedInsightNode extends Node, InsightVizNodeViewProps {
kind: NodeKind.SavedInsightNode
shortId: InsightShortId
}

// Insight viz node

export interface InsightVizNode extends Node {
export interface InsightVizNode extends Node, InsightVizNodeViewProps {
kind: NodeKind.InsightVizNode
source: InsightQueryNode
}

interface InsightVizNodeViewProps {
/** Show with most visual options enabled. Used in insight scene. */
full?: boolean
showHeader?: boolean
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@tiptap/react'
import { ReactNode, useCallback, useRef } from 'react'
import clsx from 'clsx'
import { IconClose, IconDragHandle, IconLink, IconUnfoldLess, IconUnfoldMore } from 'lib/lemon-ui/icons'
import { IconClose, IconDragHandle, IconFilter, IconLink, IconUnfoldLess, IconUnfoldMore } from 'lib/lemon-ui/icons'
import { LemonButton } from '@posthog/lemon-ui'
import './NodeWrapper.scss'
import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
Expand Down Expand Up @@ -84,7 +84,7 @@ export function NodeWrapper<T extends CustomNotebookNodeAttributes>({
}
const nodeLogic = useMountedLogic(notebookNodeLogic(nodeLogicProps))
const { title, resizeable, expanded } = useValues(nodeLogic)
const { setExpanded, deleteNode } = useActions(nodeLogic)
const { setExpanded, deleteNode, setWidgetsVisible } = useActions(nodeLogic)

const [ref, inView] = useInView({ triggerOnce: true })
const contentRef = useRef<HTMLDivElement | null>(null)
Expand Down Expand Up @@ -163,6 +163,14 @@ export function NodeWrapper<T extends CustomNotebookNodeAttributes>({
/>
)}

{!!widgets.length && isEditable ? (
<LemonButton
onClick={() => setWidgetsVisible(true)}
size="small"
icon={<IconFilter />}
/>
) : null}

{isEditable && (
<LemonButton
onClick={() => deleteNode()}
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/scenes/notebooks/Nodes/notebookNodeLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const notebookNodeLogic = kea<notebookNodeLogicType>([
timestamp,
sessionRecordingId,
}),
setWidgetsVisible: (visible: boolean) => ({ visible }),
setPreviousNode: (node: Node | null) => ({ node }),
setNextNode: (node: Node | null) => ({ node }),
deleteNode: true,
Expand Down Expand Up @@ -105,12 +106,22 @@ export const notebookNodeLogic = kea<notebookNodeLogicType>([
setNextNode: (_, { node }) => node,
},
],
widgetsVisible: [
false,
{
setWidgetsVisible: (_, { visible }) => visible,
},
],
})),

selectors({
notebookLogic: [(_, p) => [p.notebookLogic], (notebookLogic) => notebookLogic],
nodeAttributes: [(_, p) => [p.nodeAttributes], (nodeAttributes) => nodeAttributes],
widgets: [(_, p) => [p.widgets], (widgets) => widgets],
isShowingWidgets: [
(s, p) => [s.widgetsVisible, p.widgets],
(widgetsVisible, widgets) => !!widgets.length && widgetsVisible,
],
}),

listeners(({ actions, values, props }) => ({
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/notebooks/Notebook/Notebook.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
.NotebookSidebar {
position: relative;
width: 0px;
margin-top: 3.5rem; // Account for title
margin-top: 3.6rem; // Account for title
transition: width var(--notebook-popover-transition-properties);

.NotebookSidebar__content {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/scenes/notebooks/Notebook/NotebookSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ export const NotebookSidebar = (): JSX.Element | null => {
}

export const Widgets = ({ logic }: { logic: BuiltLogic<notebookNodeLogicType> }): JSX.Element | null => {
const { widgets, nodeAttributes } = useValues(logic)
const { updateAttributes } = useActions(logic)
const { widgets, nodeAttributes, isShowingWidgets } = useValues(logic)
const { updateAttributes, setWidgetsVisible } = useActions(logic)

if (widgets.length === 0) {
if (!isShowingWidgets) {
return null
}

return (
<div className="NotebookNodeSettings__widgets space-y-2 w-full">
{widgets.map(({ key, label, Component }) => (
<LemonWidget key={key} title={label}>
<LemonWidget key={key} title={label} onClose={() => setWidgetsVisible(false)}>
<Component attributes={nodeAttributes} updateAttributes={updateAttributes} />
</LemonWidget>
))}
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/scenes/notebooks/Notebook/notebookLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,7 @@ export const notebookLogic = kea<notebookLogicType>([
],
isShowingSidebar: [
(s) => [s.selectedNodeLogic],
(selectedNodeLogic) => {
return !!selectedNodeLogic?.values.widgets.length
},
(selectedNodeLogic) => selectedNodeLogic?.values.isShowingWidgets,
],
}),
sharedListeners(({ values, actions }) => ({
Expand Down
84 changes: 44 additions & 40 deletions frontend/src/scenes/onboarding/Onboarding.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SceneExport } from 'scenes/sceneTypes'
import { useActions, useValues } from 'kea'
import { useEffect } from 'react'
import { useEffect, useState } from 'react'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { FEATURE_FLAGS } from 'lib/constants'
import { urls } from 'scenes/urls'
Expand All @@ -9,6 +9,8 @@ import { SDKs } from './sdks/SDKs'
import { OnboardingProductIntro } from './OnboardingProductIntro'
import { OnboardingStep } from './OnboardingStep'
import { ProductKey } from '~/types'
import { ProductAnalyticsSDKInstructions } from './sdks/product-analytics/ProductAnalyticsSDKInstructions'
import { SessionReplaySDKInstructions } from './sdks/session-replay/SessionReplaySDKInstructions'

export const scene: SceneExport = {
component: Onboarding,
Expand All @@ -18,65 +20,57 @@ export const scene: SceneExport = {
const OnboardingWrapper = ({ children }: { children: React.ReactNode }): JSX.Element => {
const { onboardingStep } = useValues(onboardingLogic)
const { setTotalOnboardingSteps } = useActions(onboardingLogic)
const { product } = useValues(onboardingLogic)
const [allSteps, setAllSteps] = useState<JSX.Element[]>([])

useEffect(() => {
setTotalOnboardingSteps(Array.isArray(children) ? children.length : 1)
createAllSteps()
}, [children])

if (!Array.isArray(children)) {
return children as JSX.Element
useEffect(() => {
setTotalOnboardingSteps(allSteps.length)
}, [allSteps])

if (!product || !children) {
return <></>
}

const createAllSteps = (): void => {
const ProductIntro = <OnboardingProductIntro product={product} />
if (Array.isArray(children)) {
setAllSteps([ProductIntro, ...children])
} else {
setAllSteps([ProductIntro, children as JSX.Element])
}
setTotalOnboardingSteps(Array.isArray(children) ? children.length : 1)
}
return children ? (children[onboardingStep - 1] as JSX.Element) : <></>

return (allSteps[onboardingStep - 1] as JSX.Element) || <></>
}

const ProductAnalyticsOnboarding = (): JSX.Element => {
const { product } = useValues(onboardingLogic)

return product ? (
return (
<OnboardingWrapper>
<OnboardingProductIntro product={product} />
<SDKs usersAction="collecting events" />
<SDKs usersAction="collecting events" sdkInstructionMap={ProductAnalyticsSDKInstructions} />
<OnboardingStep title="my onboarding step" subtitle="my onboarding subtitle">
<div>my onboarding content</div>
</OnboardingStep>
</OnboardingWrapper>
) : (
<></>
)
}
const SessionReplayOnboarding = (): JSX.Element => {
const { product } = useValues(onboardingLogic)

return product ? (
return (
<OnboardingWrapper>
<OnboardingProductIntro product={product} />
<SDKs usersAction="recording sessions" />
<SDKs
usersAction="recording sessions"
sdkInstructionMap={SessionReplaySDKInstructions}
subtitle="Choose the framework your frontend is built on, or use our all-purpose JavaScript library."
/>
</OnboardingWrapper>
) : (
<></>
)
}
const FeatureFlagsOnboarding = (): JSX.Element => {
const { product } = useValues(onboardingLogic)

return product ? (
<OnboardingWrapper>
<OnboardingProductIntro product={product} />
<SDKs usersAction="loading flags" />
</OnboardingWrapper>
) : (
<></>
)
}

const getOnboarding = (productKey: string): JSX.Element => {
const onboardingViews = {
[ProductKey.PRODUCT_ANALYTICS]: ProductAnalyticsOnboarding,
[ProductKey.SESSION_REPLAY]: SessionReplayOnboarding,
[ProductKey.FEATURE_FLAGS]: FeatureFlagsOnboarding,
}
const OnboardingView = onboardingViews[productKey]
return OnboardingView ? <OnboardingView /> : <></>
return <OnboardingWrapper>{/* <SDKs usersAction="loading flags" /> */}</OnboardingWrapper>
}

export function Onboarding(): JSX.Element | null {
Expand All @@ -89,5 +83,15 @@ export function Onboarding(): JSX.Element | null {
}
}, [])

return product ? getOnboarding(product.type) : null
if (!product) {
return <></>
}
const onboardingViews = {
[ProductKey.PRODUCT_ANALYTICS]: ProductAnalyticsOnboarding,
[ProductKey.SESSION_REPLAY]: SessionReplayOnboarding,
[ProductKey.FEATURE_FLAGS]: FeatureFlagsOnboarding,
}
const OnboardingView = onboardingViews[product.type]

return <OnboardingView />
}
15 changes: 14 additions & 1 deletion frontend/src/scenes/onboarding/OnboardingProductIntro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { convertLargeNumberToWords } from 'scenes/billing/billing-utils'
import { BillingProductV2Type } from '~/types'
import { LemonCard } from 'lib/lemon-ui/LemonCard/LemonCard'
import { ProductPricingModal } from 'scenes/billing/ProductPricingModal'
import { IconCheckCircleOutline, IconOpenInNew } from 'lib/lemon-ui/icons'
import { IconArrowLeft, IconCheckCircleOutline, IconOpenInNew } from 'lib/lemon-ui/icons'
import { urls } from 'scenes/urls'

export const OnboardingProductIntro = ({ product }: { product: BillingProductV2Type }): JSX.Element => {
const { currentAndUpgradePlans, isPricingModalOpen } = useValues(billingProductLogic({ product }))
Expand All @@ -31,6 +32,18 @@ export const OnboardingProductIntro = ({ product }: { product: BillingProductV2T
<div className="flex flex-col w-full p-6 bg-mid items-center justify-center">
<div className="max-w-lg flex flex-wrap my-8 items-center">
<div className="w-1/2 pr-6 min-w-80">
<div className="flex mb-6">
<LemonButton
to={urls.products()}
icon={<IconArrowLeft />}
type="tertiary"
status="muted"
noPadding
size="small"
>
<span className="pr-1">All products</span>
</LemonButton>
</div>
<h1 className="text-5xl font-bold">{product.name}</h1>
<h2 className="font-bold mb-6">{product.description}</h2>
<div className="flex gap-x-2">
Expand Down
Loading

0 comments on commit ff797d2

Please sign in to comment.