Skip to content

Commit

Permalink
Merge branch 'master' into finalize-map
Browse files Browse the repository at this point in the history
  • Loading branch information
thmsobrmlr committed Oct 27, 2023
2 parents 5feca44 + 44e49cf commit 389d932
Show file tree
Hide file tree
Showing 25 changed files with 788 additions and 194 deletions.
27 changes: 16 additions & 11 deletions .github/workflows/build-hogql-parser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,44 @@ jobs:
if: github.repository == 'PostHog/posthog'
runs-on: ubuntu-22.04
outputs:
parser_any_changed: ${{ steps.changed-files-yaml.outputs.parser_any_changed }}
parser-release-needed: ${{ steps.version.outputs.parser-release-needed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetching all for comparison since last push (not just last commit)

- name: Check if hogql_parser/ has changed
id: changed-files-yaml
id: changed-files
uses: tj-actions/changed-files@v39
with:
since_last_remote_commit: true
files_yaml: |
parser:
- hogql_parser/**
- name: Notify about release needed
if: steps.changed-files-yaml.outputs.parser_any_changed == 'true'
- name: Check if version was bumped
shell: bash
id: version
run: |
published=$(curl -fSsl https://pypi.org/pypi/hogql-parser/json | jq -r '.info.version')
local=$(python hogql_parser/setup.py --version)
# TODO: Only comment if no comment alraedy exists for $local
if [[ "$published" == "$local" ]]; then
message_body="It looks like the code of \`hogql-parser\` has changed since last push, but its version stayed the same at $local. 👀\nMake sure to resolve this in \`hogql_parser/setup.py\` before merging!"
curl -s -u posthog-bot:${{ secrets.POSTHOG_BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} -X POST -d "{ \"body\": \"$message_body\" }" "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
parser_release_needed='false'
if [[ ${{ steps.changed-files.outputs.parser_any_changed }} == 'true' ]]; then
published=$(curl -fSsl https://pypi.org/pypi/hogql-parser/json | jq -r '.info.version')
local=$(python hogql_parser/setup.py --version)
if [[ "$published" != "$local" ]]; then
parser_release_needed='true'
else
message_body="It looks like the code of \`hogql-parser\` has changed since last push, but its version stayed the same at $local. 👀\nMake sure to resolve this in \`hogql_parser/setup.py\` before merging!"
curl -s -u posthog-bot:${{ secrets.POSTHOG_BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} -X POST -d "{ \"body\": \"$message_body\" }" "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
fi
fi
echo "::set-output name=parser-release-needed::$parser_release_needed"
build-wheels:
name: Build wheels on ${{ matrix.os }}
needs: check-version
runs-on: ${{ matrix.os }}
timeout-minutes: 30
if: ${{ needs.check-version.outputs.parser_any_changed == 'true' }}
if: ${{ needs.check-version.outputs.parser-release-needed == 'true' }}
strategy:
matrix:
# As of October 2023, GitHub doesn't have ARM Actions runners… and ARM emulation is insanely slow
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 28 additions & 1 deletion frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
{
"$ref": "#/definitions/PersonsQuery"
},
{
"$ref": "#/definitions/InsightPersonsQuery"
},
{
"$ref": "#/definitions/SessionsTimelineQuery"
},
Expand Down Expand Up @@ -1620,6 +1623,29 @@
],
"type": "string"
},
"InsightPersonsQuery": {
"additionalProperties": false,
"properties": {
"day": {
"type": "string"
},
"kind": {
"const": "InsightPersonsQuery",
"type": "string"
},
"response": {
"$ref": "#/definitions/PersonsQueryResponse"
},
"source": {
"$ref": "#/definitions/InsightQueryNode"
},
"status": {
"type": "string"
}
},
"required": ["kind", "source"],
"type": "object"
},
"InsightQueryNode": {
"anyOf": [
{
Expand Down Expand Up @@ -1894,6 +1920,7 @@
"PathsQuery",
"StickinessQuery",
"LifecycleQuery",
"InsightPersonsQuery",
"WebOverviewQuery",
"WebTopClicksQuery",
"WebStatsTableQuery",
Expand Down Expand Up @@ -2146,7 +2173,7 @@
"source": {
"anyOf": [
{
"$ref": "#/definitions/LifecycleQuery"
"$ref": "#/definitions/InsightPersonsQuery"
},
{
"$ref": "#/definitions/HogQLQuery"
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export enum NodeKind {
PathsQuery = 'PathsQuery',
StickinessQuery = 'StickinessQuery',
LifecycleQuery = 'LifecycleQuery',
InsightPersonsQuery = 'InsightPersonsQuery',

// Web analytics queries
WebOverviewQuery = 'WebOverviewQuery',
Expand All @@ -82,6 +83,7 @@ export type AnyDataNode =
| TimeToSeeDataSessionsQuery // old API
| EventsQuery
| PersonsQuery
| InsightPersonsQuery
| SessionsTimelineQuery
| HogQLQuery
| HogQLMetadata
Expand Down Expand Up @@ -535,7 +537,7 @@ export interface PersonsQueryResponse {

export interface PersonsQuery extends DataNode {
kind: NodeKind.PersonsQuery
source?: LifecycleQuery | HogQLQuery
source?: InsightPersonsQuery | HogQLQuery
select?: HogQLExpression[]
search?: string
properties?: AnyPropertyFilter[]
Expand Down Expand Up @@ -653,6 +655,16 @@ export type InsightFilter =
| StickinessFilter
| LifecycleFilter

export interface InsightPersonsQuery {
kind: NodeKind.InsightPersonsQuery
source: InsightQueryNode
day?: string
status?: string
// TODO: add breakdowns
// TODO: add fields for other insights (funnels dropdown, compare_previous choice, etc)
response?: PersonsQueryResponse
}

export const dateRangeForFilter = (source: FilterType | undefined): DateRange | undefined => {
if (!source) {
return undefined
Expand Down
52 changes: 14 additions & 38 deletions frontend/src/scenes/insights/filters/ActionFilter/RenameModal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { useActions, useValues } from 'kea'
import { entityFilterLogic } from 'scenes/insights/filters/ActionFilter/entityFilterLogic'
import { useEffect, useRef } from 'react'
import { InsightType } from '~/types'
import { Button, Input, Modal } from 'antd'
import { getDisplayNameFromEntityFilter } from 'scenes/insights/utils'
import { renameModalLogic } from 'scenes/insights/filters/ActionFilter/renameModalLogic'
import { InputFocusOptions } from 'antd/lib/input/Input'
import { LemonButton, LemonInput, LemonModal } from '@posthog/lemon-ui'

interface RenameModalProps {
typeKey: string
Expand All @@ -20,64 +18,42 @@ export function RenameModal({ typeKey, view }: RenameModalProps): JSX.Element {
const { name } = useValues(logic)
const { setName } = useActions(logic)

const ref = useRef<Input | null>(null)
useSelectAllText(ref, { cursor: 'all' }, [modalVisible])

const title = `Rename ${view === InsightType.FUNNELS ? 'funnel step' : 'graph series'}`

return (
<Modal
<LemonModal
data-attr="filter-rename-modal"
visible={modalVisible}
isOpen={modalVisible}
title={title}
width={520}
footer={
<>
<Button type="link" onClick={hideModal}>
<LemonButton type="secondary" onClick={hideModal}>
Cancel
</Button>
<Button type="primary" onClick={() => renameFilter(name)}>
</LemonButton>
<LemonButton type="primary" onClick={() => renameFilter(name)}>
{title}
</Button>
</LemonButton>
</>
}
onCancel={hideModal}
onClose={hideModal}
>
Query series/steps can be renamed to provide a more{' '}
<strong>meaningful label for you and your team members</strong>. Custom names are also shown on dashboards.
<br />
<div className="l4 mt-2 mb-2">Name</div>
<Input
ref={ref}
<LemonInput
value={name}
onPressEnter={() => renameFilter(name)}
onChange={(e) => setName(e.target.value)}
onChange={(value) => setName(value)}
suffix={
<span className="text-muted-alt">
{getDisplayNameFromEntityFilter(selectedFilter, false) ?? ''}
</span>
}
autoFocus
onFocus={(e) => e.target.select()}
/>
</Modal>
)
}

function useSelectAllText(
ref: React.MutableRefObject<Input | null>,
options: InputFocusOptions,
dependencies: any[] = []
): void {
// Hacky setTimeout is needed to select all text on modal open
// https://github.com/ant-design/ant-design/issues/8668#issuecomment-352955313
useEffect(
() => {
const autoFocusTimeout = setTimeout(() => {
if (ref.current) {
ref.current?.focus(options)
}
}, 0)
return () => clearTimeout(autoFocusTimeout)
},

dependencies
</LemonModal>
)
}
6 changes: 6 additions & 0 deletions frontend/src/scenes/saved-insights/SavedInsights.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ export const QUERY_TYPES_METADATA: Record<NodeKind, InsightTypeMetadata> = {
icon: IconPerson,
inMenu: false,
},
[NodeKind.InsightPersonsQuery]: {
name: 'Persons',
description: 'List of persons matching specified conditions, derived from an insight',
icon: IconPerson,
inMenu: false,
},
[NodeKind.DataTableNode]: {
name: 'Data table',
description: 'Slice and dice your data in a table',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/scenes/teamLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ export const teamLogic = kea<teamLogicType>([
],
})),
listeners(({ actions }) => ({
createTeamSuccess: () => {
organizationLogic.actions.loadCurrentOrganization()
},
deleteTeam: async ({ team }) => {
try {
await api.delete(`api/projects/${team.id}`)
Expand Down
30 changes: 27 additions & 3 deletions frontend/src/scenes/trends/viz/ActionsLineGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ import { urlsForDatasets } from '../persons-modal/persons-modal-utils'
import { DateDisplay } from 'lib/components/DateDisplay'
import { PropertyKeyInfo } from 'lib/components/PropertyKeyInfo'
import { trendsDataLogic } from '../trendsDataLogic'
import { insightDataLogic } from 'scenes/insights/insightDataLogic'
import { isInsightVizNode, isLifecycleQuery } from '~/queries/utils'
import { DataTableNode, NodeKind } from '~/queries/schema'
import { combineUrl, router } from 'kea-router'
import { urls } from 'scenes/urls'

export function ActionsLineGraph({
inSharedMode = false,
showPersonsModal = true,
context,
}: ChartParams): JSX.Element | null {
const { insightProps, hiddenLegendKeys } = useValues(insightLogic)
const { query } = useValues(insightDataLogic(insightProps))
const {
indexedResults,
labelGroupType,
Expand Down Expand Up @@ -76,13 +82,31 @@ export function ActionsLineGraph({
const day = dataset?.days?.[index] ?? ''
const label = dataset?.label ?? dataset?.labels?.[index] ?? ''

if (isLifecycle && query && isInsightVizNode(query) && isLifecycleQuery(query.source)) {
const newQuery: DataTableNode = {
kind: NodeKind.DataTableNode,
full: true,
source: {
kind: NodeKind.PersonsQuery,
source: {
kind: NodeKind.InsightPersonsQuery,
source: query.source,
day,
status: dataset.status,
},
},
}
router.actions.push(combineUrl(urls.persons(), undefined, { q: newQuery }).url)
return
}

if (!dataset) {
return
}

const urls = urlsForDatasets(crossDataset, index)
const datasetUrls = urlsForDatasets(crossDataset, index)

if (urls?.length) {
if (datasetUrls?.length) {
const title = isStickiness ? (
<>
<PropertyKeyInfo value={label || ''} disablePopover /> stickiness on day {day}
Expand All @@ -97,7 +121,7 @@ export function ActionsLineGraph({
)

openPersonsModal({
urls,
urls: datasetUrls,
urlsIndex: crossDataset?.findIndex((x) => x.id === dataset.id) || 0,
title,
})
Expand Down
8 changes: 5 additions & 3 deletions hogql_parser/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
err_indicator = PyObject_SetAttrString(py_err, "end", py_end); \
if (err_indicator == -1) goto exit##TYPE; \
PyErr_SetObject(error_type, py_err); \
exit##TYPE:; \
exit##TYPE :; \
Py_XDECREF(py_end); \
Py_XDECREF(py_start); \
Py_XDECREF(py_err); \
Expand Down Expand Up @@ -2096,7 +2096,8 @@ static PyMethodDef parser_methods[] = {
.ml_meth = method_unquote_string,
.ml_flags = METH_VARARGS,
.ml_doc = "Unquote the string (an identifier or a string literal))"},
{NULL, NULL, 0, NULL}};
{NULL, NULL, 0, NULL}
};

static int parser_modexec(PyObject* module) {
parser_state* state = get_module_state(module);
Expand All @@ -2118,7 +2119,8 @@ static int parser_modexec(PyObject* module) {
static PyModuleDef_Slot parser_slots[] = {
{Py_mod_exec, (void*)parser_modexec}, // If Python were written in C++, then Py_mod_exec would be typed better, but
// because it's in C, it expects a void pointer
{0, NULL}};
{0, NULL}
};

static int parser_traverse(PyObject* module, visitproc visit, void* arg) {
parser_state* state = get_module_state(module);
Expand Down
2 changes: 1 addition & 1 deletion hogql_parser/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ string unquote_string(string text) {
boost::replace_all(text, "\\r", "\r");
boost::replace_all(text, "\\t", "\t");
boost::replace_all(text, "\\v", "\v");
boost::replace_all(text, "\\0", ""); // NUL characters are ignored
boost::replace_all(text, "\\0", ""); // NUL characters are ignored
boost::replace_all(text, "\\\\", "\\");

return text;
Expand Down
Loading

0 comments on commit 389d932

Please sign in to comment.