diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml index 38947c4b3..65384ac81 100644 --- a/.github/workflows/deploy-demo.yml +++ b/.github/workflows/deploy-demo.yml @@ -57,12 +57,12 @@ jobs: COMMIT_HASH: $(git rev-parse --short "$GITHUB_SHA") LOGIN_PEM: ${{ secrets.LOGIN_PEM }} LOGIN_DOT_GOV_CLIENT_ID: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov" - LOGIN_DOT_GOV_USER_INFO_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/userinfo" - LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/token" - LOGIN_DOT_GOV_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-demo.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?" + LOGIN_DOT_GOV_USER_INFO_URL: "https://secure.login.gov/api/openid_connect/userinfo" + LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://secure.login.gov/api/openid_connect/token" + LOGIN_DOT_GOV_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-demo.app.cloud.gov/sign-out" + LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?" LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://notify-demo.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://idp.int.identitysandbox.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" + LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" with: cf_username: ${{ secrets.CLOUDGOV_USERNAME }} cf_password: ${{ secrets.CLOUDGOV_PASSWORD }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ac6aac9d0..cbb7b9bb7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -63,12 +63,12 @@ jobs: COMMIT_HASH: $(git rev-parse --short "$GITHUB_SHA") LOGIN_PEM: ${{ secrets.LOGIN_PEM }} LOGIN_DOT_GOV_CLIENT_ID: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov" - LOGIN_DOT_GOV_USER_INFO_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/userinfo" - LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://idp.int.identitysandbox.gov/api/openid_connect/token" - LOGIN_DOT_GOV_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-staging.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://idp.int.identitysandbox.gov/openid_connect/logout?" + LOGIN_DOT_GOV_USER_INFO_URL: "https://secure.login.gov/api/openid_connect/userinfo" + LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://secure.login.gov/api/openid_connect/token" + LOGIN_DOT_GOV_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-staging.app.cloud.gov/sign-out" + LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?" LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://notify-staging.app.cloud.gov/sign-out" - LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://idp.int.identitysandbox.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" + LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop" with: cf_username: ${{ secrets.CLOUDGOV_USERNAME }} cf_password: ${{ secrets.CLOUDGOV_PASSWORD }} diff --git a/README.md b/README.md index e98fe4535..0d080c9d8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![notify-logo](https://github.com/GSA/notifications-admin/assets/4156602/31b74039-4d87-4f89-a35e-71e9f3152342) + # Notify.gov Admin UI This is the Notify front-end for government users and admins. To see it in diff --git a/app/assets/sass/uswds/_legacy-styles.scss b/app/assets/sass/uswds/_legacy-styles.scss index 3b09e2218..b96a24844 100644 --- a/app/assets/sass/uswds/_legacy-styles.scss +++ b/app/assets/sass/uswds/_legacy-styles.scss @@ -48,13 +48,13 @@ } } -.sms-message-sender { - margin: units(1) 0 0; +.sms-message-sender, .sms-message-file-name, .sms-message-scheduler, .sms-message-template, .sms-message-sender { + margin:0.25rem 0 0; } .sms-message-recipient { color: color('gray-cool-90'); - margin: 0 0 units(1); + margin: units(1) 0 units(1); } .sms-message-status { @@ -131,7 +131,7 @@ &-label, &-button-label { font-weight: bold; - font-size: 19px; + font-size: 19px; display: block; margin: 0 0 10px 0; } diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss index addf9cc7a..55f17a795 100644 --- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss +++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss @@ -26,7 +26,7 @@ i.e. .usa-logo { font-family: family("sans"); margin: units(4) 0; - @include at-media-max('mobile-lg') { + @include at-media-max('desktop') { margin: units(4) 0 units(4) units(2); } img { @@ -43,6 +43,16 @@ i.e. text-decoration: underline; } } + @include at-media-max('desktop') { + padding: 0 units(2); + ul li { + padding-bottom: units(1); + } + } + } + .usa-nav-container { + max-width: 100%; + padding: 0; } } @@ -345,6 +355,9 @@ td.table-empty-message { background-image: url(../img/material-icons/description.svg); } } + .table-wrapper { + overflow-x: scroll; + } } .dashboard-table { @@ -403,8 +416,11 @@ td.table-empty-message { width: 5%; } th { - padding: 0.5rem 0.5rem; + padding: 0.5rem 1rem } + td { + padding: 0.5rem 1rem + } } #template-list { diff --git a/app/config.py b/app/config.py index b1bdeafd8..4328f4a75 100644 --- a/app/config.py +++ b/app/config.py @@ -36,7 +36,7 @@ class Config(object): NR_BROWSER_KEY = getenv("NR_BROWSER_KEY") settings = newrelic.agent.global_settings() NR_MONITOR_ON = settings and settings.monitor_mode - COMMIT_HASH = getenv("COMMIT_HASH", "Unknown") + COMMIT_HASH = getenv("COMMIT_HASH", "-----") TEMPLATE_PREVIEW_API_HOST = getenv( "TEMPLATE_PREVIEW_API_HOST", "http://localhost:9999" diff --git a/app/main/forms.py b/app/main/forms.py index 2e6655cc5..70dbfa37f 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1226,7 +1226,11 @@ class CsvUploadForm(StripWhitespaceForm): validators=[ DataRequired(message="Please pick a file"), CsvFileValidator(), - FileSize(max_size=10e6, message="File must be smaller than 10Mb"), # 10Mb + FileSize( + max_size=10e6, + message="File must be smaller than 10Mb. If you are trying to upload an Excel file, \ + please export the contents in the CSV format and then try again.", + ), # 10Mb ], ) diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 24b3e0490..4d5aca14d 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -76,6 +76,7 @@ def service_dashboard(service_id): "notifications": aggregate_notifications_by_job.get(job["id"], []), } for job in job_response + if aggregate_notifications_by_job.get(job["id"], []) ] return render_template( "views/dashboard/dashboard.html", diff --git a/app/main/views/index.py b/app/main/views/index.py index f4e3a67db..e6107ab10 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -102,15 +102,6 @@ def security(): return render_template("views/security.html", navigation_links=features_nav()) -@main.route("/features/terms", endpoint="terms") -@user_is_logged_in -def terms(): - return render_template( - "views/terms-of-use.html", - navigation_links=features_nav(), - ) - - @main.route("/features/using_notify") @user_is_logged_in def using_notify(): @@ -214,7 +205,6 @@ def send_files_by_email(): @main.route("/roadmap", endpoint="old_roadmap") -@main.route("/terms", endpoint="old_terms") @main.route("/information-security", endpoint="information_security") @main.route("/using_notify", endpoint="old_using_notify") @main.route("/information-risk-management", endpoint="information_risk_management") @@ -222,7 +212,6 @@ def send_files_by_email(): def old_page_redirects(): redirects = { "main.old_roadmap": "main.roadmap", - "main.old_terms": "main.terms", "main.information_security": "main.using_notify", "main.old_using_notify": "main.using_notify", "main.information_risk_management": "main.security", diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index ed8f051a3..774f2a916 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -276,12 +276,16 @@ def get_status_filters(service, message_type, statistics): } else: stats = statistics[message_type] - stats["sending"] = stats["requested"] - stats["delivered"] - stats["failed"] + + if stats.get("failure") is not None: + stats["failed"] = stats["failure"] + + stats["pending"] = stats["requested"] - stats["delivered"] - stats["failed"] filters = [ # key, label, option ("requested", "total", "sending,delivered,failed"), - ("sending", "pending", "pending"), + ("pending", "pending", "pending"), ("delivered", "delivered", "delivered"), ("failed", "failed", "failed"), ] @@ -296,7 +300,7 @@ def get_status_filters(service, message_type, statistics): message_type=message_type, status=option, ), - stats[key], + stats.get(key), ) for key, label, option in filters ] diff --git a/app/main/views/send.py b/app/main/views/send.py index 6c786e3ac..b1cea53a8 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -6,6 +6,7 @@ from zipfile import BadZipFile from flask import abort, flash, redirect, render_template, request, session, url_for from flask_login import current_user +from markupsafe import Markup from notifications_python_client.errors import HTTPError from notifications_utils import SMS_CHAR_COUNT_LIMIT from notifications_utils.insensitive_dict import InsensitiveDict @@ -151,8 +152,11 @@ def send_messages(service_id, template_id): # just show the first error, as we don't expect the form to have more # than one, since it only has one field first_field_errors = list(form.errors.values())[0] - flash(first_field_errors[0]) - + error_message = '' + error_message = f"{error_message}{first_field_errors[0]}" + error_message = f"{error_message}" + error_message = Markup(error_message) + flash(error_message) column_headings = get_spreadsheet_column_headings_from_template(template) return render_template( @@ -504,13 +508,18 @@ def _check_messages(service_id, template_id, upload_id, preview_row): template = get_template( db_template, current_service, - show_recipient=True, + show_recipient=False, email_reply_to=email_reply_to, sms_sender=sms_sender, ) + simplifed_template = get_template( + db_template, + current_service, + show_recipient=False, + ) recipients = RecipientCSV( contents, - template=template, + template=template or simplifed_template, max_initial_rows_shown=50, max_errors_shown=50, guestlist=( @@ -530,11 +539,20 @@ def _check_messages(service_id, template_id, upload_id, preview_row): back_link = url_for( "main.send_one_off", service_id=service_id, template_id=template.id ) + back_link_from_preview = url_for( + "main.send_one_off", service_id=service_id, template_id=template.id + ) choose_time_form = None else: back_link = url_for( "main.send_messages", service_id=service_id, template_id=template.id ) + back_link_from_preview = url_for( + "main.check_messages", + service_id=service_id, + template_id=template.id, + upload_id=upload_id, + ) choose_time_form = ChooseTimeForm() if preview_row < 2: @@ -542,6 +560,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row): if preview_row < len(recipients) + 2: template.values = recipients[preview_row - 2].recipient_and_personalisation + simplifed_template.values = recipients[preview_row - 2].recipient_and_personalisation elif preview_row > 2: abort(404) @@ -562,11 +581,14 @@ def _check_messages(service_id, template_id, upload_id, preview_row): remaining_messages=remaining_messages, choose_time_form=choose_time_form, back_link=back_link, + back_link_from_preview=back_link_from_preview, first_recipient_column=recipients.recipient_column_headers[0], preview_row=preview_row, sent_previously=job_api_client.has_sent_previously( service_id, template.id, db_template["version"], original_file_name ), + template_id=template_id, + simplifed_template=simplifed_template, ) @@ -614,13 +636,34 @@ def check_messages(service_id, template_id, upload_id, row_index=2): return render_template("views/check/ok.html", **data) +@main.route( + "/services///check//preview", + methods=["POST"], +) +@main.route( + "/services///check//preview/row-", + methods=["POST"], +) +@user_has_permissions("send_messages", restrict_admin_usage=True) +def preview_job(service_id, template_id, upload_id, row_index=2): + session["scheduled_for"] = request.form.get("scheduled_for", "") + data = _check_messages(service_id, template_id, upload_id, row_index) + + return render_template( + "views/check/preview.html", + scheduled_for=session["scheduled_for"], + **data, + ) + + @main.route("/services//start-job/", methods=["POST"]) @user_has_permissions("send_messages", restrict_admin_usage=True) def start_job(service_id, upload_id): + scheduled_for = session.pop("scheduled_for", None) job_api_client.create_job( upload_id, service_id, - scheduled_for=request.form.get("scheduled_for", ""), + scheduled_for=scheduled_for, ) session.pop("sender_id", None) @@ -679,7 +722,20 @@ def get_send_test_page_title(template_type, entering_recipient, name=None): return "Personalize this message" -def get_back_link(service_id, template, step_index, placeholders=None): +def get_back_link( + service_id, + template, + step_index, + placeholders=None, + preview=False, +): + if preview: + return url_for( + "main.check_notification", + service_id=service_id, + template_id=template.id, + ) + if step_index == 0: if should_skip_template_page(template._template): return url_for( @@ -779,11 +835,18 @@ def _check_notification(service_id, template_id, exception=None): email_reply_to=email_reply_to, sms_sender=sms_sender, ) - + simplifed_template = get_template( + db_template, + current_service, + ) placeholders = fields_to_fill_in(template) back_link = get_back_link(service_id, template, len(placeholders), placeholders) + back_link_from_preview = get_back_link( + service_id, template, len(placeholders), placeholders, preview=True + ) + choose_time_form = ChooseTimeForm() if (not session.get("recipient")) or not all_placeholders_in_session( @@ -797,8 +860,10 @@ def _check_notification(service_id, template_id, exception=None): return dict( template=template, back_link=back_link, + back_link_from_preview=back_link_from_preview, choose_time_form=choose_time_form, **(get_template_error_dict(exception) if exception else {}), + simplifed_template=simplifed_template ) @@ -828,12 +893,39 @@ def get_template_error_dict(exception): } +@main.route( + "/services//template//notification/check/preview", + methods=["POST"], +) +@user_has_permissions("send_messages", restrict_admin_usage=True) +def preview_notification(service_id, template_id): + recipient = get_recipient() + if not recipient: + return redirect( + url_for( + ".send_one_off", + service_id=service_id, + template_id=template_id, + ) + ) + + session["scheduled_for"] = request.form.get("scheduled_for", "") + + return render_template( + "views/notifications/preview.html", + **_check_notification(service_id, template_id), + scheduled_for=session["scheduled_for"], + recipient=recipient, + ) + + @main.route( "/services//template//notification/check", methods=["POST"], ) @user_has_permissions("send_messages", restrict_admin_usage=True) def send_notification(service_id, template_id): + scheduled_for = session.pop("scheduled_for", "") recipient = get_recipient() if not recipient: return redirect( @@ -868,7 +960,7 @@ def send_notification(service_id, template_id): job_api_client.create_job( upload_id, service_id, - scheduled_for=request.form.get("scheduled_for", ""), + scheduled_for=scheduled_for, template_id=template_id, original_file_name=filename, notification_count=1, diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index be313c59b..d39cb89af 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -53,22 +53,19 @@ def _get_access_token(code, state): # JWT expiration time (10 minute maximum) "exp": int(time.time()) + (10 * 60), } - current_app.logger.warning(f"Here is the raw payload {payload}") token = jwt.encode(payload, keystring, algorithm="RS256") base_url = f"{access_token_url}?" cli_assert = f"client_assertion={token}" cli_assert_type = "client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer" code_param = f"code={code}" url = f"{base_url}{cli_assert}&{cli_assert_type}&{code_param}&grant_type=authorization_code" - current_app.logger.info(f"This is the url we use to get the access token: {url}") headers = {"Authorization": "Bearer %s" % token} response = requests.post(url, headers=headers) - current_app.logger.info(f"GOT A RESPONSE {response.json()}") access_token = response.json()["access_token"] return access_token -def _get_user_email(access_token): +def _get_user_email_and_uuid(access_token): headers = {"Authorization": "Bearer %s" % access_token} user_info_url = os.getenv("LOGIN_DOT_GOV_USER_INFO_URL") user_attributes = requests.get( @@ -76,7 +73,8 @@ def _get_user_email(access_token): headers=headers, ) user_email = user_attributes.json()["email"] - return user_email + user_uuid = user_attributes.json()["sub"] + return user_email, user_uuid @main.route("/sign-in", methods=(["GET", "POST"])) @@ -88,11 +86,11 @@ def sign_in(): login_gov_error = request.args.get("error") if code and state: access_token = _get_access_token(code, state) - user_email = _get_user_email(access_token) + user_email, user_uuid = _get_user_email_and_uuid(access_token) redirect_url = request.args.get("next") # activate the user - user = user_api_client.get_user_by_email(user_email) + user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) activate_user(user["id"]) return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url)) @@ -198,7 +196,7 @@ def sign_in(): form=form, again=bool(redirect_url), other_device=other_device, - login_gov_enabled=bool(notify_env in ["development", "staging"]), + login_gov_enabled=bool(notify_env in ["development", "staging", "demo"]), password_reset_url=password_reset_url, initial_signin_url=initial_signin_url, ) diff --git a/app/main/views/sub_navigation_dictionaries.py b/app/main/views/sub_navigation_dictionaries.py index f76d69c14..5e32bc003 100644 --- a/app/main/views/sub_navigation_dictionaries.py +++ b/app/main/views/sub_navigation_dictionaries.py @@ -18,10 +18,6 @@ def features_nav(): "name": "Security", "link": "main.security", }, - { - "name": "Terms of use", - "link": "main.terms", - }, ] diff --git a/app/navigation.py b/app/navigation.py index 94f970540..3c79598cc 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -45,7 +45,6 @@ class HeaderNavigation(Navigation): "features_sms", "roadmap", "security", - "terms", }, "using_notify": { "get_started", diff --git a/app/notify_client/user_api_client.py b/app/notify_client/user_api_client.py index bfe2f7182..a17059e52 100644 --- a/app/notify_client/user_api_client.py +++ b/app/notify_client/user_api_client.py @@ -44,6 +44,16 @@ class UserApiClient(NotifyAdminAPIClient): user_data = self.post("/user/email", data={"email": email_address}) return user_data["data"] + def get_user_by_uuid_or_email(self, user_uuid, email_address): + + user_data = self.post( + "/user/get-login-gov-user", + data={"login_uuid": user_uuid, "email": email_address}, + ) + if user_data is None: + raise Exception("User not found") + return user_data["data"] + def get_user_by_email_or_none(self, email_address): try: return self.get_user_by_email(email_address) diff --git a/app/templates/admin_template.html b/app/templates/admin_template.html index df70151ce..1c9fe195f 100644 --- a/app/templates/admin_template.html +++ b/app/templates/admin_template.html @@ -203,10 +203,6 @@ "href": url_for("main.security"), "text": "Security" }, - { - "href": url_for("main.terms"), - "text": "Terms of use" - }, ] }, { diff --git a/app/templates/components/components/header/template.njk b/app/templates/components/components/header/template.njk index 6cc8cabd8..a4cd0d9e2 100644 --- a/app/templates/components/components/header/template.njk +++ b/app/templates/components/components/header/template.njk @@ -44,61 +44,63 @@
-
- - {% if current_user.is_authenticated %} - - {% endif %} -
- + +
diff --git a/app/templates/components/table.html b/app/templates/components/table.html index 50eb73d9a..a76f2c6bd 100644 --- a/app/templates/components/table.html +++ b/app/templates/components/table.html @@ -171,8 +171,8 @@ {% endif %}

{{ notification.status|format_notification_status_as_time( - notification.created_at|format_datetime_short, - (notification.sent_at or notification.created_at)|format_datetime_short + notification.created_at|format_datetime_short_america, + (notification.sent_at or notification.created_at)|format_datetime_short_america ) }}

{% if displayed_on_single_line %}{% endif %} diff --git a/app/templates/content_template.html b/app/templates/content_template.html index abca0be7e..34b488bb5 100644 --- a/app/templates/content_template.html +++ b/app/templates/content_template.html @@ -11,10 +11,10 @@
{% if navigation_links %} -
+
{{ sub_navigation(navigation_links) }}
-
+
{% else %}
{% endif %} diff --git a/app/templates/main_nav.html b/app/templates/main_nav.html index 65c875d7a..2f7306f09 100644 --- a/app/templates/main_nav.html +++ b/app/templates/main_nav.html @@ -1,7 +1,7 @@ {% if help %} {% include 'partials/tour.html' %} {% else %} -