diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png index 78ea79ea3f745..74e8409c16b8b 100644 Binary files a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png and b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png differ diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 5796e0e2e56df..4d12031b59db4 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -870,6 +870,9 @@ class ApiRequest { public insightVariables(teamId?: TeamType['id']): ApiRequest { return this.projectsDetail(teamId).addPathComponent('insight_variables') } + public insightVariable(variableId: string, teamId?: TeamType['id']): ApiRequest { + return this.insightVariables(teamId).addPathComponent(variableId) + } // ActivityLog public activity_log(teamId?: TeamType['id']): ApiRequest { @@ -2304,9 +2307,12 @@ const api = { async list(options?: ApiMethodOptions | undefined): Promise> { return await new ApiRequest().insightVariables().get(options) }, - async create(data: Partial): Promise { + async create(data: Partial): Promise { return await new ApiRequest().insightVariables().create({ data }) }, + async update(variableId: string, data: Partial): Promise { + return await new ApiRequest().insightVariable(variableId).update({ data }) + }, }, subscriptions: { diff --git a/frontend/src/queries/nodes/DataVisualization/Components/Variables/AddVariableButton.tsx b/frontend/src/queries/nodes/DataVisualization/Components/Variables/AddVariableButton.tsx index 076f61e78b53f..a4bbed9d1d3e7 100644 --- a/frontend/src/queries/nodes/DataVisualization/Components/Variables/AddVariableButton.tsx +++ b/frontend/src/queries/nodes/DataVisualization/Components/Variables/AddVariableButton.tsx @@ -5,14 +5,14 @@ import { FEATURE_FLAGS } from 'lib/constants' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { dataVisualizationLogic } from '../../dataVisualizationLogic' -import { addVariableLogic } from './addVariableLogic' import { NewVariableModal } from './NewVariableModal' +import { variableModalLogic } from './variableModalLogic' import { variablesLogic } from './variablesLogic' export const AddVariableButton = (): JSX.Element => { const { showEditingUI } = useValues(dataVisualizationLogic) const { featureFlags } = useValues(featureFlagLogic) - const { openModal } = useActions(addVariableLogic) + const { openNewVariableModal } = useActions(variableModalLogic) const { variables, variablesLoading } = useValues(variablesLogic) const { addVariable } = useActions(variablesLogic) @@ -30,19 +30,19 @@ export const AddVariableButton = (): JSX.Element => { items: [ { label: 'String', - onClick: () => openModal('String'), + onClick: () => openNewVariableModal('String'), }, { label: 'Number', - onClick: () => openModal('Number'), + onClick: () => openNewVariableModal('Number'), }, { label: 'Boolean', - onClick: () => openModal('Boolean'), + onClick: () => openNewVariableModal('Boolean'), }, { label: 'List', - onClick: () => openModal('List'), + onClick: () => openNewVariableModal('List'), }, ], }, diff --git a/frontend/src/queries/nodes/DataVisualization/Components/Variables/NewVariableModal.tsx b/frontend/src/queries/nodes/DataVisualization/Components/Variables/NewVariableModal.tsx index b7386fd745d5a..95c0d66a1c3d9 100644 --- a/frontend/src/queries/nodes/DataVisualization/Components/Variables/NewVariableModal.tsx +++ b/frontend/src/queries/nodes/DataVisualization/Components/Variables/NewVariableModal.tsx @@ -10,7 +10,7 @@ import { useActions, useValues } from 'kea' import { LemonField } from 'lib/lemon-ui/LemonField' import { Variable } from '../../types' -import { addVariableLogic } from './addVariableLogic' +import { variableModalLogic } from './variableModalLogic' const renderVariableSpecificFields = ( variable: Variable, @@ -95,12 +95,14 @@ const renderVariableSpecificFields = ( } export const NewVariableModal = (): JSX.Element => { - const { closeModal, updateVariable, save } = useActions(addVariableLogic) - const { isModalOpen, variable } = useValues(addVariableLogic) + const { closeModal, updateVariable, save } = useActions(variableModalLogic) + const { isModalOpen, variable, modalType } = useValues(variableModalLogic) + + const title = modalType === 'new' ? `New ${variable.type} variable` : `Editing ${variable.name}` return ( { @@ -49,6 +50,7 @@ export const VariablesForInsight = (): JSX.Element => { const { updateVariableValue, removeVariable } = useActions(variablesLogic) const { showEditingUI } = useValues(dataVisualizationLogic) const { variableOverridesAreSet } = useValues(dataNodeLogic) + const { openExistingVariableModal } = useActions(variableModalLogic) if (!featureFlags[FEATURE_FLAGS.INSIGHT_VARIABLES] || !variablesForInsight.length || !showVariablesBar) { return <> @@ -65,6 +67,7 @@ export const VariablesForInsight = (): JSX.Element => { onChange={updateVariableValue} onRemove={removeVariable} variableOverridesAreSet={variableOverridesAreSet} + variableSettingsOnClick={() => openExistingVariableModal(n)} /> ))} @@ -79,6 +82,7 @@ interface VariableInputProps { closePopover: () => void onChange: (variableId: string, value: any) => void onRemove?: (variableId: string) => void + variableSettingsOnClick?: () => void } const VariableInput = ({ @@ -87,6 +91,7 @@ const VariableInput = ({ closePopover, onChange, onRemove, + variableSettingsOnClick, }: VariableInputProps): JSX.Element => { const [localInputValue, setLocalInputValue] = useState(() => { const val = variable.value ?? variable.default_value @@ -191,7 +196,7 @@ const VariableInput = ({ } } }} - className="text-xs flex flex-1 items-center" + className="text-xs flex flex-1 items-center mr-2" > {variableAsHogQL} @@ -209,7 +214,14 @@ const VariableInput = ({ tooltip="Remove variable from insight" /> )} - } size="xsmall" tooltip="Open variable settings" /> + {variableSettingsOnClick && ( + } + size="xsmall" + tooltip="Open variable settings" + /> + )} )} @@ -223,6 +235,7 @@ interface VariableComponentProps { onChange: (variableId: string, value: any) => void variableOverridesAreSet: boolean onRemove?: (variableId: string) => void + variableSettingsOnClick?: () => void } const VariableComponent = ({ @@ -231,6 +244,7 @@ const VariableComponent = ({ onChange, variableOverridesAreSet, onRemove, + variableSettingsOnClick, }: VariableComponentProps): JSX.Element => { const [isPopoverOpen, setPopoverOpen] = useState(false) @@ -244,6 +258,12 @@ const VariableComponent = ({ onChange={onChange} closePopover={() => setPopoverOpen(false)} onRemove={onRemove} + variableSettingsOnClick={() => { + if (variableSettingsOnClick) { + setPopoverOpen(false) + variableSettingsOnClick() + } + }} /> } visible={isPopoverOpen} diff --git a/frontend/src/queries/nodes/DataVisualization/Components/Variables/addVariableLogic.ts b/frontend/src/queries/nodes/DataVisualization/Components/Variables/variableModalLogic.ts similarity index 72% rename from frontend/src/queries/nodes/DataVisualization/Components/Variables/addVariableLogic.ts rename to frontend/src/queries/nodes/DataVisualization/Components/Variables/variableModalLogic.ts index a8802e6b6b6ea..641e991250537 100644 --- a/frontend/src/queries/nodes/DataVisualization/Components/Variables/addVariableLogic.ts +++ b/frontend/src/queries/nodes/DataVisualization/Components/Variables/variableModalLogic.ts @@ -3,8 +3,8 @@ import { actions, connect, kea, key, listeners, path, props, reducers } from 'ke import api, { ApiError } from 'lib/api' import { BooleanVariable, ListVariable, NumberVariable, StringVariable, Variable, VariableType } from '../../types' -import type { addVariableLogicType } from './addVariableLogicType' import { variableDataLogic } from './variableDataLogic' +import type { variableModalLogicType } from './variableModalLogicType' import { variablesLogic } from './variablesLogic' const DEFAULT_VARIABLE: StringVariable = { @@ -19,7 +19,7 @@ export interface AddVariableLogicProps { key: string } -export const addVariableLogic = kea([ +export const variableModalLogic = kea([ path(['queries', 'nodes', 'DataVisualization', 'Components', 'Variables', 'variableLogic']), props({ key: '' } as AddVariableLogicProps), key((props) => props.key), @@ -27,29 +27,40 @@ export const addVariableLogic = kea([ actions: [variableDataLogic, ['getVariables'], variablesLogic, ['addVariable']], }), actions({ - openModal: (variableType: VariableType) => ({ variableType }), + openNewVariableModal: (variableType: VariableType) => ({ variableType }), + openExistingVariableModal: (variable: Variable) => ({ variable }), closeModal: true, updateVariable: (variable: Variable) => ({ variable }), save: true, }), reducers({ + modalType: [ + 'new' as 'new' | 'existing', + { + openNewVariableModal: () => 'new', + openExistingVariableModal: () => 'existing', + }, + ], variableType: [ 'string' as VariableType, { - openModal: (_, { variableType }) => variableType, + openNewVariableModal: (_, { variableType }) => variableType, + openExistingVariableModal: (_, { variable }) => variable.type, }, ], isModalOpen: [ false as boolean, { - openModal: () => true, + openNewVariableModal: () => true, + openExistingVariableModal: () => true, closeModal: () => false, }, ], variable: [ DEFAULT_VARIABLE as Variable, { - openModal: (_, { variableType }) => { + openExistingVariableModal: (_, { variable }) => ({ ...variable }), + openNewVariableModal: (_, { variableType }) => { if (variableType === 'String') { return { id: '', @@ -101,10 +112,14 @@ export const addVariableLogic = kea([ listeners(({ values, actions }) => ({ save: async () => { try { - const variable = await api.insightVariables.create(values.variable) + if (values.modalType === 'new') { + const variable = await api.insightVariables.create(values.variable) + actions.addVariable({ variableId: variable.id, code_name: variable.code_name }) + } else { + await api.insightVariables.update(values.variable.id, values.variable) + } actions.getVariables() - actions.addVariable({ variableId: variable.id, code_name: variable.code_name }) actions.closeModal() } catch (e: any) { const error = e as ApiError diff --git a/frontend/src/queries/nodes/DataVisualization/DataVisualization.tsx b/frontend/src/queries/nodes/DataVisualization/DataVisualization.tsx index 830ed2aabbdb5..9a021d962b0f9 100644 --- a/frontend/src/queries/nodes/DataVisualization/DataVisualization.tsx +++ b/frontend/src/queries/nodes/DataVisualization/DataVisualization.tsx @@ -39,7 +39,7 @@ import { SideBar } from './Components/SideBar' import { Table } from './Components/Table' import { TableDisplay } from './Components/TableDisplay' import { AddVariableButton } from './Components/Variables/AddVariableButton' -import { addVariableLogic } from './Components/Variables/addVariableLogic' +import { variableModalLogic } from './Components/Variables/variableModalLogic' import { VariablesForInsight } from './Components/Variables/Variables' import { variablesLogic } from './Components/Variables/variablesLogic' import { dataVisualizationLogic, DataVisualizationLogicProps } from './dataVisualizationLogic' @@ -104,7 +104,7 @@ export function DataTableVisualization({ logic={variablesLogic} props={{ key: dataVisualizationLogicProps.key, readOnly: readOnly ?? false }} > - +