Skip to content

Commit

Permalink
Merge branch 'master' into #448
Browse files Browse the repository at this point in the history
  • Loading branch information
EDsCODE committed May 4, 2020
2 parents ea35d79 + a390089 commit 24d7703
Show file tree
Hide file tree
Showing 19 changed files with 537 additions and 177 deletions.
45 changes: 45 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
# Changelog

### 1.3.0 - Wednesday 29 April 2020

- We have added an Android library so you can now capture events in your Android app and send them to PostHog, we can automatically capture screen changes, and send any other events that you like

![android events](https://posthog.com/wp-content/uploads/2020/04/android-events.gif)

- There is now, also a [PostHog Gatsby plugin](https://docs.posthog.com/#/integrations/gatsby)

- We have added URL wildcards so you can use % as a wildcard when setting up an action

![url wildcards](https://posthog.com/wp-content/uploads/2020/04/Posthog-19-e1588157571429.png)

- We have also updated the Trends page design as well as adding trends info hints. Trends is the default homepage when logging into PostHog.

![trend layout](https://posthog.com/wp-content/uploads/2020/04/Posthog-21-e1588171341976.png)

![trend hints](https://posthog.com/wp-content/uploads/2020/04/Fullscreen_4_29_20__12_09_PM-e1588158606164.png)

- The Events table can now be sorted by timestamp.

![timestamp reverse](https://posthog.com/wp-content/uploads/2020/04/timestampreverse.gif)

- Added a more strict flake8 setup and improvements
- Upgraded Kea to `2.0.0-beta.5`
- Implemented AntD into Setup page
- You can now allow access to your PostHog instance by IP address for more security. this does not apply to the JS snippet or the event capture API
- Added model for typing of filters
- Added copy code to clipboard changes
- Use forward for header in middleware if applicable
- Move get_ip_address to utils
- Fixed redirect to be explicit for /Trends
- Moved models to separate files
- Added link to docs for local deployment
- Warn instead of crash on invalid selector when using the front-end toolbar


#### Bug Fixes
- Fixed issue with default trends route
- Fixed Setup page operations not working
- Fixed crash when hovering over events
- Fixed issues with $create_alias when users have multiple distinct_ids attached to them
- Fixed trends save to dashboard issue
- Fixed adding dashboarditem with set dates


### 1.2.0 - Wednesday 22 Aptil 2020

- We have added an iOS library so you can now capture events in your iOS app and send them to PostHog, we can automatically capture screen changes, and send any other events that you like
Expand Down
5 changes: 3 additions & 2 deletions frontend/public/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
<html>
<head>
<title>Posthog</title>
<meta name="robots" content="noindex">
<link rel="icon" href="https://posthog.com/wp-content/uploads/2020/01/cropped-Frame-1-32x32.png" sizes="32x32"/>
<link rel="icon" href="https://posthog.com/wp-content/uploads/2020/01/cropped-Frame-1-192x192.png" sizes="192x192"/>
{% if not opt_out_capture %}
<link rel="icon" href="https://posthog.com/wp-content/uploads/2020/01/cropped-Frame-1-192x192.png" sizes="192x192"/>
{% if not opt_out_capture %}
<script src="https://t.posthog.com/static/array.js"></script>
<script id="posthog-snippet">
posthog.init('sTMFPsFhdP1Ssg');
Expand Down
68 changes: 41 additions & 27 deletions frontend/src/scenes/actions/ActionStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,16 @@ export class ActionStep extends Component {
<div className="btn-group">
<button
type="button"
onClick={() => this.sendStep({ ...step, event: '$autocapture' })}
onClick={() =>
this.setState(
{
selection: Object.keys(step).filter(
key => key != 'id' && key != 'isNew' && step[key]
),
},
() => this.sendStep({ ...step, event: '$autocapture' })
)
}
className={'btn ' + (step.event == '$autocapture' ? 'btn-secondary' : 'btn-light')}
>
Frontend element
Expand Down Expand Up @@ -202,7 +211,7 @@ export class ActionStep extends Component {
'//' +
window.location.host +
window.location.pathname
: null,
: step.url,
})
)
}}
Expand All @@ -229,33 +238,38 @@ export class ActionStep extends Component {
)
}
AutocaptureFields({ step, isEditor, actionId }) {
if (!isEditor)
return (
<span>
<AppEditorLink actionId={actionId} style={{ margin: '1rem 0' }} className="btn btn-sm btn-light">
Select element on site <i className="fi flaticon-export" />
</AppEditorLink>
<br />
<a href="/~https://github.com/PostHog/posthog/wiki/Actions" target="_blank">
See documentation
</a>{' '}
on how to set up actions.
</span>
)
return (
<div>
<this.Option
item="href"
label="Link href"
selector={this.state.element && 'a[href="' + this.state.element.getAttribute('href') + '"]'}
/>
<this.Option item="text" label="Text" />
<this.Option item="selector" label="Selector" selector={step.selector} />
<this.Option
item="url"
extra_options={<this.URLMatching step={step} isEditor={isEditor} />}
label="URL"
/>
{!isEditor && (
<span>
<AppEditorLink
actionId={actionId}
style={{ margin: '1rem 0' }}
className="btn btn-sm btn-light"
>
Select element on site <i className="fi flaticon-export" />
</AppEditorLink>
<a href="https://docs.posthog.com/#/features/actions" target="_blank" style={{ marginLeft: 8 }}>
See documentation.
</a>{' '}
</span>
)}
{(isEditor || step.selector || step.href || step.text) && (
<span>
<this.Option
item="href"
label="Link href"
selector={this.state.element && 'a[href="' + this.state.element.getAttribute('href') + '"]'}
/>
<this.Option item="text" label="Text" />
<this.Option item="selector" label="Selector" selector={step.selector} />
<this.Option
item="url"
extra_options={<this.URLMatching step={step} isEditor={isEditor} />}
label="URL"
/>
</span>
)}
</div>
)
}
Expand Down
50 changes: 30 additions & 20 deletions frontend/src/scenes/events/EventsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,26 +155,36 @@ export class EventsTable extends Component {
{event.person}
</Link>
</td>
{params.map(param => (
<td key={param} title={event.properties[param]}>
<FilterLink
property={param}
value={event.properties[param]}
filters={properties}
onClick={(key, value) =>
this.setState(
{
properties: {
...properties,
[key]: value,
{params.map(paramRequest => {
let param = paramRequest
let value = event.properties[param]

if (param === '$current_url' && !value) {
param = '$screen'
value = event.properties[param]
}

return (
<td key={param} title={value}>
<FilterLink
property={param}
value={event.properties[param]}
filters={properties}
onClick={(key, value) =>
this.setState(
{
properties: {
...properties,
[key]: value,
},
},
},
this.fetchEvents
)
}
/>
</td>
))}
this.fetchEvents
)
}
/>
</td>
)
})}
<td>{moment(event.timestamp).fromNow()}</td>
</tr>
)
Expand Down Expand Up @@ -209,7 +219,7 @@ export class EventsTable extends Component {
<tr>
<th>Event</th>
<th>Person</th>
<th>Path</th>
<th>Path / Screen</th>
<th>Source</th>
<th onClick={this.onTimestapHeaderClick}>
When <i className="fi flaticon-sort" />
Expand Down
44 changes: 20 additions & 24 deletions frontend/src/scenes/setup/OptOutCapture.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,42 @@ import React, { useState } from 'react'
import { useValues } from 'kea'
import api from '../../lib/api'
import { userLogic } from '../userLogic'
import { Switch } from 'antd'

export function OptOutCapture() {
const { user } = useValues(userLogic)
const [saved, setSaved] = useState(false)

return (
<div>
PostHog uses PostHog (unsurprisingly!) to capture information about
how people are using the product. We believe that product analytics
are the best way to make PostHog more useful for everyone.
PostHog uses PostHog (unsurprisingly!) to capture information about how people are using the product. We
believe that product analytics are the best way to make PostHog more useful for everyone.
<br />
<br />
We also understand there are many reasons why people don't want to
or aren't allowed to send this usage data. Just tick the box below
to opt out of this.
We also understand there are many reasons why people don't want to or aren't allowed to send this usage
data. Just tick the box below to opt out of this.
<br />
<br />
<label>
<input
type="checkbox"
onChange={e => {
api.update('api/user', {
team: { opt_out_capture: e.target.checked },
}).then(() => setSaved(true))
}}
defaultChecked={user.team.opt_out_capture}
/>
&nbsp;Tick this box to <strong>opt-out</strong> of sending usage
data to PostHog.
<Switch
onChange={checked => {
api.update('api/user', {
team: { opt_out_capture: checked },
}).then(() => setSaved(true))
}}
defaultChecked={user.team.opt_out_capture}
/>
<label
style={{
marginLeft: '10px',
}}
>
Opt-out of sending usage data to PostHog.
</label>
{saved && (
<p className="text-success">
Preference saved.{' '}
<a href="/setup">
Refresh the page for the change to take effect.
</a>
Preference saved. <a href="/setup">Refresh the page for the change to take effect.</a>
</p>
)}
<br />
<br />
</div>
)
}
26 changes: 14 additions & 12 deletions frontend/src/scenes/setup/UpdateEmailPreferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState } from 'react'
import { useValues, useActions } from 'kea'
import { userLogic } from '../userLogic'
import api from '../../lib/api'
import { Switch } from 'antd'

export function UpdateEmailPreferences() {
const { user } = useValues(userLogic)
Expand All @@ -10,18 +11,19 @@ export function UpdateEmailPreferences() {

return (
<div>
<label>
<input
type="checkbox"
onChange={e => {
// TODO: refactor so we arent re rendering multiple times
userUpdateRequest({ user: { email_opt_in: !user.email_opt_in } })
setSaved(true)
}}
defaultChecked={user.email_opt_in}
/>
&nbsp;Tick this box to receive security and feature updates via email. You can easily unsubscribe at any
time.
<Switch
onChange={checked => {
userUpdateRequest({ user: { email_opt_in: !user.email_opt_in } })
setSaved(true)
}}
defaultChecked={user.email_opt_in}
/>
<label
style={{
marginLeft: '10px',
}}
>
Receive security and feature updates via email. You can easily unsubscribe at any time.
</label>
{saved && <p className="text-success">Preference saved.</p>}
<br />
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/scenes/users/Cohorts.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export class Cohorts extends Component {
</Link>
</td>
<td>
<a href={'/api/person.csv?cohort=' + cohort.id}>
<i className="fi flaticon-export" />
</a>
<DeleteWithUndo
endpoint="cohort"
object={cohort}
Expand Down
9 changes: 3 additions & 6 deletions posthog/api/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from rest_framework.exceptions import AuthenticationFailed
from django.db.models import Q, Count, Prefetch, functions, QuerySet
from django.db import connection
from django.utils.timezone import now
from typing import Any, List, Dict, Optional, Tuple
import pandas as pd
import datetime
Expand Down Expand Up @@ -145,10 +146,6 @@ def _group_events_to_date(self, date_from: datetime.datetime, date_to: datetime.
'month': 'M'
}
response = {}
# handle "today" date range
if date_from == date_to:
date_from = pd.Timestamp(ts_input=date_from).replace(hour=0)
date_to = pd.Timestamp(ts_input=date_to).replace(hour=23)

time_index = pd.date_range(date_from, date_to, freq=freq_map[interval])
if len(aggregates) > 0:
Expand Down Expand Up @@ -240,7 +237,7 @@ def _aggregate_by_interval(self, filtered_events: QuerySet, entity: Entity, filt

dates_filled = self._group_events_to_date(
date_from=filter.date_from if filter.date_from else pd.Timestamp(aggregates[0][interval]),
date_to=filter.date_to,
date_to=filter.date_to if filter.date_to else now(),
aggregates=aggregates,
interval=interval,
breakdown=breakdown
Expand All @@ -259,7 +256,7 @@ def _execute_custom_sql(self, query, params):
return cursor.fetchall()

def _stickiness(self, filtered_events: QuerySet, filter: Filter) -> Dict[str, Any]:
range_days = (filter.date_to - filter.date_from).days + 2 if filter.date_from else 90
range_days = (filter.date_to - filter.date_from).days + 2 if filter.date_from and filter.date_to else 90

events = filtered_events\
.filter(self._filter_events(filter))\
Expand Down
Loading

0 comments on commit 24d7703

Please sign in to comment.