Skip to content

Commit

Permalink
Merge pull request #35 from sidorov-as/master
Browse files Browse the repository at this point in the history
Add SVG badges for feature flags
  • Loading branch information
BestDoctorAdmin authored Aug 30, 2022
2 parents 0d7a2e6 + f8eb04b commit 45a6526
Show file tree
Hide file tree
Showing 27 changed files with 668 additions and 45 deletions.
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ __pycache__/
.gitlab-ci.yml
.coverage.*
coverage.xml
docs/
.*cache/
.python-version
.rozental.sqlite
.coverage
.git/
Dockerfile
Dockerfile
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,5 @@ yum-root-*

.rozental.sqlite
.tm_properties

docker-compose.override.yml
1 change: 1 addition & 0 deletions .mdlrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
style '.mdlrc.rb'
3 changes: 3 additions & 0 deletions .mdlrc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
all
rule 'MD013', :line_length => 120
exclude_rule 'MD033'
64 changes: 59 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ Flag/feature toggle service, written in aiohttp.

### Basic

| Method | Endpoint | Description |
| ------- | ---------------------------| ----------------------------------- |
| `GET` | `/api/docs` | Api documentation |
| `GET` | `/api/v1/switch` | List of flags for the group. |
| Method | Endpoint | Description |
| ------- |----------------------------------|-----------------------------------------|
| `GET` | `/api/docs` | Api documentation |
| `GET` | `/api/v1/switch` | List of flags for the group. |
| `GET` | `/api/v1/switches/{id}/svg-badge` | SVG badge with actual flag information |
| `GET` | `/api/v1/switches_full_info` | List of all active flags with full info. |

### Admin

Expand All @@ -31,6 +33,58 @@ Flag/feature toggle service, written in aiohttp.
}
```

## SVG badges

SVG badges can be useful for showing actual feature flag states.

Open `Flag detail` page, find `SVG badge` section and copy badge.

<details>
<summary>Screenshot</summary>

![admin-flag-editing-page](docs/assets/img/admin-flag-editing-page.png)

</details>

You will get an image with a link in Markdown format:

```markdown
[![flag-name](link-to-svg-badge)](link-to-flag-editing-page)
```

Then paste text in a text editor with Markdown support (task tracker, Slack, Mattermost etc.).
Actual flag state will be displayed as follows:

| State | Badge |
|---------------|-------------------------------------------------------------------|
| Active flag | ![active-flag-badge](its_on/static/img/active-flag-badge.svg) |
| Inactive flag | ![inactive-flag-badge](its_on/static/img/inactive-flag-badge.svg) |
| Deleted flag | ![deleted-flag-badge](its_on/static/img/deleted-flag-badge.svg) |
| Unknown flag | ![unknown-flag-badge](its_on/static/img/unknown-flag-badge.svg) |

See [settings.yaml](settings.yaml) for additional settings.

## Environment notice

Environment notice helps to visually distinguish environments (e.g. development, staging, production).

<details>
<summary>Screenshot</summary>

![admin-environment-indicator](docs/assets/img/admin-environment-indicator.png)

</details>

To add the environment notice to every page in the admin, add following settings:

```env
export DYNACONF_ENVIRONMENT_NOTICE__show=true # false by default
export DYNACONF_ENVIRONMENT_NOTICE__environment_name='<Environment>'
export DYNACONF_ENVIRONMENT_NOTICE__background_color='<HEX color>'
```

See [settings.yaml](settings.yaml) for default settings for each specified environment.

## Installation

### Prerequisites
Expand Down Expand Up @@ -75,7 +129,7 @@ and you are good to go!

Example `docker-compose.yml` file:

```
```yaml
version: '3'
services:
cache:
Expand Down
Binary file added docs/assets/img/admin-environment-indicator.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 added docs/assets/img/admin-flag-editing-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion its_on/admin/views/switches.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from its_on.admin.utils import get_switch_history, save_switch_history
from its_on.models import switches
from its_on.schemes import RemoteSwitchesDataSchema
from its_on.utils import get_switch_badge_svg, get_switch_markdown_badge


class SwitchListAdminView(web.View):
Expand Down Expand Up @@ -83,12 +84,19 @@ class SwitchDetailAdminView(web.View, UpdateMixin):
model = switches

async def get_context_data(
self, switch: Optional[RowProxy] = None, errors: ValidationError = None, updated: bool = False,
self, switch: Optional[RowProxy] = None, errors: ValidationError = None,
updated: bool = False,
) -> Dict[str, Any]:
switch = switch if switch else await self.get_object(self.request)
switch_history = await get_switch_history(self.request, switch)

svg_badge = get_switch_badge_svg(self.request.host, switch)
markdown_badge = get_switch_markdown_badge(self.request, switch)

context_data = {
'object': switch,
'svg_badge': svg_badge,
'markdown_badge': markdown_badge,
'switch_history': switch_history,
'errors': errors,
'updated': updated,
Expand Down
10 changes: 10 additions & 0 deletions its_on/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from dynaconf import settings

SVG_BADGE_SETTINGS = settings.FLAG_SVG_BADGE

SVG_BADGE_BACKGROUND_COLOR = SVG_BADGE_SETTINGS.BACKGROUND_COLOR

SWITCH_IS_ACTIVE_SVG_BADGE_PREFIX = SVG_BADGE_SETTINGS.PREFIX.IS_ACTIVE
SWITCH_IS_INACTIVE_SVG_BADGE_PREFIX = SVG_BADGE_SETTINGS.PREFIX.IS_INACTIVE
SWITCH_IS_HIDDEN_SVG_BADGE_PREFIX = SVG_BADGE_SETTINGS.PREFIX.IS_HIDDEN
SWITCH_NOT_FOUND_SVG_BADGE_PREFIX = SVG_BADGE_SETTINGS.PREFIX.NOT_FOUND
9 changes: 8 additions & 1 deletion its_on/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,19 @@ async def dispose_redis_pool(app: web.Application) -> None:
redis_pool.close()
await redis_pool.wait_closed()

aiohttp_jinja2.setup(
jinja2_env = aiohttp_jinja2.setup(
app,
loader=jinja2.FileSystemLoader(
str(BASE_DIR / 'its_on' / 'templates'),
),
)

jinja2_env.globals.update({
'show_env_notice': settings.ENVIRONMENT_NOTICE.SHOW,
'env_notice_name': settings.ENVIRONMENT_NOTICE.ENVIRONMENT_NAME,
'env_notice_background_color': settings.ENVIRONMENT_NOTICE.BACKGROUND_COLOR,
})

app['static_root_url'] = '/static'

app.on_startup.append(init_pg)
Expand Down
9 changes: 8 additions & 1 deletion its_on/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from dynaconf import settings

from auth.views import LoginView, LogoutView
from its_on.views import SwitchFullListView, SwitchListView
from its_on.views import SwitchFullListView, SwitchListView, SwitchSvgBadgeView
from its_on.admin.views.switches import (
SwitchAddAdminView,
SwitchDeleteAdminView,
Expand Down Expand Up @@ -34,6 +34,13 @@ def setup_routes(app: Application, base_dir: Path, cors_config: CorsConfig) -> N
get_switch_view = app.router.add_view('/api/v1/switch', SwitchListView)
cors_config.add(get_switch_view)

get_switch_svg_badge_view = app.router.add_view(
'/api/v1/switches/{id}/svg-badge',
SwitchSvgBadgeView,
name='switch_svg_badge',
)
cors_config.add(get_switch_svg_badge_view)

if settings.ENABLE_SWITCHES_FULL_INFO_ENDPOINT:
get_switch_full_view = app.router.add_view('/api/v1/switches_full_info', SwitchFullListView)
cors_config.add(get_switch_full_view)
Expand Down
23 changes: 23 additions & 0 deletions its_on/static/img/active-flag-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions its_on/static/img/deleted-flag-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added its_on/static/img/favicon.ico
Binary file not shown.
23 changes: 23 additions & 0 deletions its_on/static/img/inactive-flag-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions its_on/static/img/unknown-flag-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 39 additions & 10 deletions its_on/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>ITS ON Admin</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="{{ static('css/style.css') }}">
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.min.js"></script>
{% block title %}
<title>ITS ON Admin</title>
{% endblock %}
{% block head_meta %}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/x-icon" href="{{ static('img/favicon.ico') }}"/>
{% endblock %}
{% block head_css %}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ static('css/style.css') }}">
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/css/select2.min.css" rel="stylesheet"/>
{% if show_env_notice %}
<style>
body:before {
display: block;
line-height: 35px;
text-align: center;
font-weight: bold;
text-transform: uppercase;
color: white;
content: "{{ env_notice_name }}";
background-color: {{ env_notice_background_color }};
}
</style>
{% endif %}
{% endblock %}
{% block head_js %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.min.js"></script>
{% endblock %}
</head>
<body>
{% block page_body %}
<div class="container-fluid">
<div class="row content">
<div class="col-sm-3 sidenav">
Expand All @@ -24,10 +48,15 @@ <h4>ITS ON Admin</h4>
<form action="/zbs/logout">
<button type="submit" class="btn btn-danger">Log out</button>
</form>
</ul><br>
</ul>
<br>
</div>
{% block content %}{% endblock %}
</div>
</div>
{% endblock %}

{% block tail_js %}
{% endblock %}
</body>
</html>
Loading

0 comments on commit 45a6526

Please sign in to comment.