mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-23 03:06:01 +02:00
Merge branch 'main' into dk/2379-portfolio-domain-readonly-permissions
This commit is contained in:
commit
9a6f5fc408
26 changed files with 291 additions and 78 deletions
|
@ -29,6 +29,7 @@ on:
|
|||
- hotgov
|
||||
- litterbox
|
||||
- ms
|
||||
- ad
|
||||
# GitHub Actions has no "good" way yet to dynamically input branches
|
||||
branch:
|
||||
description: 'Branch to deploy'
|
||||
|
|
1
.github/workflows/deploy-sandbox.yaml
vendored
1
.github/workflows/deploy-sandbox.yaml
vendored
|
@ -29,6 +29,7 @@ jobs:
|
|||
|| startsWith(github.head_ref, 'litterbox/')
|
||||
|| startsWith(github.head_ref, 'ag/')
|
||||
|| startsWith(github.head_ref, 'ms/')
|
||||
|| startsWith(github.head_ref, 'ad/')
|
||||
outputs:
|
||||
environment: ${{ steps.var.outputs.environment}}
|
||||
runs-on: "ubuntu-latest"
|
||||
|
|
1
.github/workflows/migrate.yaml
vendored
1
.github/workflows/migrate.yaml
vendored
|
@ -16,6 +16,7 @@ on:
|
|||
- stable
|
||||
- staging
|
||||
- development
|
||||
- ad
|
||||
- ms
|
||||
- ag
|
||||
- litterbox
|
||||
|
|
1
.github/workflows/reset-db.yaml
vendored
1
.github/workflows/reset-db.yaml
vendored
|
@ -16,6 +16,7 @@ on:
|
|||
options:
|
||||
- staging
|
||||
- development
|
||||
- ad
|
||||
- ms
|
||||
- ag
|
||||
- litterbox
|
||||
|
|
32
ops/manifests/manifest-ad.yaml
Normal file
32
ops/manifests/manifest-ad.yaml
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
applications:
|
||||
- name: getgov-ad
|
||||
buildpacks:
|
||||
- python_buildpack
|
||||
path: ../../src
|
||||
instances: 1
|
||||
memory: 512M
|
||||
stack: cflinuxfs4
|
||||
timeout: 180
|
||||
command: ./run.sh
|
||||
health-check-type: http
|
||||
health-check-http-endpoint: /health
|
||||
health-check-invocation-timeout: 40
|
||||
env:
|
||||
# Send stdout and stderr straight to the terminal without buffering
|
||||
PYTHONUNBUFFERED: yup
|
||||
# Tell Django where to find its configuration
|
||||
DJANGO_SETTINGS_MODULE: registrar.config.settings
|
||||
# Tell Django where it is being hosted
|
||||
DJANGO_BASE_URL: https://getgov-ad.app.cloud.gov
|
||||
# Tell Django how much stuff to log
|
||||
DJANGO_LOG_LEVEL: INFO
|
||||
# default public site location
|
||||
GETGOV_PUBLIC_SITE_URL: https://get.gov
|
||||
# Flag to disable/enable features in prod environments
|
||||
IS_PRODUCTION: False
|
||||
routes:
|
||||
- route: getgov-ad.app.cloud.gov
|
||||
services:
|
||||
- getgov-credentials
|
||||
- getgov-ad-database
|
9
src/package-lock.json
generated
9
src/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@uswds/uswds": "^3.8.0",
|
||||
"@uswds/uswds": "^3.8.1",
|
||||
"pa11y-ci": "^3.0.1",
|
||||
"sass": "^1.54.8"
|
||||
},
|
||||
|
@ -187,9 +187,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@uswds/uswds": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@uswds/uswds/-/uswds-3.8.0.tgz",
|
||||
"integrity": "sha512-rMwCXe/u4HGkfskvS1Iuabapi/EXku3ChaIFW7y/dUhc7R1TXQhbbfp8YXEjmXPF0yqJnv9T08WPgS0fQqWZ8w==",
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@uswds/uswds/-/uswds-3.8.1.tgz",
|
||||
"integrity": "sha512-bKG/B9mJF1v0yoqth48wQDzST5Xyu3OxxpePIPDyhKWS84oDrCehnu3Z88JhSjdIAJMl8dtjtH8YvdO9kZUpAg==",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"dependencies": {
|
||||
"classlist-polyfill": "1.2.0",
|
||||
"object-assign": "4.1.1",
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@uswds/uswds": "^3.8.0",
|
||||
"@uswds/uswds": "^3.8.1",
|
||||
"pa11y-ci": "^3.0.1",
|
||||
"sass": "^1.54.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@uswds/compile": "^1.0.0-beta.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,15 +207,11 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
|
||||
|
||||
})();
|
||||
|
||||
/** An IIFE for pages in DjangoAdmin that use a clipboard button
|
||||
*/
|
||||
(function (){
|
||||
|
||||
function copyInnerTextToClipboard(elem) {
|
||||
let text = elem.innerText
|
||||
navigator.clipboard.writeText(text)
|
||||
}
|
||||
|
||||
function copyToClipboardAndChangeIcon(button) {
|
||||
// Assuming the input is the previous sibling of the button
|
||||
let input = button.previousElementSibling;
|
||||
|
@ -224,7 +220,7 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
if (input) {
|
||||
navigator.clipboard.writeText(input.value).then(function() {
|
||||
// Change the icon to a checkmark on successful copy
|
||||
let buttonIcon = button.querySelector('.usa-button__clipboard use');
|
||||
let buttonIcon = button.querySelector('.copy-to-clipboard use');
|
||||
if (buttonIcon) {
|
||||
let currentHref = buttonIcon.getAttribute('xlink:href');
|
||||
let baseHref = currentHref.split('#')[0];
|
||||
|
@ -233,21 +229,17 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
buttonIcon.setAttribute('xlink:href', baseHref + '#check');
|
||||
|
||||
// Change the button text
|
||||
nearestSpan = button.querySelector("span")
|
||||
let nearestSpan = button.querySelector("span")
|
||||
let original_text = nearestSpan.innerText
|
||||
nearestSpan.innerText = "Copied to clipboard"
|
||||
|
||||
setTimeout(function() {
|
||||
// Change back to the copy icon
|
||||
buttonIcon.setAttribute('xlink:href', currentHref);
|
||||
if (button.classList.contains('usa-button__small-text')) {
|
||||
nearestSpan.innerText = "Copy email";
|
||||
} else {
|
||||
nearestSpan.innerText = "Copy";
|
||||
}
|
||||
nearestSpan.innerText = original_text;
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
|
||||
}).catch(function(error) {
|
||||
console.error('Clipboard copy failed', error);
|
||||
});
|
||||
|
@ -255,7 +247,7 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
}
|
||||
|
||||
function handleClipboardButtons() {
|
||||
clipboardButtons = document.querySelectorAll(".usa-button__clipboard")
|
||||
clipboardButtons = document.querySelectorAll(".copy-to-clipboard")
|
||||
clipboardButtons.forEach((button) => {
|
||||
|
||||
// Handle copying the text to your clipboard,
|
||||
|
@ -278,20 +270,7 @@ function addOrRemoveSessionBoolean(name, add){
|
|||
});
|
||||
}
|
||||
|
||||
function handleClipboardLinks() {
|
||||
let emailButtons = document.querySelectorAll(".usa-button__clipboard-link");
|
||||
if (emailButtons){
|
||||
emailButtons.forEach((button) => {
|
||||
button.addEventListener("click", ()=>{
|
||||
copyInnerTextToClipboard(button);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleClipboardButtons();
|
||||
handleClipboardLinks();
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
@ -605,3 +584,169 @@ function initializeWidgetOnList(list, parentId) {
|
|||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
/** An IIFE for copy summary button (appears in DomainRegistry models)
|
||||
*/
|
||||
(function (){
|
||||
const copyButton = document.getElementById('id-copy-to-clipboard-summary');
|
||||
|
||||
if (copyButton) {
|
||||
copyButton.addEventListener('click', function() {
|
||||
/// Generate a rich HTML summary text and copy to clipboard
|
||||
|
||||
//------ Organization Type
|
||||
const organizationTypeElement = document.getElementById('id_organization_type');
|
||||
const organizationType = organizationTypeElement.options[organizationTypeElement.selectedIndex].text;
|
||||
|
||||
//------ Alternative Domains
|
||||
const alternativeDomainsDiv = document.querySelector('.form-row.field-alternative_domains .readonly');
|
||||
const alternativeDomainslinks = alternativeDomainsDiv.querySelectorAll('a');
|
||||
const alternativeDomains = Array.from(alternativeDomainslinks).map(link => link.textContent);
|
||||
|
||||
//------ Existing Websites
|
||||
const existingWebsitesDiv = document.querySelector('.form-row.field-current_websites .readonly');
|
||||
const existingWebsiteslinks = existingWebsitesDiv.querySelectorAll('a');
|
||||
const existingWebsites = Array.from(existingWebsiteslinks).map(link => link.textContent);
|
||||
|
||||
//------ Additional Contacts
|
||||
// 1 - Create a hyperlinks map so we can display contact details and also link to the contact
|
||||
const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly');
|
||||
let otherContactLinks = [];
|
||||
const nameToUrlMap = {};
|
||||
if (otherContactsDiv) {
|
||||
otherContactLinks = otherContactsDiv.querySelectorAll('a');
|
||||
otherContactLinks.forEach(link => {
|
||||
const name = link.textContent.trim();
|
||||
const url = link.href;
|
||||
nameToUrlMap[name] = url;
|
||||
});
|
||||
}
|
||||
|
||||
// 2 - Iterate through contact details and assemble html for summary
|
||||
let otherContactsSummary = ""
|
||||
const bulletList = document.createElement('ul');
|
||||
|
||||
// CASE 1 - Contacts are not in a table (this happens if there is only one or two other contacts)
|
||||
const contacts = document.querySelectorAll('.field-other_contacts .dja-detail-list dd');
|
||||
if (contacts) {
|
||||
contacts.forEach(contact => {
|
||||
// Check if the <dl> element is not empty
|
||||
const name = contact.querySelector('a#contact_info_name')?.innerText;
|
||||
const title = contact.querySelector('span#contact_info_title')?.innerText;
|
||||
const email = contact.querySelector('span#contact_info_email')?.innerText;
|
||||
const phone = contact.querySelector('span#contact_info_phone')?.innerText;
|
||||
const url = nameToUrlMap[name] || '#';
|
||||
// Format the contact information
|
||||
const listItem = document.createElement('li');
|
||||
listItem.innerHTML = `<a href="${url}">${name}</a>, ${title}, ${email}, ${phone}`;
|
||||
bulletList.appendChild(listItem);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// CASE 2 - Contacts are in a table (this happens if there is more than 2 contacts)
|
||||
const otherContactsTable = document.querySelector('.form-row.field-other_contacts table tbody');
|
||||
if (otherContactsTable) {
|
||||
const otherContactsRows = otherContactsTable.querySelectorAll('tr');
|
||||
otherContactsRows.forEach(contactRow => {
|
||||
// Extract the contact details
|
||||
const name = contactRow.querySelector('th').textContent.trim();
|
||||
const title = contactRow.querySelectorAll('td')[0].textContent.trim();
|
||||
const email = contactRow.querySelectorAll('td')[1].textContent.trim();
|
||||
const phone = contactRow.querySelectorAll('td')[2].textContent.trim();
|
||||
const url = nameToUrlMap[name] || '#';
|
||||
// Format the contact information
|
||||
const listItem = document.createElement('li');
|
||||
listItem.innerHTML = `<a href="${url}">${name}</a>, ${title}, ${email}, ${phone}`;
|
||||
bulletList.appendChild(listItem);
|
||||
});
|
||||
}
|
||||
otherContactsSummary += bulletList.outerHTML
|
||||
|
||||
|
||||
//------ Requested Domains
|
||||
const requestedDomainElement = document.getElementById('id_requested_domain');
|
||||
const requestedDomain = requestedDomainElement.options[requestedDomainElement.selectedIndex].text;
|
||||
|
||||
//------ Submitter
|
||||
// Function to extract text by ID and handle missing elements
|
||||
function extractTextById(id, divElement) {
|
||||
if (divElement) {
|
||||
const element = divElement.querySelector(`#${id}`);
|
||||
return element ? ", " + element.textContent.trim() : '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// Extract the submitter name, title, email, and phone number
|
||||
const submitterDiv = document.querySelector('.form-row.field-submitter');
|
||||
const submitterNameElement = document.getElementById('id_submitter');
|
||||
const submitterName = submitterNameElement.options[submitterNameElement.selectedIndex].text;
|
||||
const submitterTitle = extractTextById('contact_info_title', submitterDiv);
|
||||
const submitterEmail = extractTextById('contact_info_email', submitterDiv);
|
||||
const submitterPhone = extractTextById('contact_info_phone', submitterDiv);
|
||||
let submitterInfo = `${submitterName}${submitterTitle}${submitterEmail}${submitterPhone}`;
|
||||
|
||||
|
||||
//------ Senior Official
|
||||
const seniorOfficialDiv = document.querySelector('.form-row.field-senior_official');
|
||||
const seniorOfficialElement = document.getElementById('id_senior_official');
|
||||
const seniorOfficialName = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text;
|
||||
const seniorOfficialTitle = extractTextById('contact_info_title', seniorOfficialDiv);
|
||||
const seniorOfficialEmail = extractTextById('contact_info_email', seniorOfficialDiv);
|
||||
const seniorOfficialPhone = extractTextById('contact_info_phone', seniorOfficialDiv);
|
||||
let seniorOfficialInfo = `${seniorOfficialName}${seniorOfficialTitle}${seniorOfficialEmail}${seniorOfficialPhone}`;
|
||||
|
||||
const html_summary = `<strong>Recommendation:</strong></br>` +
|
||||
`<strong>Organization Type:</strong> ${organizationType}</br>` +
|
||||
`<strong>Requested Domain:</strong> ${requestedDomain}</br>` +
|
||||
`<strong>Current Websites:</strong> ${existingWebsites.join(', ')}</br>` +
|
||||
`<strong>Rationale:</strong></br>` +
|
||||
`<strong>Alternative Domains:</strong> ${alternativeDomains.join(', ')}</br>` +
|
||||
`<strong>Submitter:</strong> ${submitterInfo}</br>` +
|
||||
`<strong>Senior Official:</strong> ${seniorOfficialInfo}</br>` +
|
||||
`<strong>Other Employees:</strong> ${otherContactsSummary}</br>`;
|
||||
|
||||
//Replace </br> with \n, then strip out all remaining html tags (replace <...> with '')
|
||||
const plain_summary = html_summary.replace(/<\/br>|<br>/g, '\n').replace(/<\/?[^>]+(>|$)/g, '');
|
||||
|
||||
// Create Blobs with the summary content
|
||||
const html_blob = new Blob([html_summary], { type: 'text/html' });
|
||||
const plain_blob = new Blob([plain_summary], { type: 'text/plain' });
|
||||
|
||||
// Create a ClipboardItem with the Blobs
|
||||
const clipboardItem = new ClipboardItem({
|
||||
'text/html': html_blob,
|
||||
'text/plain': plain_blob
|
||||
});
|
||||
|
||||
// Write the ClipboardItem to the clipboard
|
||||
navigator.clipboard.write([clipboardItem]).then(() => {
|
||||
// Change the icon to a checkmark on successful copy
|
||||
let buttonIcon = copyButton.querySelector('use');
|
||||
if (buttonIcon) {
|
||||
let currentHref = buttonIcon.getAttribute('xlink:href');
|
||||
let baseHref = currentHref.split('#')[0];
|
||||
|
||||
// Append the new icon reference
|
||||
buttonIcon.setAttribute('xlink:href', baseHref + '#check');
|
||||
|
||||
// Change the button text
|
||||
nearestSpan = copyButton.querySelector("span")
|
||||
original_text = nearestSpan.innerText
|
||||
nearestSpan.innerText = "Copied to clipboard"
|
||||
|
||||
setTimeout(function() {
|
||||
// Change back to the copy icon
|
||||
buttonIcon.setAttribute('xlink:href', currentHref);
|
||||
nearestSpan.innerText = original_text
|
||||
}, 2000);
|
||||
|
||||
}
|
||||
console.log('Summary copied to clipboard successfully!');
|
||||
}).catch(err => {
|
||||
console.error('Failed to copy text: ', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -369,9 +369,6 @@ input.admin-confirm-button {
|
|||
padding: 10px 8px;
|
||||
line-height: normal;
|
||||
}
|
||||
.usa-icon {
|
||||
top: 2px;
|
||||
}
|
||||
a.button:active, a.button:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -447,15 +444,12 @@ address.margin-top-neg-1__detail-list {
|
|||
}
|
||||
}
|
||||
|
||||
td button.usa-button__clipboard-link, address.dja-address-contact-list {
|
||||
address.dja-address-contact-list {
|
||||
font-size: unset;
|
||||
}
|
||||
|
||||
address.dja-address-contact-list {
|
||||
color: var(--body-quiet-color);
|
||||
button.usa-button__clipboard-link {
|
||||
font-size: unset;
|
||||
}
|
||||
}
|
||||
|
||||
// Mimic the normal label size
|
||||
|
@ -464,11 +458,18 @@ address.dja-address-contact-list {
|
|||
font-size: 0.875rem;
|
||||
color: var(--body-quiet-color);
|
||||
}
|
||||
}
|
||||
|
||||
address button.usa-button__clipboard-link, td button.usa-button__clipboard-link {
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
// Targets the unstyled buttons in the form
|
||||
.button--clipboard {
|
||||
color: var(--link-fg);
|
||||
}
|
||||
|
||||
// Targets the DJA buttom with a nested icon
|
||||
button .usa-icon,
|
||||
.button .usa-icon,
|
||||
.button--clipboard .usa-icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.errors span.select2-selection {
|
||||
|
@ -663,7 +664,7 @@ address.dja-address-contact-list {
|
|||
align-items: center;
|
||||
|
||||
|
||||
.usa-button__icon {
|
||||
.usa-button--icon {
|
||||
position: absolute;
|
||||
right: auto;
|
||||
left: 4px;
|
||||
|
@ -681,10 +682,6 @@ address.dja-address-contact-list {
|
|||
}
|
||||
}
|
||||
|
||||
button.usa-button__clipboard {
|
||||
color: var(--link-fg);
|
||||
}
|
||||
|
||||
.no-outline-on-click:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
|
|
@ -213,4 +213,4 @@ a.usa-button--unstyled:visited {
|
|||
|
||||
.margin-right-neg-4px {
|
||||
margin-right: -4px;
|
||||
}
|
||||
}
|
|
@ -15,3 +15,4 @@
|
|||
margin-right: units(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,4 +27,4 @@
|
|||
|
||||
/*--------------------------------------------------
|
||||
--- Admin ---------------------------------*/
|
||||
@forward "admin";
|
||||
@forward "admin";
|
|
@ -664,6 +664,7 @@ ALLOWED_HOSTS = [
|
|||
"getgov-stable.app.cloud.gov",
|
||||
"getgov-staging.app.cloud.gov",
|
||||
"getgov-development.app.cloud.gov",
|
||||
"getgov-ad.app.cloud.gov",
|
||||
"getgov-ms.app.cloud.gov",
|
||||
"getgov-ag.app.cloud.gov",
|
||||
"getgov-litterbox.app.cloud.gov",
|
||||
|
|
|
@ -22,6 +22,11 @@ class UserFixture:
|
|||
"""
|
||||
|
||||
ADMINS = [
|
||||
{
|
||||
"username": "aad084c3-66cc-4632-80eb-41cdf5c5bcbf",
|
||||
"first_name": "Aditi",
|
||||
"last_name": "Green",
|
||||
},
|
||||
{
|
||||
"username": "be17c826-e200-4999-9389-2ded48c43691",
|
||||
"first_name": "Matthew",
|
||||
|
@ -120,6 +125,11 @@ class UserFixture:
|
|||
]
|
||||
|
||||
STAFF = [
|
||||
{
|
||||
"username": "ffec5987-aa84-411b-a05a-a7ee5cbcde54",
|
||||
"first_name": "Aditi-Analyst",
|
||||
"last_name": "Green-Analyst",
|
||||
},
|
||||
{
|
||||
"username": "d6bf296b-fac5-47ff-9c12-f88ccc5c1b99",
|
||||
"first_name": "Matthew-Analyst",
|
||||
|
|
|
@ -215,6 +215,11 @@ class DomainRequest(TimeStampedModel):
|
|||
}
|
||||
return org_election_map
|
||||
|
||||
@classmethod
|
||||
def get_org_label(cls, org_name: str):
|
||||
# Translating the key that is given to the direct readable value
|
||||
return cls(org_name).label if org_name else None
|
||||
|
||||
class OrganizationChoicesVerbose(models.TextChoices):
|
||||
"""
|
||||
Tertiary organization choices
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends "admin/change_form.html" %}
|
||||
{% load static i18n %} <!-- Add this line to load static template tag -->
|
||||
|
||||
{% comment %} Replace the Django ul markup with a div. We'll edit the child markup accordingly in change_form_object_tools {% endcomment %}
|
||||
{% block object-tools %}
|
||||
|
@ -9,4 +10,4 @@
|
|||
{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -1,4 +1,5 @@
|
|||
{% load i18n admin_urls %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% comment %} Replace li with p for more semantic HTML if we have a single child {% endcomment %}
|
||||
{% block object-tools-items %}
|
||||
|
@ -13,8 +14,21 @@
|
|||
</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="margin-0 padding-0">
|
||||
<a href="{% add_preserved_filters history_url %}" class="historylink">{% translate "History" %}</a>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{% add_preserved_filters history_url %}">{% translate "History" %}</a>
|
||||
</li>
|
||||
{% if opts.model_name == 'domainrequest' %}
|
||||
<li>
|
||||
<a id="id-copy-to-clipboard-summary" class="button--clipboard" type="button" href="#">
|
||||
<svg class="usa-icon" >
|
||||
<use xlink:href="{%static 'img/sprite.svg'%}#content_copy"></use>
|
||||
</svg>
|
||||
<span>{% translate "Copy request summary" %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Template for an input field with a clipboard
|
|||
<div class="admin-icon-group">
|
||||
{{ field }}
|
||||
<button
|
||||
class="usa-button usa-button--unstyled padding-left-1 usa-button__icon usa-button__clipboard"
|
||||
class="usa-button usa-button--unstyled padding-left-1 usa-button--icon button--clipboard copy-to-clipboard"
|
||||
type="button"
|
||||
>
|
||||
<div class="no-outline-on-click">
|
||||
|
@ -25,7 +25,7 @@ Template for an input field with a clipboard
|
|||
<div class="admin-icon-group admin-icon-group__clipboard-link">
|
||||
<input aria-hidden="true" class="display-none" value="{{ field.email }}" />
|
||||
<button
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button__icon usa-button__clipboard text-no-underline"
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button--icon button--clipboard copy-to-clipboard text-no-underline"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
|
|
|
@ -2,25 +2,28 @@
|
|||
|
||||
<address class="{% if no_title_top_padding %}margin-top-neg-1__detail-list{% endif %} {% if user.has_contact_info %}margin-bottom-1{% endif %} dja-address-contact-list">
|
||||
|
||||
|
||||
{% if show_formatted_name %}
|
||||
{% if user.get_formatted_name %}
|
||||
<a href="{% url 'admin:registrar_contact_change' user.id %}">{{ user.get_formatted_name }}</a><br />
|
||||
<a id="contact_info_name" href="{% url 'admin:registrar_contact_change' user.id %}">{{ user.get_formatted_name }}</a>
|
||||
{% else %}
|
||||
None<br />
|
||||
None
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</br>
|
||||
|
||||
{% if user.has_contact_info %}
|
||||
{# Title #}
|
||||
{% if user.title %}
|
||||
{{ user.title }}
|
||||
<br>
|
||||
<span id="contact_info_title">{{ user.title }}</span>
|
||||
{% else %}
|
||||
None<br>
|
||||
None
|
||||
{% endif %}
|
||||
</br>
|
||||
|
||||
{# Email #}
|
||||
{% if user.email %}
|
||||
{{ user.email }}
|
||||
<span id="contact_info_email">{{ user.email }}</span>
|
||||
{% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %}
|
||||
<br class="admin-icon-group__br">
|
||||
{% else %}
|
||||
|
@ -29,7 +32,7 @@
|
|||
|
||||
{# Phone #}
|
||||
{% if user.phone %}
|
||||
{{ user.phone }}
|
||||
<span id="contact_info_phone">{{ user.phone }}</span>
|
||||
<br>
|
||||
{% else %}
|
||||
None<br>
|
||||
|
@ -40,6 +43,6 @@
|
|||
{% endif %}
|
||||
|
||||
{% if user_verification_type %}
|
||||
{{ user_verification_type }}
|
||||
<span id="contact_info_phone">{{ user_verification_type }}</span>
|
||||
{% endif %}
|
||||
</address>
|
||||
|
|
|
@ -5,8 +5,8 @@ accept and become a domain manager.
|
|||
</p>
|
||||
|
||||
<p>
|
||||
An “invited” status indicates that the recipient has not logged in to the registrar since the invitation was sent.
|
||||
A “received” status indicates that the recipient has logged in.
|
||||
An “invited” status indicates that the recipient has not logged in to the registrar since the invitation was sent. Deleting an invitation with an "invited" status will prevent the user from signing in.
|
||||
A “received” status indicates that the recipient has logged in. Deleting an invitation with a "received" status will not revoke that user's access from the domain. To remove a user who has already signed in, go to <a class="text-underline" href="{% url 'admin:registrar_userdomainrole_changelist' %}">User domain roles</a> and delete the role for the correct domain/manager combination.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -219,7 +219,7 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
|||
<td class="padding-left-1 text-size-small">
|
||||
<input aria-hidden="true" class="display-none" value="{{ contact.email }}" />
|
||||
<button
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button__icon usa-button__clipboard usa-button__small-text text-no-underline"
|
||||
class="usa-button usa-button--unstyled padding-right-1 usa-button--icon button--clipboard copy-to-clipboard usa-button__small-text text-no-underline"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
{% load static %}
|
||||
|
||||
<section class="section--outlined domains{% if portfolio is not None %} margin-top-0{% endif %}" id="domains">
|
||||
<div class="grid-row">
|
||||
<div class="section--outlined__header margin-bottom-3 {% if portfolio is None %} section--outlined__header--no-portfolio justify-content-space-between{% else %} grid-row{% endif %}">
|
||||
{% if portfolio is None %}
|
||||
<div class="mobile:grid-col-12 desktop:grid-col-6">
|
||||
<h2 id="domains-header" class="flex-6">Domains</h2>
|
||||
</div>
|
||||
<h2 id="domains-header" class="display-inline-block">Domains</h2>
|
||||
<span class="display-none" id="no-portfolio-js-flag"></span>
|
||||
{% else %}
|
||||
<!-- Embedding the portfolio value in a data attribute -->
|
||||
|
|
|
@ -164,7 +164,7 @@ class TestDomainInvitationAdmin(TestCase):
|
|||
)
|
||||
|
||||
# Assert that the filters are added
|
||||
self.assertContains(response, "invited", count=4)
|
||||
self.assertContains(response, "invited", count=5)
|
||||
self.assertContains(response, "Invited", count=2)
|
||||
self.assertContains(response, "retrieved", count=2)
|
||||
self.assertContains(response, "Retrieved", count=2)
|
||||
|
@ -584,7 +584,7 @@ class TestDomainInformationAdmin(TestCase):
|
|||
self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields)
|
||||
|
||||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard", count=4)
|
||||
self.assertContains(response, "button--clipboard", count=4)
|
||||
|
||||
# cleanup this test
|
||||
domain_info.delete()
|
||||
|
|
|
@ -444,7 +444,7 @@ class TestDomainAdminWithClient(TestCase):
|
|||
self.assertContains(response, "(555) 555 5557")
|
||||
|
||||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard")
|
||||
self.assertContains(response, "button--clipboard")
|
||||
|
||||
# cleanup from this test
|
||||
domain.delete()
|
||||
|
|
|
@ -1411,7 +1411,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
|||
self.test_helper.assert_response_contains_distinct_values(response, expected_other_employees_fields)
|
||||
|
||||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard", count=4)
|
||||
self.assertContains(response, "button--clipboard", count=5)
|
||||
|
||||
# Test that Creator counts display properly
|
||||
self.assertNotContains(response, "Approved domains")
|
||||
|
|
|
@ -374,8 +374,9 @@ class DomainExport(BaseExport):
|
|||
if first_ready_on is None:
|
||||
first_ready_on = "(blank)"
|
||||
|
||||
domain_org_type = model.get("generic_org_type")
|
||||
human_readable_domain_org_type = DomainRequest.OrganizationChoices.get_org_label(domain_org_type)
|
||||
# organization_type has generic_org_type AND is_election
|
||||
domain_org_type = model.get("organization_type")
|
||||
human_readable_domain_org_type = DomainRequest.OrgChoicesElectionOffice.get_org_label(domain_org_type)
|
||||
domain_federal_type = model.get("federal_type")
|
||||
human_readable_domain_federal_type = BranchChoices.get_branch_label(domain_federal_type)
|
||||
domain_type = human_readable_domain_org_type
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue