Browse Source

Add a "Create a Copy" function for cloning checks Fixes #288

pull/307/head
Pēteris Caune 5 years ago
parent
commit
488ab2cce7
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
8 changed files with 122 additions and 12 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +18
    -0
      hc/front/tests/test_copy.py
  3. +1
    -0
      hc/front/urls.py
  4. +22
    -0
      hc/front/views.py
  5. +22
    -0
      static/css/details.css
  6. +32
    -0
      templates/front/copy_modal.html
  7. +25
    -7
      templates/front/details.html
  8. +1
    -5
      templates/front/remove_check_modal.html

+ 1
- 0
CHANGELOG.md View File

@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
- Autofocus the email field in the signup form, and submit on enter key - Autofocus the email field in the signup form, and submit on enter key
- Add support for OpsGenie EU region (#294) - Add support for OpsGenie EU region (#294)
- Update OpsGenie logo and setup illustrations - Update OpsGenie logo and setup illustrations
- Add a "Create a Copy" function for cloning checks (#288)
### Bug Fixes ### Bug Fixes
- Prevent double-clicking the submit button in signup form - Prevent double-clicking the submit button in signup form


+ 18
- 0
hc/front/tests/test_copy.py View File

@ -0,0 +1,18 @@
from hc.api.models import Channel, Check
from hc.test import BaseTestCase
class CopyCheckTestCase(BaseTestCase):
def setUp(self):
super(CopyCheckTestCase, self).setUp()
self.check = Check(project=self.project)
self.check.name = "Foo"
self.check.save()
self.copy_url = "/checks/%s/copy/" % self.check.code
def test_it_works(self):
self.client.login(username="[email protected]", password="password")
r = self.client.post(self.copy_url, follow=True)
self.assertContains(r, "This is a brand new check")
self.assertContains(r, "Foo (copy)")

+ 1
- 0
hc/front/urls.py View File

@ -13,6 +13,7 @@ check_urls = [
path("status/", views.status_single, name="hc-status-single"), path("status/", views.status_single, name="hc-status-single"),
path("last_ping/", views.ping_details, name="hc-last-ping"), path("last_ping/", views.ping_details, name="hc-last-ping"),
path("transfer/", views.transfer, name="hc-transfer"), path("transfer/", views.transfer, name="hc-transfer"),
path("copy/", views.copy, name="hc-copy"),
path( path(
"channels/<uuid:channel_code>/enabled", "channels/<uuid:channel_code>/enabled",
views.switch_channel, views.switch_channel,


+ 22
- 0
hc/front/views.py View File

@ -483,6 +483,7 @@ def details(request, code):
"timezones": pytz.all_timezones, "timezones": pytz.all_timezones,
"downtimes": check.downtimes(months=3), "downtimes": check.downtimes(months=3),
"is_new": "new" in request.GET, "is_new": "new" in request.GET,
"is_copied": "copied" in request.GET,
} }
return render(request, "front/details.html", ctx) return render(request, "front/details.html", ctx)
@ -513,6 +514,27 @@ def transfer(request, code):
return render(request, "front/transfer_modal.html", ctx) return render(request, "front/transfer_modal.html", ctx)
@require_POST
@login_required
def copy(request, code):
check = _get_check_for_user(request, code)
copied = Check(project=check.project)
copied.name = check.name + " (copy)"
copied.desc, copied.tags = check.desc, check.tags
copied.subject = check.subject
copied.kind = check.kind
copied.timeout, copied.grace = check.timeout, check.grace
copied.schedule, copied.tz = check.schedule, check.tz
copied.save()
copied.channel_set.add(*check.channel_set.all())
url = reverse("hc-details", args=[copied.code])
return redirect(url + "?copied")
@login_required @login_required
def status_single(request, code): def status_single(request, code):
check = _get_check_for_user(request, code) check = _get_check_for_user(request, code)


+ 22
- 0
static/css/details.css View File

@ -103,3 +103,25 @@
text-align: center; text-align: center;
padding: 32px; padding: 32px;
} }
ul.checkmarks {
padding-left: 20px;
list-style: none;
color: #117a3f;
}
ul.checkmarks li:before {
content: '✔ ';
}
ul.crosses {
padding-left: 20px;
list-style: none;
color: #aa413e;
}
ul.crosses li:before {
content: '✘ ';
}

+ 32
- 0
templates/front/copy_modal.html View File

@ -0,0 +1,32 @@
<div id="copy-modal" class="modal">
<div class="modal-dialog">
<form action="{% url 'hc-copy' check.code %}" method="post">
{% csrf_token %}
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4>Create a Copy of This Check</h4>
</div>
<div class="modal-body">
<p>You are about to <strong>create a new check based on this
check's configuration</strong>. The following items will
get copied:</p>
<ul class="checkmarks">
<li>Name, tags and description</li>
<li>Schedule</li>
<li>Assigned notification methods</li>
</ul>
<p>The following items <em>will not</em> be copied:</p>
<ul class="crosses">
<li>Its URL (a new URL will be generated)</li>
<li>The log of already received pings</li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Create a Copy</button>
</div>
</div>
</form>
</div>
</div>

+ 25
- 7
templates/front/details.html View File

@ -11,12 +11,23 @@
<div class="col-sm-12"> <div class="col-sm-12">
<p id="new-check-alert" class="alert alert-success"> <p id="new-check-alert" class="alert alert-success">
<strong>Your new check is ready!</strong> <strong>Your new check is ready!</strong>
You can now
<a data-target="edit-name" href="#" >give it a name</a>
or
You can now
<a data-target="edit-name" href="#" >give it a name</a>
or
<a data-target="edit-timeout" href="#" >set its schedule</a>. <a data-target="edit-timeout" href="#" >set its schedule</a>.
</p> </p>
</div>
</div>
{% endif %}
{% if is_copied %}
<div class="col-sm-12">
<p id="new-check-alert" class="alert alert-success">
<strong>Copy created!</strong>
This is a brand new check, with details copied over from your existing check.
You might now want to
<a data-target="edit-name" href="#">update its name and tags</a>.
</p>
</div>
{% endif %} {% endif %}
{% if messages %} {% if messages %}
@ -196,15 +207,21 @@
<div class="details-block"> <div class="details-block">
<h2>Danger Zone</h2> <h2>Danger Zone</h2>
<p>Transfer to a different project, or permanently remove this check.</p>
<p>Copy, Transfer, or permanently remove this check.</p>
<div class="text-right"> <div class="text-right">
<button
id="copy-btn"
data-toggle="modal"
data-target="#copy-modal"
class="btn btn-sm btn-default">Create a Copy&hellip;</button>
<button <button
id="transfer-btn" id="transfer-btn"
data-toggle="modal" data-toggle="modal"
data-target="#transfer-modal" data-target="#transfer-modal"
data-url="{% url 'hc-transfer' check.code %}" data-url="{% url 'hc-transfer' check.code %}"
class="btn btn-sm btn-default">Transfer to Another Project&hellip;</button> class="btn btn-sm btn-default">Transfer to Another Project&hellip;</button>
&nbsp;
<button <button
id="details-remove-check" id="details-remove-check"
data-toggle="modal" data-toggle="modal"
@ -223,13 +240,13 @@
<label class="btn btn-default btn-xs" data-format="UTC"> <label class="btn btn-default btn-xs" data-format="UTC">
<input type="radio" name="date-format"> <input type="radio" name="date-format">
UTC UTC
</label>
</label>
{% if check.kind == "cron" and check.tz != "UTC" %} {% if check.kind == "cron" and check.tz != "UTC" %}
<label class="btn btn-default btn-xs" data-format="{{ check.tz }}"> <label class="btn btn-default btn-xs" data-format="{{ check.tz }}">
<input type="radio" name="date-format"> <input type="radio" name="date-format">
{{ check.tz }} {{ check.tz }}
</label>
</label>
{% endif %} {% endif %}
<label class="btn btn-default btn-xs active" data-format="local"> <label class="btn btn-default btn-xs active" data-format="local">
@ -263,6 +280,7 @@
{% include "front/show_usage_modal.html" %} {% include "front/show_usage_modal.html" %}
{% include "front/remove_check_modal.html" %} {% include "front/remove_check_modal.html" %}
{% include "front/email_settings_modal.html" %} {% include "front/email_settings_modal.html" %}
{% include "front/copy_modal.html" %}
{% endblock %} {% endblock %}


+ 1
- 5
templates/front/remove_check_modal.html View File

@ -1,10 +1,6 @@
<div id="remove-check-modal" class="modal"> <div id="remove-check-modal" class="modal">
<div class="modal-dialog"> <div class="modal-dialog">
<form
id="remove-check-form"
{% if check %}action="{% url 'hc-remove-check' check.code %}"{% endif %}
method="post">
<form action="{% url 'hc-remove-check' check.code %}" method="post">
{% csrf_token %} {% csrf_token %}
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">


Loading…
Cancel
Save