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

Add option for rtl template content #1968

Merged
merged 37 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fda3079
feat(rtl template): refactor template content into a macro that will …
andrewleith Oct 8, 2024
246f825
chore: regen css/js
andrewleith Oct 8, 2024
15bce7c
feat(rtl template content): add switch to template form; pass switch …
andrewleith Oct 8, 2024
1500090
chore: formatting
andrewleith Oct 8, 2024
cd8da3b
chore: add translations
andrewleith Oct 8, 2024
0cb9460
chore: update temporary translation
andrewleith Oct 8, 2024
dc136be
chore: update temporary translatio again
andrewleith Oct 8, 2024
0aaf38e
chore: 😱
andrewleith Oct 8, 2024
f70f21a
chore: formatting
andrewleith Oct 8, 2024
5e379c7
a11y(rtl): update translations, add hint for users of assistive tech
andrewleith Oct 8, 2024
3e48fc3
chore: fix form label - will be overridden by .html
andrewleith Oct 8, 2024
fc92b3d
feat(highlighttags): make this plugin aware of RTL attribute
andrewleith Oct 11, 2024
e993cf9
feat(templateContent.js): only run the code when the checkbox is present
andrewleith Oct 11, 2024
801c614
fix(rtl): include text direction in preview data
andrewleith Oct 11, 2024
43e030b
chore(rtl): update tests
andrewleith Oct 11, 2024
89ce097
chore: formatting
andrewleith Oct 11, 2024
2d38ba0
Merge branch 'main' into feat/add-rtl-templates
andrewleith Oct 11, 2024
b117711
fix(highlighttags): ensure checkbox exists before setting text direction
andrewleith Oct 11, 2024
a1e0f39
feat(rtl): wrap in feature flag
andrewleith Oct 15, 2024
6cae90e
chore: update label name to match designs
andrewleith Oct 15, 2024
e3c8c8f
chore: formatting
andrewleith Oct 15, 2024
617f333
feat(rtl): remove `use_styled_checkbox` switch; implement fieldset; u…
andrewleith Oct 15, 2024
9880e30
chore: re-gen css
andrewleith Oct 15, 2024
2c07ffc
chore: add missing translation
andrewleith Oct 15, 2024
a7d571c
fix(highlightTags): only set `dir` attribute on template content
andrewleith Oct 15, 2024
d118dcb
chore: read FF_RTL from environment
andrewleith Oct 16, 2024
a66ec18
chore: bump utils
andrewleith Oct 16, 2024
2cc5825
chore: bump utils
andrewleith Oct 16, 2024
b217f0f
fix(rtl): remember rtl setting when previewing/editing
andrewleith Oct 17, 2024
408bff2
feat(checkbox): add testid param
andrewleith Oct 17, 2024
f67318c
test(rtl): add test-ids
andrewleith Oct 17, 2024
de17190
test(rtl): add ui tests
andrewleith Oct 17, 2024
4377bbc
Merge branch 'main' into feat/add-rtl-templates
andrewleith Oct 17, 2024
104d476
chore: re gen poetry.lock
andrewleith Oct 17, 2024
96cffb7
chore: remove duplicated button
andrewleith Oct 17, 2024
0868809
chore(ci): add text-direction tests to CI suite
andrewleith Oct 17, 2024
14907cc
Merge branch 'main' into feat/add-rtl-templates
andrewleith Oct 21, 2024
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
13 changes: 12 additions & 1 deletion app/assets/javascripts/highlightTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,24 @@
if (!("oninput" in document.createElement("input"))) return;

const tagPattern = /\(\(([^\)\((\?)]+)(\?\?)?([^\)\(]*)\)\)/g;
// set text_direction variable based on value of checkbox #text_direction_rtl
const textDirectionElement = document.getElementById("text_direction_rtl");
const textDirection =
textDirectionElement && textDirectionElement.checked ? "rtl" : "ltr";

Modules.HighlightTags = function () {
this.start = function (textarea) {
// only add the dir attribute if the textarea is the template_content
let extraMarkup = "";

if (textarea.attr("id") == "template_content") {
extraMarkup = ` dir="${textDirection}" `;
}

this.$textbox = $(textarea)
.wrap(
`
<div class='textbox-highlight-wrapper' />
<div class='textbox-highlight-wrapper'${extraMarkup}/>
`,
)
.after(
Expand Down
20 changes: 20 additions & 0 deletions app/assets/javascripts/templateContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* This module enhances the template content text area with a switch to enable right-to-left text direction.
*/
(function () {
const checkbox = document.getElementById("text_direction_rtl");
const content = document.getElementById("template_content");

// update the dir attribute when checkbox is clicked
if (checkbox) {
checkbox.addEventListener("change", function () {
content.dir = this.checked ? "rtl" : "ltr";
content.closest(".textbox-highlight-wrapper").dir = content.dir;
});

// on page load, if the checkbox is checked, set the dir attribute
if (checkbox.checked) {
content.dir = "rtl";
}
}
})();
2 changes: 1 addition & 1 deletion app/assets/stylesheets/index.css

Large diffs are not rendered by default.

15 changes: 3 additions & 12 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class Config(object):

# FEATURE FLAGS
FF_SALESFORCE_CONTACT = env.bool("FF_SALESFORCE_CONTACT", True)
FF_RTL = env.bool("FF_RTL", True)

FREE_YEARLY_EMAIL_LIMIT = env.int("FREE_YEARLY_EMAIL_LIMIT", 10_000_000)
FREE_YEARLY_SMS_LIMIT = env.int("FREE_YEARLY_SMS_LIMIT", 25_000)
Expand Down Expand Up @@ -211,12 +212,7 @@ class Test(Development):
SYSTEM_STATUS_URL = "https://localhost:3000"
NO_BRANDING_ID = "0af93cf1-2c49-485f-878f-f3e662e651ef"

FF_SPIKE_SMS_DAILY_LIMIT = True
FF_SMS_PARTS_UI = False
FF_BOUNCE_RATE_V1 = True
FF_BOUNCE_RATE_V15 = True
FF_BOUNCE_RATE_BACKEND = True
FF_ABTEST_SERVICE_ID = ""
FF_RTL = True


class ProductionFF(Config):
Expand All @@ -242,12 +238,7 @@ class ProductionFF(Config):
SYSTEM_STATUS_URL = "https://localhost:3000"
NO_BRANDING_ID = "0af93cf1-2c49-485f-878f-f3e662e651ef"

FF_SPIKE_SMS_DAILY_LIMIT = True
FF_SMS_PARTS_UI = False
FF_BOUNCE_RATE_V1 = True
FF_BOUNCE_RATE_V15 = True
FF_BOUNCE_RATE_BACKEND = True
FF_ABTEST_SERVICE_ID = ""
FF_RTL = False


class Production(Config):
Expand Down
5 changes: 4 additions & 1 deletion app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,9 @@ class BaseTemplateForm(StripWhitespaceForm):
NoCommasInPlaceHolders(),
],
)

text_direction_rtl = BooleanField("text_direction_rtl")

process_type = RadioField(
_l("Select a priority queue"),
choices=[
Expand Down Expand Up @@ -838,7 +841,7 @@ class EmailTemplateFormWithCategory(BaseTemplateFormWithCategory):
subject = TextAreaField(_l("Subject line of the email"), validators=[DataRequired(message=_l("This cannot be empty"))])

template_content = TextAreaField(
_l("Email message"),
_l("Email content"),
validators=[
DataRequired(message=_l("This cannot be empty")),
NoCommasInPlaceHolders(),
Expand Down
6 changes: 6 additions & 0 deletions app/main/views/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def preview_template(service_id, template_id=None):
template["subject"],
None if template["process_type"] == TC_PRIORITY_VALUE else template["process_type"],
template["template_category_id"],
template["text_direction_rtl"],
)
else:
new_template = service_api_client.create_service_template(
Expand Down Expand Up @@ -767,6 +768,7 @@ def add_service_template(service_id, template_type, template_folder_id=None): #
"process_type": form.process_type.data,
"folder": template_folder_id,
"template_category_id": form.template_category_id.data,
"text_direction_rtl": form.text_direction_rtl.data,
}
set_preview_data(preview_template_data, service_id)
return redirect(
Expand Down Expand Up @@ -897,6 +899,8 @@ def edit_service_template(service_id, template_id):
template["content"] = new_template_data["content"]
template["name"] = new_template_data["name"]
template["subject"] = new_template_data["subject"]
template["text_direction_rtl"] = new_template_data["text_direction_rtl"]

template["template_content"] = template["content"]

if template.get("process_type_column") is None:
Expand All @@ -920,6 +924,7 @@ def edit_service_template(service_id, template_id):
"reply_to_text": template["reply_to_text"],
"folder": template["folder"],
"template_category_id": form.template_category_id.data,
"text_direction_rtl": form.text_direction_rtl.data,
}
set_preview_data(new_template_data, service_id, template_id)

Expand Down Expand Up @@ -959,6 +964,7 @@ def edit_service_template(service_id, template_id):
subject,
None if form.process_type.data == TC_PRIORITY_VALUE else form.process_type.data,
form.template_category_id.data,
form.text_direction_rtl.data,
)
# Send the information in form's template_category_other field to Freshdesk
# This code path is a little complex - We do not want to raise an error if the request to Freshdesk fails, only if template creation fails
Expand Down
23 changes: 22 additions & 1 deletion app/notify_client/service_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def create_service_template(
process_type="normal",
parent_folder_id=None,
template_category_id=None,
text_direction_rtl=False,
):
"""
Create a service template.
Expand All @@ -208,6 +209,11 @@ def create_service_template(
"process_type": process_type,
"template_category_id": template_category_id,
}

# Move this into `data` dictionary above 👆 when FF_RTL removed
if current_app.config["FF_RTL"]:
data["text_direction_rtl"] = text_direction_rtl

if subject:
data.update({"subject": subject})
if parent_folder_id:
Expand All @@ -220,7 +226,16 @@ def create_service_template(
@cache.delete("template-{id_}-version-None")
@cache.delete("template-{id_}-versions")
def update_service_template(
self, id_, name, type_, content, service_id, subject=None, process_type=None, template_category_id=None
self,
id_,
name,
type_,
content,
service_id,
subject=None,
process_type=None,
template_category_id=None,
text_direction_rtl=False,
):
"""
Update a service template.
Expand All @@ -233,7 +248,13 @@ def update_service_template(
"service": service_id,
"template_category_id": template_category_id,
"process_type": process_type,
"text_direction_rtl": text_direction_rtl,
}

# Move this into `data` dictionary above 👆 when FF_RTL removed
if current_app.config["FF_RTL"]:
data["text_direction_rtl"] = text_direction_rtl

if subject:
data.update({"subject": subject})

Expand Down
7 changes: 5 additions & 2 deletions app/templates/components/checkbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@
{% endmacro %}


{% macro checkbox_input(id, name, data=None, value="y") %}
{% macro checkbox_input(id, name, data=None, value="y", class="", testid=None) %}
<input
id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ value }}"
id="{{ id }}" name="{{ name }}" type="checkbox" value="{{ value }}" class="{{ class }}"
{% if data %}
checked
{% endif %}
{% if testid %}
data-testid="{{ testid }}"
{% endif %}
>
{% endmacro %}

Expand Down
21 changes: 21 additions & 0 deletions app/templates/components/template-content.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% from "components/checkbox.html" import checkbox, checkbox_input %}
{% from "components/textbox.html" import textbox %}

{% macro template_content(content_field, checkbox_field) %}
<!-- TODO: remove `use_styled_checkbox` and this if statement once we decide on the UI element to use here -->

<fieldset class="contain-floats w-full" role="radiogroup">
<legend>
<span>{{ _('Email message') }}</span>
</legend>
{% if config["FF_RTL"] %}
<div class="p-2 bg-gray-300 flex items-center">
{{ checkbox_input(checkbox_field.id, checkbox_field.name, checkbox_field.data, class="h-8 w-8 mr-2", testid="template-rtl") }}
<label class="pb-0 inline-block text-small" for="text_direction_rtl">{{ _('Display') }}<span class="sr-only"> {{ _('email content') }} </span> {{ _('right to left') }}</label>
</div>
{% endif %}

{{ textbox(content_field, highlight_tags=True, width='w-full', rows=8, testid="template-content", label_class="sr-only" ) }}
</fieldset>

{% endmacro %}
7 changes: 4 additions & 3 deletions app/templates/components/textbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
rows=8,
required=true,
is_page_heading=false,
testid=None
testid=None,
label_class=None
) %}
<div
class="form-group contain-floats box-border mb-gutterHalf md:mb-gutter{% if field.errors %} form-group-error{% endif %}"
Expand All @@ -22,9 +23,9 @@
{% set describedby = '' %}

{% if is_page_heading %}
<h1><label class="form-label heading-large" for="{{ field.name }}" >
<h1><label class="form-label heading-large{% if label_class %} {{ label_class }} {% endif %}" for="{{ field.name }}" >
{% else %}
<label class="form-label" for="{{ field.name }}" >
<label class="form-label{% if label_class %} {{ label_class }} {% endif %}" for="{{ field.name }}" >
{% endif %}
{% if label %}
{{ label }}
Expand Down
7 changes: 4 additions & 3 deletions app/templates/views/edit-email-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
{% from "components/form.html" import form_wrapper %}
{% from "components/task-shortcut.html" import task_shortcut %}
{% from "components/template-category.html" import template_category %}
{% from "components/template-content.html" import template_content with context%}

{% block service_page_title %}
{{ heading }}
Expand Down Expand Up @@ -50,9 +51,9 @@
{{ textbox(form.name, width='w-full', hint=_('This will not show in the message. Use a name that helps you find the template when you need it.'), rows=10, testid="template-name") }}

{{ textbox(form.subject, width='w-full', highlight_tags=True, rows=2, hint=_("Tell recipients what the email is about. Try to use less than 10 words.", testid="template-subject")) }}

{{ textbox(form.template_content, highlight_tags=True, width='w-full', rows=8, testid="template-content" ) }}

{{ template_content(form.template_content, form.text_direction_rtl) }}
<h2 class="heading-medium">{{ _('Template category') }}</h2>
{% call template_category(form.template_category_id, true if template_category_mode == 'expand' else false) %}
{{ select(form.template_category_id, hint=_('Template categories help improve delivery of your messages'), option_hints=template_category_hints, option_conditionals=other_category, testid="template-categories", use_aria_labelledby=false) }}
Expand Down
2 changes: 1 addition & 1 deletion app/templates/views/templates/_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<h2 class="heading-medium">{{ _('Ready to send?') }}</h2>

<div class="mb-12">
<a href="{{ url_for('.add_recipients', service_id=current_service.id, template_id=template.id) }}" class="button">
<a href="{{ url_for('.add_recipients', service_id=current_service.id, template_id=template.id) }}" class="button" data-testid="add-recipients">
{{ _('Yes, add recipients') }}
</a>
<a href="{{ url_for('.send_test', service_id=current_service.id, template_id=template.id) }}" class="button button-secondary">{{ _('No, send yourself this message') }}</a>
Expand Down
6 changes: 5 additions & 1 deletion app/translations/csv/fr.csv
Original file line number Diff line number Diff line change
Expand Up @@ -1986,4 +1986,8 @@
"The service {} responded in {} seconds.","Le service {} a répondu en {} secondes."
"Are you sure you want to delete this callback configuration?","Voulez-vous vraiment supprimer cette configuration de rappel?"
"Your Callback configuration has been deleted.","Votre configuration de rappel a été supprimée."
"The service {} took longer than 1 second to respond.","Le service {} a mis plus d’une seconde à répondre."
"The service {} took longer than 1 second to respond.","Le service {} a mis plus d’une seconde à répondre."
"Display","Afficher"
"email content","le message du courriel"
"Email content","Message du courriel"
"right to left","de droite à gauche"
1 change: 1 addition & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const javascripts = () => {
paths.src + "javascripts/notificationsReports.js",
paths.src + "javascripts/main.js",
paths.src + "javascripts/templateCategories.js",
paths.src + "javascripts/templateContent.js",
])
.pipe(plugins.prettyerror())
.pipe(
Expand Down
8 changes: 4 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ unidecode = "^1.3.8"

# PaaS
awscli-cwlogs = "^1.4.6"
notifications-utils = { git = "https://github.com/cds-snc/notifier-utils.git", tag = "52.3.3" }
notifications-utils = { git = "https://github.com/cds-snc/notifier-utils.git", tag = "52.3.5" }


# Pinned dependencies
certifi = "^2024.0.0" # Pinned for security reasons: https://github.com/cds-snc/notification-admin/security/dependabot/169
Expand Down
Loading
Loading