-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(surveys): allow to stop surveys once reached enough responses #21528
Merged
Merged
Changes from 12 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
0bc6e84
feat(surveys): allow to stop surveys once reached enough responses
nikitaevg eb7367c
fix targeting
nikitaevg 6d46d59
polish
nikitaevg 1ec1b50
fix type errors
nikitaevg 4bd29e7
make the periodic job better, add tests for it
nikitaevg 709ce86
Merge remote-tracking branch 'upstream/master' into 21179-stop-survey
nikitaevg ef47dd9
resolve the conflict, revert some files
nikitaevg a2fcfc9
revert files
nikitaevg afd068c
fix types problems, add info about response limit
nikitaevg 6d25e56
fix tests
nikitaevg ca7a81c
make the responses limit bold
nikitaevg dc4eec9
Merge branch 'master' into 21179-stop-survey
neilkakkar 70b9fef
Update frontend/src/scenes/surveys/SurveyEdit.tsx
nikitaevg e6abdee
address the PR comments
nikitaevg d707e02
fix typing error
nikitaevg 34902b1
add a frontend test and snapshots
nikitaevg 6f4ac1a
Merge remote-tracking branch 'upstream/master' into 21179-stop-survey
nikitaevg e3ed0ee
add a forgotten migration
nikitaevg a6a7435
revert formatted files
nikitaevg 23043e6
add a forgotten file
nikitaevg 68b6a71
Merge remote-tracking branch 'upstream/master' into 21179-stop-survey
nikitaevg ff42287
why I always forget to save this file
nikitaevg 6c1cacd
replace typing.List and typing.Dict
nikitaevg 9aedb05
fix types, add snapshot, clean test
neilkakkar 78f5e02
stabilise uuids
neilkakkar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import './EditSurvey.scss' | |
|
||
import { DndContext } from '@dnd-kit/core' | ||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable' | ||
import { IconInfo } from '@posthog/icons' | ||
import { IconLock, IconPlus, IconTrash } from '@posthog/icons' | ||
import { | ||
LemonButton, | ||
|
@@ -19,6 +20,7 @@ import { FlagSelector } from 'lib/components/FlagSelector' | |
import { FEATURE_FLAGS } from 'lib/constants' | ||
import { IconCancel } from 'lib/lemon-ui/icons' | ||
import { LemonField } from 'lib/lemon-ui/LemonField' | ||
import { Tooltip } from 'lib/lemon-ui/Tooltip' | ||
import { featureFlagLogic as enabledFeaturesLogic } from 'lib/logic/featureFlagLogic' | ||
import { featureFlagLogic } from 'scenes/feature-flags/featureFlagLogic' | ||
import { FeatureFlagReleaseConditions } from 'scenes/feature-flags/FeatureFlagReleaseConditions' | ||
|
@@ -516,13 +518,18 @@ export default function SurveyEdit(): JSX.Element { | |
type="number" | ||
size="small" | ||
min={0} | ||
value={value?.seenSurveyWaitPeriodInDays} | ||
value={value?.seenSurveyWaitPeriodInDays || NaN} | ||
onChange={(val) => { | ||
if (val !== undefined && val > 0) { | ||
onChange({ | ||
...value, | ||
seenSurveyWaitPeriodInDays: val, | ||
}) | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This allows one to actually clean the input field |
||
onChange({ | ||
...value, | ||
seenSurveyWaitPeriodInDays: null, | ||
}) | ||
} | ||
}} | ||
className="w-16" | ||
|
@@ -597,6 +604,46 @@ export default function SurveyEdit(): JSX.Element { | |
</LemonField.Pure> | ||
), | ||
}, | ||
{ | ||
key: SurveyEditSection.CompletionConditions, | ||
header: 'Completion conditions', | ||
content: ( | ||
<LemonField name="responses_limit"> | ||
{({ onChange, value }) => { | ||
return ( | ||
<div className="flex flex-row gap-2 items-center"> | ||
<LemonCheckbox | ||
checked={!!value} | ||
onChange={(checked) => { | ||
const newResponsesLimit = checked ? 100 : null | ||
onChange(newResponsesLimit) | ||
}} | ||
/> | ||
Stop the survey once | ||
<LemonInput | ||
type="number" | ||
size="small" | ||
min={1} | ||
value={value || NaN} | ||
onChange={(newValue) => { | ||
if (newValue && newValue > 0) { | ||
onChange(newValue) | ||
} else { | ||
onChange(null) | ||
} | ||
}} | ||
className="w-16" | ||
/>{' '} | ||
responses are received. | ||
<Tooltip title="The survey might receive slightly more responses than the limit specifies."> | ||
nikitaevg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<IconInfo /> | ||
</Tooltip> | ||
</div> | ||
) | ||
}} | ||
</LemonField> | ||
), | ||
}, | ||
]} | ||
/> | ||
</div> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Generated by Django 4.1.13 on 2024-04-14 13:56 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("posthog", "0403_plugin_has_private_access"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="survey", | ||
name="responses_limit", | ||
field=models.PositiveIntegerField(null=True), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
from typing import List, Dict | ||
nikitaevg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
from itertools import groupby | ||
from django.db.models import UUIDField, DateTimeField | ||
from django.utils import timezone | ||
|
||
from posthog.clickhouse.client.connection import Workload | ||
from posthog.client import sync_execute | ||
from posthog.models import Survey | ||
|
||
|
||
def _get_surveys_response_counts( | ||
surveys_ids: List[UUIDField], team_id: UUIDField, earliest_survey_start_date: DateTimeField | ||
) -> Dict[str, int]: | ||
data = sync_execute( | ||
""" | ||
SELECT JSONExtractString(properties, '$survey_id') as survey_id, count() | ||
nikitaevg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
FROM events | ||
WHERE event = 'survey sent' | ||
AND team_id = %(team_id)s | ||
AND timestamp >= %(earliest_survey_start_date)s | ||
AND survey_id in %(surveys_ids)s | ||
GROUP BY survey_id | ||
""", | ||
{"surveys_ids": surveys_ids, "team_id": team_id, "earliest_survey_start_date": earliest_survey_start_date}, | ||
workload=Workload.OFFLINE, | ||
) | ||
|
||
counts = {} | ||
for survey_id, count in data: | ||
counts[survey_id] = count | ||
return counts | ||
|
||
|
||
def _stop_survey_if_reached_limit(survey: Survey, responses_count: int) -> None: | ||
assert survey.responses_limit is not None | ||
if responses_count < survey.responses_limit: | ||
return | ||
|
||
survey.end_date = timezone.now() | ||
survey.responses_limit = None | ||
survey.save(update_fields=["end_date", "responses_limit"]) | ||
|
||
|
||
def stop_surveys_reached_target() -> None: | ||
all_surveys = Survey.objects.exclude(responses_limit__isnull=True).only( | ||
"id", "responses_limit", "team_id", "created_at" | ||
) | ||
|
||
all_surveys_sorted = sorted(all_surveys, key=lambda survey: survey.team_id) | ||
for team_id, team_surveys in groupby(all_surveys_sorted, lambda survey: survey.team_id): | ||
team_surveys_list = list(team_surveys) | ||
surveys_ids = [survey.id for survey in team_surveys_list] | ||
earliest_survey_start_date = min([survey.created_at for survey in team_surveys_list]) | ||
|
||
response_counts = _get_surveys_response_counts(surveys_ids, team_id, earliest_survey_start_date) | ||
for survey in team_surveys_list: | ||
survey_id = str(survey.id) | ||
if survey_id not in response_counts: | ||
continue | ||
|
||
_stop_survey_if_reached_limit(survey, response_counts[survey_id]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cleans the input field when the value is null