Skip to content

Commit

Permalink
Merge pull request #37 from torchbox/global-events
Browse files Browse the repository at this point in the history
Add global events that don't require a goal page
  • Loading branch information
KalobTaulien authored Jul 19, 2021
2 parents 092fc20 + 4da1633 commit 84a8a54
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ from wagtail_ab_testing.events import BaseEvent

class CustomEvent(BaseEvent):
name = "Name of the event type"
requires_page = True # Set to False to create a "Global" event type that could be reached on any page

def get_page_types(self):
return [
Expand Down
4 changes: 4 additions & 0 deletions wagtail_ab_testing/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ class BaseEvent:
"""
name = None

# When False, the user won't be asked to select a goal page
requires_page = True

# A list of page model classes that this event can be triggered on.
# This may be overridden by the .get_page_types() method
# Leave this as None to allow any page
page_types = None

def get_page_types(self):
Expand Down
4 changes: 3 additions & 1 deletion wagtail_ab_testing/static/wagtail_ab_testing/js/tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@
}

// Check non-page-specific goals
checkGoalReached(null);
// Note: we need to check for the string 'null' as nulls are converted to strings
// when they are used as keys in JSON
checkGoalReached('null');
};

// Trigger visit page event
Expand Down
29 changes: 25 additions & 4 deletions wagtail_ab_testing/static_src/components/GoalSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ const GoalPageSelector: FunctionComponent<GoalPageSelectorProps> = ({
});
};

const onClickClear = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
setSelectedPageId(null);
};

return (
<GoalPageSelectorDiv>
{selectedPageInfo && (
Expand All @@ -83,6 +88,14 @@ const GoalPageSelector: FunctionComponent<GoalPageSelectorProps> = ({
? gettext('Choose a different page')
: gettext('Choose a page')}
</button>
{selectedPageInfo && (
<button
className="button button-primary"
onClick={onClickClear}
>
{gettext('Clear')}
</button>
)}
<input
type="hidden"
name="goal_page"
Expand All @@ -109,10 +122,15 @@ interface GoalSelectorProps {
name: string;
}[];
};
globalGoalTypes: {
slug: string;
name: string;
}[];
}

const GoalSelector: FunctionComponent<GoalSelectorProps> = ({
goalTypesByPageType
goalTypesByPageType,
globalGoalTypes
}) => {
const [selectedPageType, setSelectedPageType] = React.useState<
string | null
Expand All @@ -128,7 +146,7 @@ const GoalSelector: FunctionComponent<GoalSelectorProps> = ({

const goalTypes = selectedPageType
? goalTypesByPageType[selectedPageType.toLowerCase()] || []
: [];
: globalGoalTypes;

return (
<div>
Expand All @@ -138,9 +156,12 @@ const GoalSelector: FunctionComponent<GoalSelectorProps> = ({
</SunkenLabel>
<GoalPageSelector onChangeSelectedPage={onChangeSelectedPage} />
</Field>
<Field visible={!!selectedPageType}>
<Field visible={!!goalTypes}>
<SunkenLabel>{gettext('What is the goal?')}</SunkenLabel>
<select name="goal_event" disabled={goalTypes.length === 0}>
<select name="goal_event">
<option key="" value="">
Choose a goal
</option>
{goalTypes.map(({ slug, name }) => (
<option key={slug} value={slug}>
{name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<h2>{{ ab_test.name }}</h2>
<p><b>{% trans "Page:" %}</b> {{ page.title }}</p>
{% if ab_test.hypothesis %}<p><b>{% trans "Hypothesis:" %}</b> {{ ab_test.hypothesis }}</p>{% endif %}
<p><b>{% trans "Goal:" %}</b> {{ ab_test.get_goal_event_display }}: {{ ab_test.goal_page }}</p>
<p><b>{% trans "Goal:" %}</b> {{ ab_test.get_goal_event_display }}{% if ab_test.goal_page_id %}: {{ ab_test.goal_page }}{% endif %}</p>
{% if ab_test.created_by %}<p><b>{% trans "Test by:" %}</b> {{ ab_test.created_by }}</p>{% endif %}

<div class="abtest-progressbar">
Expand Down
5 changes: 4 additions & 1 deletion wagtail_ab_testing/test/tests/test_add_abtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ def test_get_add_form(self):
"goalTypesByPageType": {
"wagtailcore.page": [{"slug": "visit-page", "name": "Visit page"}],
"wagtail_ab_testing_test.simplepage": [{"slug": "visit-page", "name": "Visit page"}]
}
},
"globalGoalTypes": [
{'name': 'Global Event', 'slug': 'global-event'}
]
})

def test_post_add_form(self):
Expand Down
15 changes: 15 additions & 0 deletions wagtail_ab_testing/test/wagtail_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

from wagtail.core import hooks
from wagtail_ab_testing.events import BaseEvent


class GlobalEvent(BaseEvent):
name = "Global Event"
requires_page = False


@hooks.register('register_ab_testing_event_types')
def register_submit_form_event_type():
return {
'global-event': GlobalEvent(),
}
15 changes: 12 additions & 3 deletions wagtail_ab_testing/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def add_form(request, page_id):
else:
form = CreateAbTestForm()

event_types = get_event_types().items()
return render(request, 'wagtail_ab_testing/add_form.html', {
'page': page,
'form': form,
Expand All @@ -135,11 +136,19 @@ def add_form(request, page_id):
'slug': slug,
'name': event_type.name,
}
for slug, event_type in get_event_types().items()
if event_type.can_be_triggered_on_page_type(page_type)
for slug, event_type in event_types
if event_type.requires_page and event_type.can_be_triggered_on_page_type(page_type)
]
for page_type in PAGE_MODEL_CLASSES
}
},
'globalGoalTypes': [
{
'slug': slug,
'name': event_type.name,
}
for slug, event_type in event_types
if not event_type.requires_page
]
}, cls=DjangoJSONEncoder)
})

Expand Down

0 comments on commit 84a8a54

Please sign in to comment.