mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-14 17:08:29 +00:00
Add a "Create a Copy" function for cloning checks Fixes #288
This commit is contained in:
parent
a5827c6458
commit
488ab2cce7
8 changed files with 122 additions and 12 deletions
|
@ -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
hc/front/tests/test_copy.py
Normal file
18
hc/front/tests/test_copy.py
Normal 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="alice@example.org", 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)")
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
templates/front/copy_modal.html
Normal file
32
templates/front/copy_modal.html
Normal 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">×</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>
|
|
@ -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
|
You can now
|
||||||
<a data-target="edit-name" href="#" >give it a name</a>
|
<a data-target="edit-name" href="#" >give it a name</a>
|
||||||
or
|
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…</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…</button>
|
class="btn btn-sm btn-default">Transfer to Another Project…</button>
|
||||||
|
|
||||||
<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,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
|
<form action="{% url 'hc-remove-check' check.code %}" method="post">
|
||||||
id="remove-check-form"
|
|
||||||
{% if check %}action="{% url 'hc-remove-check' check.code %}"{% endif %}
|
|
||||||
method="post">
|
|
||||||
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
Loading…
Add table
Reference in a new issue