mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-04 13:38:25 -04:00
335 lines
15 KiB
HTML
335 lines
15 KiB
HTML
{% from "components/page-header.html" import page_header %}
|
|
{% extends "withnav_template.html" %}
|
|
|
|
{% block org_page_title %}
|
|
Organization Dashboard
|
|
{% endblock %}
|
|
|
|
{% block maincolumn_content %}
|
|
|
|
{{ page_header('Organization Dashboard', size='large') }}
|
|
|
|
<div class="margin-bottom-3">
|
|
<div class="grid-row flex-align-center">
|
|
<h2 id="chartTitle" class="margin-right-1 margin-y-0">Overall {{ selected_year }} Messages Sent</h2>
|
|
<button
|
|
type="button"
|
|
class="usa-tooltip usa-tooltip__information margin-right-0"
|
|
data-position="top"
|
|
title="Total messages sent across all services in {{ current_org.name }}"
|
|
>
|
|
<span class="usa-sr-only">More information</span>
|
|
<img src="{{ asset_url('img/usa-icons/info.svg') }}" alt="" class="usa-icon" role="presentation" />
|
|
</button>
|
|
</div>
|
|
<div class="font-sans-xl text-primary-darker margin-top-1">{{ "{:,}".format(messages_sent|default(0)) }} sent</div>
|
|
</div>
|
|
<div class="grid-row margin-bottom-3 maxw-tablet">
|
|
<div class="grid-col-12 tablet:grid-col-6 margin-bottom-2 tablet:margin-bottom-0 tablet:padding-right-1">
|
|
<div class="usa-summary-box height-full" role="region">
|
|
<div class="usa-summary-box__body">
|
|
<div class="usa-summary-box__text">
|
|
<div class="display-flex flex-align-end">
|
|
<div class="flex-1">
|
|
<div class="text-base-dark text-uppercase font-sans-3xs text-ls-1 margin-bottom-05">Total Services</div>
|
|
<div class="font-sans-xl text-primary-darker line-height-sans-1">{{ total_services }}</div>
|
|
</div>
|
|
<div class="text-ink font-body-2xs line-height-sans-3">
|
|
<span class="text-bold">{{ live_services }}</span> Live
|
|
<span class="margin-left-1 text-bold">{{ trial_services }}</span> Trial
|
|
<span class="margin-left-1 text-bold">{{ suspended_services }}</span> Archived
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid-col-12 tablet:grid-col-6 tablet:padding-left-1">
|
|
<div class="usa-summary-box height-full" role="region">
|
|
<div class="usa-summary-box__body">
|
|
<div class="usa-summary-box__text">
|
|
<div class="text-base-dark text-uppercase font-sans-3xs text-ls-1 margin-bottom-05">Agreement Period</div>
|
|
<div class="font-sans-xl text-primary-darker">Jan 1 - Dec 31</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="display-flex flex-gap-1 margin-bottom-3">
|
|
<a {% if not create_service_form %}href="{{ url_for('.organization_dashboard', org_id=current_org.id, action='create-service') }}"{% endif %}
|
|
class="usa-button {% if create_service_form %}usa-button--base button-not-clickable{% else %}usa-button--outline{% endif %}">
|
|
Create new service
|
|
</a>
|
|
<a {% if not invite_user_form %}href="{{ url_for('.organization_dashboard', org_id=current_org.id, action='invite-user') }}"{% endif %}
|
|
class="usa-button {% if invite_user_form %}usa-button--base button-not-clickable{% else %}usa-button--outline{% endif %}">
|
|
Add org admin
|
|
</a>
|
|
</div>
|
|
|
|
{% if create_service_form %}
|
|
<div id="create-service-form" class="padding-3 radius-md margin-bottom-3 bg-gray-5">
|
|
<h3 class="margin-top-0">Create a new service</h3>
|
|
<form method="post" action="{{ url_for('.organization_dashboard', org_id=current_org.id, action='create-service') }}">
|
|
<input type="hidden" name="csrf_token" value="{{ create_service_form.csrf_token._value() }}"/>
|
|
|
|
{{ create_service_form.name(param_extensions={"hint": {"text": "You can change this later"}}) }}
|
|
|
|
<div class="display-flex flex-gap-1 margin-top-3">
|
|
<button type="submit" class="usa-button">Create service</button>
|
|
<a href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}" class="usa-button usa-button--outline">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if invite_user_form %}
|
|
<div id="invite-user-form" class="bg-base-lightest padding-3 radius-md margin-bottom-3">
|
|
<h3 class="margin-top-0">Invite a team member</h3>
|
|
<p class="margin-top-0">{{ current_org.name }} team members can see usage and team members for each service, and invite other team members.</p>
|
|
<form method="post" action="{{ url_for('.organization_dashboard', org_id=current_org.id, action='invite-user') }}">
|
|
<input type="hidden" name="csrf_token" value="{{ invite_user_form.csrf_token._value() }}"/>
|
|
|
|
{{ invite_user_form.email_address(param_extensions={"classes": ""}, error_message_with_html=True) }}
|
|
|
|
<div class="display-flex flex-gap-1 margin-top-3">
|
|
<button type="submit" class="usa-button">Send invitation</button>
|
|
<a href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}" class="usa-button usa-button--outline">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if edit_service_data %}
|
|
<div class="bg-base-lightest padding-3 radius-md margin-bottom-3">
|
|
<h3 class="margin-top-0">Manage Service</h3>
|
|
<form id="edit-service-form" method="post" action="{{ url_for('.organization_dashboard', org_id=current_org.id, action='edit-service', service_id=edit_service_data.id) }}">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
|
|
<div class="usa-form-group">
|
|
<label class="usa-label" for="service_name">Service Name</label>
|
|
<input class="usa-input" type="text" id="service_name" name="service_name"
|
|
value="{{ edit_service_data.name }}" required>
|
|
</div>
|
|
|
|
<div class="usa-form-group">
|
|
<label class="usa-label" for="primary_contact">Primary Contact Email</label>
|
|
<input class="usa-input" type="email" id="primary_contact" name="primary_contact"
|
|
value="{{ edit_service_data.primary_contact|default('') }}" placeholder="email@example.com">
|
|
</div>
|
|
|
|
<fieldset class="usa-fieldset margin-top-2">
|
|
<legend class="usa-legend">Service Status</legend>
|
|
<div class="usa-radio">
|
|
<input class="usa-radio__input" id="statusTrial" type="radio" name="status" value="trial"
|
|
{% if edit_service_data.status == 'trial' %}checked{% endif %}>
|
|
<label class="usa-radio__label" for="statusTrial">Trial</label>
|
|
</div>
|
|
<div class="usa-radio">
|
|
<input class="usa-radio__input" id="statusLive" type="radio" name="status" value="live"
|
|
{% if edit_service_data.status == 'live' %}checked{% endif %}>
|
|
<label class="usa-radio__label" for="statusLive">Live</label>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<div class="display-flex flex-gap-1 margin-top-3">
|
|
<button type="button" class="usa-button" data-open-modal="confirmEditModal">Save Changes</button>
|
|
<a href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}" class="usa-button usa-button--outline">Cancel</a>
|
|
{% if edit_service_data.status == 'trial' or current_user.platform_admin %}
|
|
<button type="button" class="usa-button usa-button--secondary margin-left-auto" data-open-modal="confirmDeleteModal" data-service-id="{{ edit_service_data.id }}" data-service-name="{{ edit_service_data.name }}">Delete Service</button>
|
|
{% endif %}
|
|
</div>
|
|
</form>
|
|
<div class="border-top-1px border-base-lighter margin-top-3 padding-top-3">
|
|
<a href="{{ url_for('main.invite_user', service_id=edit_service_data.id) }}" class="usa-button usa-button--outline">Invite team member</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="usa-modal"
|
|
data-module="usa-modal"
|
|
id="confirmEditModal"
|
|
aria-hidden="true"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="confirmEditModalHeading"
|
|
aria-describedby="confirmEditModalDesc"
|
|
>
|
|
<div class="usa-modal__content">
|
|
<div class="usa-modal__main">
|
|
<h2 class="usa-modal__heading font-body-lg" id="confirmEditModalHeading">Are you sure you want to save these changes?</h2>
|
|
<p id="confirmEditModalDesc">This will update the service name, primary contact, and/or status. If you're changing the status to Live, team members will be notified.</p>
|
|
<div class="usa-modal__footer">
|
|
<ul class="usa-button-group">
|
|
<li class="usa-button-group__item">
|
|
<button type="button" id="edit-service-confirm-btn" class="usa-button">Confirm changes</button>
|
|
</li>
|
|
<li class="usa-button-group__item">
|
|
<button class="usa-button usa-button--unstyled padding-105 text-center" data-close-modal type="button">
|
|
No, go back
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<button class="usa-button usa-modal__close" aria-label="Close this window" data-close-modal type="button">
|
|
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
|
|
<use xlink:href="{{ asset_url('img/sprite.svg') }}#close"></use>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<form id="delete-service-form" method="post" class="display-none">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
<input type="hidden" name="confirm_delete" value="delete"/>
|
|
</form>
|
|
|
|
<div
|
|
class="usa-modal"
|
|
data-module="usa-modal"
|
|
id="confirmDeleteModal"
|
|
aria-hidden="true"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="confirmDeleteModalHeading"
|
|
aria-describedby="confirmDeleteModalDesc"
|
|
>
|
|
<div class="usa-modal__content">
|
|
<div class="usa-modal__main">
|
|
<h2 class="usa-modal__heading font-body-lg text-secondary-dark" id="confirmDeleteModalHeading">
|
|
Are you absolutely sure?
|
|
</h2>
|
|
<p id="confirmDeleteModalDesc">
|
|
This will permanently delete '<strong id="delete-service-name-display"></strong>' and all associated data.
|
|
This action <strong>cannot be undone</strong>.
|
|
</p>
|
|
<div class="usa-modal__footer">
|
|
<ul class="usa-button-group">
|
|
<li class="usa-button-group__item">
|
|
<button type="button" id="delete-service-confirm-btn" class="usa-button usa-button--secondary">Yes, permanently delete</button>
|
|
</li>
|
|
<li class="usa-button-group__item">
|
|
<button class="usa-button usa-button--unstyled padding-105 text-center" data-close-modal type="button">
|
|
No, go back
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<button class="usa-button usa-modal__close" aria-label="Close this window" data-close-modal type="button">
|
|
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
|
|
<use xlink:href="{{ asset_url('img/sprite.svg') }}#close"></use>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="usa-accordion margin-bottom-3">
|
|
<h3 class="usa-accordion__heading">
|
|
<button
|
|
type="button"
|
|
class="usa-accordion__button"
|
|
aria-expanded="false"
|
|
aria-controls="what-is-service-content"
|
|
>
|
|
What is a service?
|
|
</button>
|
|
</h3>
|
|
<div id="what-is-service-content" class="usa-accordion__content usa-prose" hidden>
|
|
<p>
|
|
Services are your organization's workspaces for sending text messages and emails. If you have multiple teams using Notify for different purposes, it is helpful to set up a separate Service for each team, with its own managers and templates. There is no limit to the number of Services you can create, and messages sent by all of your Services contribute to your overall messaging usage. Within each Service, you can:
|
|
</p>
|
|
<ol class="usa-list">
|
|
<li>Create and edit message templates</li>
|
|
<li>Send messages to recipients</li>
|
|
<li>View message status and history</li>
|
|
<li>Manage team members and permissions</li>
|
|
<li>Track usage and delivery statistics</li>
|
|
<li>Service members can be added to multiple services and can switch between them</li>
|
|
<li>Organizational administrators can always see all Services</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="margin-bottom-5">
|
|
<h2 class="font-heading-lg margin-bottom-2">Services Overview</h2>
|
|
<div class="table-overflow-x-auto">
|
|
<table class="usa-table service-dashboard-table">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" role="columnheader">Name</th>
|
|
<th scope="col" role="columnheader">Status</th>
|
|
<th scope="col" role="columnheader">Usage</th>
|
|
<th scope="col" role="columnheader">Primary Contact</th>
|
|
<th scope="col" role="columnheader">Last Used</th>
|
|
<th scope="col" role="columnheader">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% if services %}
|
|
{% for service in services %}
|
|
{% set is_new_service = new_service_id and service.id == new_service_id %}
|
|
{% set is_updated_service = updated_service_id and service.id == updated_service_id %}
|
|
<tr id="service-{{ service.id }}" {% if is_new_service or is_updated_service %}class="is-highlighted"{% endif %}>
|
|
<td><a href="{{ url_for('main.service_dashboard', service_id=service.id) }}" class="usa-link">{{ service.name }}</a></td>
|
|
<td>
|
|
{% if not service.active %}
|
|
Archived
|
|
{% elif service.restricted %}
|
|
Trial
|
|
{% else %}
|
|
Live
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ service.usage }}</td>
|
|
<td>{{ service.primary_contact }}</td>
|
|
<td>{{ service.recent_template }}</td>
|
|
<td>
|
|
{% if service.active %}
|
|
{% set is_managing = edit_service_data and edit_service_data.id == service.id %}
|
|
|
|
{% if is_managing %}
|
|
<span class="text-base">Manage</span>
|
|
{% else %}
|
|
<a href="{{ url_for('.organization_dashboard', org_id=current_org.id, action='edit-service', service_id=service.id) }}" class="usa-link">
|
|
Manage
|
|
</a>
|
|
{% endif %}
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="6" class="table-empty-message">No services found within this organization</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block extra_javascripts %}
|
|
<script nonce="{{ csp_nonce() }}">
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
{% if new_service_id %}
|
|
if (window.OrganizationDashboard) {
|
|
window.OrganizationDashboard.highlightAndScrollToService('{{ new_service_id }}');
|
|
}
|
|
{% endif %}
|
|
|
|
{% if updated_service_id %}
|
|
if (window.OrganizationDashboard) {
|
|
window.OrganizationDashboard.highlightAndScrollToService('{{ updated_service_id }}');
|
|
}
|
|
{% endif %}
|
|
});
|
|
</script>
|
|
{{ super() }}
|
|
{% endblock %}
|