Skip to content
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

Overhaul the admin and support for required condition #35

Merged
merged 7 commits into from
Jun 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
[![Build Status](https://travis-ci.org/cfpb/wagtail-flags.svg?branch=master)](https://travis-ci.org/cfpb/wagtail-flags)
[![Coverage Status](https://coveralls.io/repos/github/cfpb/wagtail-flags/badge.svg?branch=master)](https://coveralls.io/github/cfpb/wagtail-flags?branch=master)

Feature flags allow you to toggle functionality in the Wagtail based on configurable conditions.
Feature flags allow you to toggle functionality based on configurable conditions.

Wagtail-Flags adds a Wagtail admin UI and Wagtail Site-based condition on top of [Django-Flags](https:/cfpb/django-flags). For a more complete overview of feature flags and how to use them, please see the [Django-Flags documentation](https://cfpb.github.io/django-flags).

![Feature flags in the Wagtail admin](https://raw.githubusercontent.com/cfpb/wagtail-flags/master/screenshot_list.png)
![Feature flags in the Wagtail admin](wagtailflags.gif)

- [Dependencies](#dependencies)
- [Installation](#installation)
Expand All @@ -27,9 +27,10 @@ Wagtail-Flags adds a Wagtail admin UI and Wagtail Site-based condition on top of

## Installation

1. Install wagtail-flags:
1. Install Django-Flags and Wagtail-Flags:

```shell
pip install django-flags
pip install wagtail-flags
```

Expand All @@ -52,7 +53,7 @@ First, define the flag in Django `settings.py`:

```python
FLAGS = {
'MY_FLAG': {}
'MY_FLAG': []
}
```

Expand Down Expand Up @@ -80,9 +81,9 @@ urlpatterns = [
]
```

Finally, add conditions for the flag in the Wagtail admin under "Settings", "Flags":
Finally, add conditions for the flag in the Wagtail admin under "Settings", "Flags", "MY_FLAG":

![Creating conditions in the Wagtail admin](https://raw.githubusercontent.com/cfpb/wagtail-flags/master/screenshot_create.png)
![Creating conditions in the Wagtail admin](screenshot_create.png)

## Extended conditions

Expand All @@ -93,7 +94,11 @@ Wagtail-Flags adds the following conditions to Django-Flags:
Allows a flag to be enabled for a Wagtail site that matches the hostname and port in the condition value.

```python
FLAGS = {'MY_FLAG': {'site': 'staging.mysite.com'}}
FLAGS = {
'MY_FLAG': [
{'condition': 'site', 'value': 'staging.mysite.com'}
],
}
```

## Getting help
Expand Down
Binary file modified screenshot_create.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed screenshot_list.png
Binary file not shown.
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
long_description = open('README.md', 'r').read()

install_requires = [
'wagtail>=1.10,<2.5',
'django-flags>=4.0,<5.0'
'wagtail>=1.13,<2.5',
'django-flags>=4.2,<5.0'
]

testing_extras = [
Expand All @@ -31,7 +31,6 @@
classifiers=[
'Framework :: Django',
'Framework :: Django :: 1.11',
'Framework :: Django :: 1.8',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'Framework :: Django :: 2.2',
Expand Down
Binary file added wagtailflags.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions wagtailflags/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from django import forms

from flags.conditions import get_conditions
from flags.models import FlagState
from flags.sources import get_flags


class NewFlagForm(forms.ModelForm):
name = forms.CharField(
label='Name',
required=True
)

def clean_name(self):
name = self.cleaned_data['name']
if name in get_flags():
raise forms.ValidationError(
"Flag named {} already exists".format(name)
)
return name

def save(self, commit=True):
obj = super(NewFlagForm, self).save(commit=False)
obj.condition = 'boolean'
obj.value = 'False'
obj.required = False
obj.save()
return obj

class Meta:
model = FlagState
fields = ('name', )


class FlagStateForm(forms.ModelForm):
name = forms.CharField(
label='Flag',
required=True,
disabled=True,
)
condition = forms.ChoiceField(
label='Condition name',
required=True
)
value = forms.CharField(
label='Expected value',
required=True
)
required = forms.BooleanField(
label='Required',
required=False,
help_text=('All conditions marked "required" must be met to enable '
'the flag'),
)

def __init__(self, *args, **kwargs):
super(FlagStateForm, self).__init__(*args, **kwargs)

self.fields['condition'].choices = [
(c, c) for c in sorted(get_conditions()) if c != 'boolean'
]

class Meta:
model = FlagState
fields = ('name', 'condition', 'value', 'required')
6 changes: 6 additions & 0 deletions wagtailflags/static/wagtailflags/css/wagtailflags.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.flags-breadcrumb {
margin-left: 0;
}
section.flag {
margin-top: 4em;
}
8 changes: 8 additions & 0 deletions wagtailflags/templates/wagtailflags/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% extends "wagtailadmin/base.html" %}

<ul class="breadcrumb">
<li class="home"><a href="#" class="icon icon-home text-replace">Home</a></li>
<li><a href="#">Various</a></li>
<li><a href="#">Subpages</a></li>
<li><a href="#">There is a max length of this many</a></li>
</ul>
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% block titletag %}{% trans "Create a flag condition" as flags_str %}{% endblock %}
{% block titletag %}Create a flag{% endblock %}

{% block content %}
{% trans "Create a flag condition" as flags_str %}
{% include "wagtailadmin/shared/header.html" with title=flags_str icon="tag" %}
{% include "wagtailadmin/shared/header.html" with title=flag.name icon="tag" %}

<h2 class="nice-padding">New flag condition:</h2>
<form class="nice-padding" method="POST" action="{% url 'wagtailflags:create' %}">
<h2 class="nice-padding">
Create a flag
</h2>

<form class="nice-padding" method="POST" action="{% url 'wagtailflags:create_flag' %}">
{% csrf_token %}
<ul class="fields">
<li class="actions">
Expand All @@ -28,8 +30,8 @@ <h2 class="nice-padding">New flag condition:</h2>
{% endfor %}
</li>
<li class="actions">
<input class="button action-save button-longrunning" type="submit" value="Save new condition" />
<a class="button bicolor icon icon-cog" href="{% url 'wagtailflags:list' %}">Back to flag conditions…</a>
<input class="button action-save button-longrunning" type="submit" value="Save flag" />
<a class="button bicolor icon icon-cog" href="{% url 'wagtailflags:list' %}">Back to flags</a>
</li>
</ul>
</form>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load i18n feature_flags %}
{% block titletag %}{% trans "Delete" as delete_str %}: {{ flag_id }}{% endblock %}

{% block content %}
{% trans "Delete flag condition:" as delete_str %}
{% include "wagtailadmin/shared/header.html" with title=delete_str subtitle=state_str %}
{% include "wagtailadmin/shared/header.html" with title=delete_str subtitle=condition_str %}
{% flag_enabled 'WAGTAILFLAGS_ADMIN_BIG_LIST' as big_list_flag %}

<form class="nice-padding" method="POST" action="{% url 'wagtailflags:delete' state_id %}">
<form class="nice-padding" method="POST" action="{% url 'wagtailflags:delete_condition' flag.name condition_pk %}">
{% csrf_token %}

<p>Are you sure you want to delete this flag condition?</p>
<input type="submit" value="Yes, delete it" class="button serious">
<a href="{% url 'wagtailflags:list' %}" class="button button-secondary">No, don't delete it</a>

{% if big_list_flag %}
<a href="{% url 'wagtailflags:list' %}#{{ flag.name }}" class="button button-secondary">No, don't delete it</a>
{% else %}
<a href="{% url 'wagtailflags:flag_index' flag.name %}" class="button button-secondary">No, don't delete it</a>
{% endif %}
</form>
{% endblock %}
49 changes: 49 additions & 0 deletions wagtailflags/templates/wagtailflags/flags/edit_condition.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n feature_flags %}
{% block titletag %}{% if form.instance %}Edit {{ form.instance.condition }}{% else %}Create condition{% endif %}{% endblock %}

{% block content %}
{% include "wagtailadmin/shared/header.html" with title=flag.name icon="tag" %}
{% flag_enabled 'WAGTAILFLAGS_ADMIN_BIG_LIST' as big_list_flag %}

<h2 class="nice-padding">
{% if form.instance %}Edit {{ form.instance.condition }}{% else %}Create condition{% endif %}
</h2>

{{ form.errors }}

{% if condition_pk %}
<form class="nice-padding" method="POST" action="{% url 'wagtailflags:edit_condition' flag.name condition_pk %}">
{% else %}
<form class="nice-padding" method="POST" action="{% url 'wagtailflags:create_condition' flag.name %}">
{% endif %}
{% csrf_token %}
<ul class="fields">
<li class="actions">
{% for field in form %}
{% if field.errors %}
<div class="help-block help-critical" style="margin-top:0;">
{{ field.errors }}
</div>
{% endif %}
<label>{{ field.label }}</label>
<div class="field-content">
<div class="input">
{{ field }}
<span></span>
</div>
<p class="help"></p>
</div>
{% endfor %}
</li>
<li class="actions">
<input class="button action-save button-longrunning" type="submit" value="Save condition" />
{% if big_list_flag %}
<a class="button bicolor icon icon-cog" href="{% url 'wagtailflags:list' %}#{{ flag.name }}">Back to {{ flag.name }}</a>
{% else %}
<a class="button bicolor icon icon-cog" href="{% url 'wagtailflags:flag_index' flag.name %}">Back to {{ flag.name }}</a>
{% endif %}
</li>
</ul>
</form>
{% endblock %}
13 changes: 13 additions & 0 deletions wagtailflags/templates/wagtailflags/flags/flag_index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% block titletag %}{% trans "Flags" %}: {{ flag.name }}{% endblock %}

{% block content %}
{% include "wagtailflags/includes/header.html" with title=flag.name icon="tag" %}

<div class="nice-padding">

{% include "wagtailflags/includes/flag_index.html" with flag=flag %}

</div>
{% endblock %}
63 changes: 63 additions & 0 deletions wagtailflags/templates/wagtailflags/includes/flag_index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% load i18n %}
{% load wagtailflags_admin %}
{% load i18n feature_flags flags_debug wagtailflags_admin %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this load wagtailflags_admin twice?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed so.


<section class="flag" id="{{ flag.name }}">
<div class="help-block help-info">
<p>{{ flag|state_str }}</p>
</div>

{% with flag|conditions_without_bool as conditions %}
{% if conditions|length > 0 %}
<table class="listing">
<thead>
<tr>
<th>Condition</th>
<th>Value</th>
<th></th>
</tr>
</thead>
<tbody>
{% for condition in conditions %}
<tr>
<td>
<b>{{ condition.condition }}</b>
</td>
<td>
{{ condition.value }}
</td>
<td>
{% if condition.required %}
Required
{% else %}
Optional
{% endif %}
</td>
<td>
{% if condition.obj %}
<div class="button-group">
<a href="{% url 'wagtailflags:edit_condition' flag.name condition.obj.pk %}" class="button button-small button-secondary">Edit</a>
<a href="{% url 'wagtailflags:delete_condition' flag.name condition.obj.pk %}" class="button button-small no">Delete</a>
</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endwith %}

{% if flag|enablable or flag|disablable %}
<a href="{% url 'wagtailflags:flag_index' flag.name %}?{% if flag|bool_enabled %}disable{% else %}enable{% endif %}"
class="button button-secondary{% if flag|bool_enabled %} no{% endif %}">
{% if flag|bool_enabled %}Disable{% else %}Enable{% endif %} {{ flag.name }}
{% if flag|required_conditions_without_bool|length > 0 %}
when required conditions are met
{% else %}
for all requests
{% endif %}
</a>
{% endif %}
<a href="{% url 'wagtailflags:create_condition' flag.name %}" class="button bicolor icon icon-plus">Add a condition</a>
</section>
9 changes: 9 additions & 0 deletions wagtailflags/templates/wagtailflags/includes/header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% if flag %}
<ul class="breadcrumb flags-breadcrumb">
<li><a href="{% url 'wagtailflags:list' %}">Flags</a></li>
<li>{{ title }}</li>
</ul>
{% include "wagtailadmin/shared/header.html" with title=title icon=icon %}
{% else %}
{% include "wagtailadmin/shared/header.html" with title=title icon=icon add_text='Add flag' add_link='wagtailflags:create_flag' %}
{% endif %}
Loading