mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-19 22:13:48 -04:00
Add option to copy existing template when adding
Sometimes when setting up a service you might have a few very similar templates, in which only a small amount of content. Or you might even have a few of services, which are used by different teams but have similar templates. Copy and pasting, especially from one service to another, is a pain. This commit makes it easier by allowing users to copy an existing template when choosing to add a new one, instead of starting from scratch.
This commit is contained in:
@@ -81,6 +81,14 @@
|
||||
margin-bottom: $gutter * 2;
|
||||
}
|
||||
|
||||
.left-gutter {
|
||||
padding-left: $gutter;
|
||||
}
|
||||
|
||||
.left-gutter-4-3 {
|
||||
padding-left: $gutter * 4 / 3;
|
||||
}
|
||||
|
||||
.align-with-heading {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
||||
@@ -837,14 +837,15 @@ class ChooseTemplateType(StripWhitespaceForm):
|
||||
]
|
||||
)
|
||||
|
||||
def __init__(self, include_letters=False, *args, **kwargs):
|
||||
def __init__(self, include_letters=False, include_copy=False, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.template_type.choices = filter(None, [
|
||||
('email', 'Email'),
|
||||
('sms', 'Text message'),
|
||||
('letter', 'Letter') if include_letters else None
|
||||
('letter', 'Letter') if include_letters else None,
|
||||
('copy-existing', 'Copy of an existing template') if include_copy else None,
|
||||
])
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,12 @@ from notifications_python_client.errors import HTTPError
|
||||
from notifications_utils.formatters import nl2br
|
||||
from notifications_utils.recipients import first_column_headings
|
||||
|
||||
from app import current_service, service_api_client, template_statistics_client
|
||||
from app import (
|
||||
current_service,
|
||||
service_api_client,
|
||||
template_statistics_client,
|
||||
user_api_client,
|
||||
)
|
||||
from app.main import main
|
||||
from app.main.forms import (
|
||||
ChooseTemplateType,
|
||||
@@ -202,11 +207,21 @@ def view_template_version_preview(service_id, template_id, version, filetype):
|
||||
def add_template_by_type(service_id):
|
||||
|
||||
form = ChooseTemplateType(
|
||||
include_letters='letter' in current_service['permissions']
|
||||
include_letters='letter' in current_service['permissions'],
|
||||
include_copy=any((
|
||||
service_api_client.count_service_templates(service_id),
|
||||
len(user_api_client.get_service_ids_for_user(current_user)) > 1,
|
||||
)),
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
|
||||
if form.template_type.data == 'copy-existing':
|
||||
return redirect(url_for(
|
||||
'.choose_template_to_copy',
|
||||
service_id=service_id,
|
||||
))
|
||||
|
||||
if form.template_type.data == 'letter':
|
||||
blank_letter = service_api_client.create_service_template(
|
||||
'Untitled',
|
||||
@@ -240,6 +255,51 @@ def add_template_by_type(service_id):
|
||||
return render_template('views/templates/add.html', form=form)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/templates/copy")
|
||||
@login_required
|
||||
@user_has_permissions('manage_templates')
|
||||
def choose_template_to_copy(service_id):
|
||||
return render_template(
|
||||
'views/templates/copy.html',
|
||||
services=[{
|
||||
'name': service['name'],
|
||||
'id': service['id'],
|
||||
'templates': [
|
||||
template for template in
|
||||
service_api_client.get_service_templates(service['id'])['data']
|
||||
if template['template_type'] in current_service['permissions']
|
||||
],
|
||||
} for service in user_api_client.get_services_for_user(current_user)],
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/templates/copy/<uuid:template_id>", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions('manage_templates')
|
||||
def copy_template(service_id, template_id):
|
||||
|
||||
if not user_api_client.user_belongs_to_service(
|
||||
current_user, request.args.get('from_service')
|
||||
):
|
||||
abort(403)
|
||||
|
||||
template = service_api_client.get_service_template(
|
||||
request.args.get('from_service'),
|
||||
str(template_id),
|
||||
)['data']
|
||||
template['template_content'] = template['content']
|
||||
template['name'] = 'Copy of ‘{}’'.format(template['name'])
|
||||
form = form_objects[template['template_type']](**template)
|
||||
|
||||
return render_template(
|
||||
'views/edit-{}-template.html'.format(template['template_type']),
|
||||
form=form,
|
||||
template_type=template['template_type'],
|
||||
heading_action='Add',
|
||||
services=user_api_client.get_service_ids_for_user(current_user),
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/templates/action-blocked/<notification_type>/<return_to>/<template_id>")
|
||||
@login_required
|
||||
@user_has_permissions('manage_templates')
|
||||
|
||||
@@ -125,6 +125,7 @@ class HeaderNavigation(Navigation):
|
||||
'choose_account',
|
||||
'choose_service',
|
||||
'choose_template',
|
||||
'choose_template_to_copy',
|
||||
'confirm_edit_organisation_name',
|
||||
'confirm_redact_template',
|
||||
'conversation',
|
||||
@@ -132,6 +133,7 @@ class HeaderNavigation(Navigation):
|
||||
'conversation_reply_with_template',
|
||||
'conversation_updates',
|
||||
'cookies',
|
||||
'copy_template',
|
||||
'create_api_key',
|
||||
'delete_service_template',
|
||||
'delivery_and_failure',
|
||||
@@ -291,8 +293,10 @@ class MainNavigation(Navigation):
|
||||
'check_messages',
|
||||
'check_notification',
|
||||
'choose_template',
|
||||
'choose_template_to_copy',
|
||||
'confirm_redact_template',
|
||||
'conversation_reply',
|
||||
'copy_template',
|
||||
'delete_service_template',
|
||||
'edit_service_template',
|
||||
'send_messages',
|
||||
@@ -544,6 +548,7 @@ class CaseworkNavigation(Navigation):
|
||||
'check_notification',
|
||||
'choose_account',
|
||||
'choose_service',
|
||||
'choose_template_to_copy',
|
||||
'confirm_edit_organisation_name',
|
||||
'confirm_redact_template',
|
||||
'conversation',
|
||||
@@ -551,6 +556,7 @@ class CaseworkNavigation(Navigation):
|
||||
'conversation_reply_with_template',
|
||||
'conversation_updates',
|
||||
'cookies',
|
||||
'copy_template',
|
||||
'create_api_key',
|
||||
'create_email_branding',
|
||||
'delete_service_template',
|
||||
@@ -771,12 +777,14 @@ class OrgNavigation(Navigation):
|
||||
'choose_account',
|
||||
'choose_service',
|
||||
'choose_template',
|
||||
'choose_template_to_copy',
|
||||
'confirm_redact_template',
|
||||
'conversation',
|
||||
'conversation_reply',
|
||||
'conversation_reply_with_template',
|
||||
'conversation_updates',
|
||||
'cookies',
|
||||
'copy_template',
|
||||
'create_api_key',
|
||||
'create_email_branding',
|
||||
'delete_service_template',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from itertools import chain
|
||||
|
||||
from notifications_python_client.errors import HTTPError
|
||||
|
||||
from app.notify_client import NotifyAdminAPIClient, cache
|
||||
@@ -209,3 +211,17 @@ class UserApiClient(NotifyAdminAPIClient):
|
||||
def get_organisations_and_services_for_user(self, user):
|
||||
endpoint = '/user/{}/organisations-and-services'.format(user.id)
|
||||
return self.get(endpoint)
|
||||
|
||||
def get_services_for_user(self, user):
|
||||
orgs_and_services_for_user = self.get_organisations_and_services_for_user(user)
|
||||
return orgs_and_services_for_user['services_without_organisations'] + next(chain(
|
||||
org['services'] for org in orgs_and_services_for_user['organisations']
|
||||
), [])
|
||||
|
||||
def get_service_ids_for_user(self, user):
|
||||
return {
|
||||
service['id'] for service in self.get_services_for_user(user)
|
||||
}
|
||||
|
||||
def user_belongs_to_service(self, user, service_id):
|
||||
return service_id in self.get_service_ids_for_user(user)
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
{{ heading_action }} email template
|
||||
</h1>
|
||||
|
||||
<form method="post">
|
||||
<form
|
||||
method="post"
|
||||
action="{{ url_for('.add_service_template', service_id=current_service.id, template_type=template_type) }}"
|
||||
>
|
||||
<div class="grid-row">
|
||||
<div class="column-five-sixths">
|
||||
{{ textbox(form.name, width='1-1', hint='Your recipients won’t see this', rows=10) }}
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
{{ heading_action }} letter template
|
||||
</h1>
|
||||
|
||||
<form method="post">
|
||||
<form
|
||||
method="post"
|
||||
action="{{ url_for('.add_service_template', service_id=current_service.id, template_type=template_type) }}"
|
||||
>
|
||||
<div class="grid-row">
|
||||
<div class="column-five-sixths">
|
||||
{{ textbox(form.name, width='1-1', hint='Your recipients won’t see this', rows=10) }}
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
{{ heading_action }} text message template
|
||||
</h1>
|
||||
|
||||
<form method="post">
|
||||
<form
|
||||
method="post"
|
||||
action="{{ url_for('.add_service_template', service_id=current_service.id, template_type=template_type) }}"
|
||||
>
|
||||
<div class="grid-row">
|
||||
<div class="column-two-thirds">
|
||||
{{ textbox(form.name, width='1-1', hint='Your recipients won’t see this') }}
|
||||
|
||||
36
app/templates/views/templates/copy.html
Normal file
36
app/templates/views/templates/copy.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{% from "components/message-count-label.html" import message_count_label %}
|
||||
|
||||
{% extends "withnav_template.html" %}
|
||||
|
||||
{% block service_page_title %}
|
||||
Copy an existing template
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
<div class="bottom-gutter-3-2">
|
||||
<h1 class="heading-large">Copy an existing template</h1>
|
||||
</div>
|
||||
<nav>
|
||||
{% for service in services %}
|
||||
{% if service.templates and services|length > 1 %}
|
||||
<h2 class="">
|
||||
{{ service.name }}
|
||||
</h2>
|
||||
<div class="left-gutter-4-3 bottom-gutter-3-2">
|
||||
{% endif %}
|
||||
{% for template in service.templates %}
|
||||
<h2 class="message-name">
|
||||
<a href="{{ url_for('.copy_template', service_id=current_service.id, template_id=template.id, from_service=service.id) }}">{{ template.name }}</a>
|
||||
</h2>
|
||||
<p class="message-type">
|
||||
{{ message_count_label(1, template.template_type, suffix='')|capitalize }} template
|
||||
</p>
|
||||
{% endfor %}
|
||||
{% if service.templates %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</nav>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user