More test fixes
- Legacy-Id: 19803
This commit is contained in:
parent
7f918b00da
commit
5132661b06
|
@ -101,7 +101,6 @@ class CommunityListTests(WebTest):
|
|||
self.assertContains(r, draft.name)
|
||||
|
||||
def test_manage_personal_list(self):
|
||||
return # FIXME-LARS
|
||||
|
||||
PersonFactory(user__username='plain')
|
||||
ad = Person.objects.get(user__username='ad')
|
||||
|
@ -116,7 +115,7 @@ class CommunityListTests(WebTest):
|
|||
# add document
|
||||
self.assertIn('add_document', page.forms)
|
||||
form = page.forms['add_document']
|
||||
form['documents']=draft.pk
|
||||
form['documents'].options=[(draft.pk, True, draft.name)]
|
||||
page = form.submit('action',value='add_documents')
|
||||
self.assertEqual(page.status_int, 302)
|
||||
clist = CommunityList.objects.get(user__username="plain")
|
||||
|
@ -173,7 +172,6 @@ class CommunityListTests(WebTest):
|
|||
self.assertTrue(not clist.searchrule_set.filter(rule_type="author_rfc"))
|
||||
|
||||
def test_manage_group_list(self):
|
||||
return # FIXME-LARS
|
||||
draft = WgDraftFactory(group__acronym='mars')
|
||||
RoleFactory(group__acronym='mars',name_id='chair',person=PersonFactory(user__username='marschairman'))
|
||||
|
||||
|
|
|
@ -228,7 +228,6 @@ class SearchTests(TestCase):
|
|||
self.assertContains(r, "Document Search")
|
||||
|
||||
def test_docs_for_ad(self):
|
||||
return # FIXME-LARS
|
||||
ad = RoleFactory(name_id='ad',group__type_id='area',group__state_id='active').person
|
||||
draft = IndividualDraftFactory(ad=ad)
|
||||
draft.action_holders.set([PersonFactory()])
|
||||
|
@ -273,7 +272,6 @@ class SearchTests(TestCase):
|
|||
self.assertContains(r, 'title="AUTH48"') # title attribute of AUTH48 badge in auth48_alert_badge filter
|
||||
|
||||
def test_drafts_in_last_call(self):
|
||||
return # FIXME-LARS
|
||||
draft = IndividualDraftFactory(pages=1)
|
||||
draft.action_holders.set([PersonFactory()])
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="lc"))
|
||||
|
@ -283,7 +281,6 @@ class SearchTests(TestCase):
|
|||
self.assertContains(r, escape(draft.action_holders.first().plain_name()))
|
||||
|
||||
def test_in_iesg_process(self):
|
||||
return # FIXME-LARS
|
||||
doc_in_process = IndividualDraftFactory()
|
||||
doc_in_process.action_holders.set([PersonFactory()])
|
||||
doc_in_process.set_state(State.objects.get(type='draft-iesg', slug='lc'))
|
||||
|
@ -334,7 +331,6 @@ class SearchTests(TestCase):
|
|||
self.assertEqual(data[0]["id"], doc_alias.pk)
|
||||
|
||||
def test_recent_drafts(self):
|
||||
return # FIXME-LARS
|
||||
# Three drafts to show with various warnings
|
||||
drafts = WgDraftFactory.create_batch(3,states=[('draft','active'),('draft-iesg','ad-eval')])
|
||||
for index, draft in enumerate(drafts):
|
||||
|
@ -800,7 +796,6 @@ Man Expires September 22, 2015 [Page 3]
|
|||
self.client.login(username=username, password=username + '+password')
|
||||
|
||||
def test_edit_authors_permissions(self):
|
||||
return # FIXME-LARS
|
||||
"""Only the secretariat may edit authors"""
|
||||
draft = WgDraftFactory(authors=PersonFactory.create_batch(3))
|
||||
RoleFactory(group=draft.group, name_id='chair')
|
||||
|
@ -915,7 +910,6 @@ Man Expires September 22, 2015 [Page 3]
|
|||
post_data[_add_prefix(str(form_index) + '-ORDER')] = str(insert_order)
|
||||
|
||||
def test_edit_authors_missing_basis(self):
|
||||
return # FIXME-LARS
|
||||
draft = WgDraftFactory()
|
||||
DocumentAuthorFactory.create_batch(3, document=draft)
|
||||
url = urlreverse('ietf.doc.views_doc.edit_authors', kwargs=dict(name=draft.name))
|
||||
|
@ -932,7 +926,6 @@ Man Expires September 22, 2015 [Page 3]
|
|||
self.assertContains(r, 'This field is required.')
|
||||
|
||||
def test_edit_authors_no_change(self):
|
||||
return # FIXME-LARS
|
||||
draft = WgDraftFactory()
|
||||
DocumentAuthorFactory.create_batch(3, document=draft)
|
||||
url = urlreverse('ietf.doc.views_doc.edit_authors', kwargs=dict(name=draft.name))
|
||||
|
@ -1011,15 +1004,12 @@ Man Expires September 22, 2015 [Page 3]
|
|||
self.assertIn(auth.name, evt.desc)
|
||||
|
||||
def test_edit_authors_append_author(self):
|
||||
return # FIXME-LARS
|
||||
self.do_edit_authors_append_authors_test(1)
|
||||
|
||||
def test_edit_authors_append_authors(self):
|
||||
return # FIXME-LARS
|
||||
self.do_edit_authors_append_authors_test(3)
|
||||
|
||||
def test_edit_authors_insert_author(self):
|
||||
return # FIXME-LARS
|
||||
"""Can add author in the middle of the list"""
|
||||
draft = WgDraftFactory()
|
||||
DocumentAuthorFactory.create_batch(3, document=draft)
|
||||
|
@ -1076,7 +1066,6 @@ Man Expires September 22, 2015 [Page 3]
|
|||
self.assertEqual(reorder_events.count(), 2)
|
||||
|
||||
def test_edit_authors_remove_author(self):
|
||||
return # FIXME-LARS
|
||||
draft = WgDraftFactory()
|
||||
DocumentAuthorFactory.create_batch(3, document=draft)
|
||||
url = urlreverse('ietf.doc.views_doc.edit_authors', kwargs=dict(name=draft.name))
|
||||
|
@ -1127,7 +1116,6 @@ Man Expires September 22, 2015 [Page 3]
|
|||
self.assertIn(reordered_person.name, reordered_event.desc)
|
||||
|
||||
def test_edit_authors_reorder_authors(self):
|
||||
return # FIXME-LARS
|
||||
draft = WgDraftFactory()
|
||||
DocumentAuthorFactory.create_batch(3, document=draft)
|
||||
url = urlreverse('ietf.doc.views_doc.edit_authors', kwargs=dict(name=draft.name))
|
||||
|
@ -1184,7 +1172,6 @@ Man Expires September 22, 2015 [Page 3]
|
|||
)
|
||||
|
||||
def test_edit_authors_edit_fields(self):
|
||||
return # FIXME-LARS
|
||||
draft = WgDraftFactory()
|
||||
DocumentAuthorFactory.create_batch(3, document=draft)
|
||||
url = urlreverse('ietf.doc.views_doc.edit_authors', kwargs=dict(name=draft.name))
|
||||
|
@ -1287,14 +1274,13 @@ Man Expires September 22, 2015 [Page 3]
|
|||
with self.settings(DOC_ACTION_HOLDER_AGE_LIMIT_DAYS=20):
|
||||
r = self.client.get(url)
|
||||
|
||||
# FIXME-LARS
|
||||
# self.assertContains(r, 'Action Holders') # should still be shown
|
||||
# q = PyQuery(r.content)
|
||||
# self.assertEqual(len(self._pyquery_select_action_holder_string(q, '(None)')), 0)
|
||||
# for person in draft.action_holders.all():
|
||||
# self.assertEqual(len(self._pyquery_select_action_holder_string(q, person.plain_name())), 1)
|
||||
# # check that one action holder was marked as old
|
||||
# self.assertEqual(len(self._pyquery_select_action_holder_string(q, 'for 30 days')), 1)
|
||||
self.assertContains(r, 'Action Holders') # should still be shown
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(self._pyquery_select_action_holder_string(q, '(None)')), 0)
|
||||
for person in draft.action_holders.all():
|
||||
self.assertEqual(len(self._pyquery_select_action_holder_string(q, person.plain_name())), 1)
|
||||
# check that one action holder was marked as old
|
||||
self.assertEqual(len(self._pyquery_select_action_holder_string(q, 'for 30 days')), 1)
|
||||
|
||||
@mock.patch.object(Document, 'action_holders_enabled', return_value=True, new_callable=mock.PropertyMock)
|
||||
def test_document_draft_action_holders_buttons(self, mock_method):
|
||||
|
@ -1456,12 +1442,11 @@ Man Expires September 22, 2015 [Page 3]
|
|||
|
||||
class DocTestCase(TestCase):
|
||||
def test_status_change(self):
|
||||
return # FIXME-LARS
|
||||
statchg = StatusChangeFactory()
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=statchg.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=statchg.relateddocument_set.first().target.document.canonical_name())))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=statchg.relateddocument_set.first().target.document)))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
def test_document_charter(self):
|
||||
CharterFactory(name='charter-ietf-mars')
|
||||
|
@ -2381,7 +2366,6 @@ class ChartTests(ResourceTestCaseMixin, TestCase):
|
|||
|
||||
class FieldTests(TestCase):
|
||||
def test_searchabledocumentsfield_pre(self):
|
||||
return # FIXME-LARS
|
||||
# so far, just tests that the format expected by select2 set up
|
||||
docs = IndividualDraftFactory.create_batch(3)
|
||||
|
||||
|
@ -2391,8 +2375,7 @@ class FieldTests(TestCase):
|
|||
form = _TestForm(initial=dict(test_field=docs))
|
||||
html = str(form)
|
||||
q = PyQuery(html)
|
||||
json_data = q('input.select2-field').attr('data-pre')
|
||||
print(json_data)
|
||||
json_data = q('.select2-field').attr('data-pre')
|
||||
try:
|
||||
decoded = json.loads(json_data)
|
||||
except json.JSONDecodeError as e:
|
||||
|
@ -2401,7 +2384,7 @@ class FieldTests(TestCase):
|
|||
self.assertCountEqual(decoded_ids, [str(doc.id) for doc in docs])
|
||||
for doc in docs:
|
||||
self.assertEqual(
|
||||
dict(id=doc.pk, text=escape(uppercase_std_abbreviated_name(doc.name))),
|
||||
dict(id=doc.pk, selected=True, text=escape(uppercase_std_abbreviated_name(doc.name))),
|
||||
decoded[str(doc.pk)],
|
||||
)
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ This test section has some text.
|
|||
new_editors.discard(acting_editor)
|
||||
new_editors.add(PersonFactory())
|
||||
url = urlreverse('ietf.doc.views_bofreq.change_editors', kwargs=dict(name=doc.name))
|
||||
postdict = dict(editors=','.join([str(p.pk) for p in new_editors]))
|
||||
postdict = dict(editors=[str(p.pk) for p in new_editors])
|
||||
r = self.client.post(url, postdict)
|
||||
self.assertEqual(r.status_code,302)
|
||||
editors = bofreq_editors(doc)
|
||||
|
@ -196,7 +196,7 @@ This test section has some text.
|
|||
new_editors = set(previous_editors)
|
||||
new_editors.discard(acting_editor)
|
||||
new_editors.add(PersonFactory())
|
||||
postdict = dict(editors=','.join([str(p.pk) for p in new_editors]))
|
||||
postdict = dict(editors=[str(p.pk) for p in new_editors])
|
||||
r = self.client.post(url,postdict)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
updated_editors = bofreq_editors(doc)
|
||||
|
@ -213,7 +213,7 @@ This test section has some text.
|
|||
new_responsible = set(previous_responsible[1:])
|
||||
new_responsible.add(RoleFactory(group__type_id='area',name_id='ad').person)
|
||||
url = urlreverse('ietf.doc.views_bofreq.change_responsible', kwargs=dict(name=doc.name))
|
||||
postdict = dict(responsible=','.join([str(p.pk) for p in new_responsible]))
|
||||
postdict = dict(responsible=[str(p.pk) for p in new_responsible])
|
||||
r = self.client.post(url, postdict)
|
||||
self.assertEqual(r.status_code,302)
|
||||
responsible = bofreq_responsible(doc)
|
||||
|
@ -235,7 +235,7 @@ This test section has some text.
|
|||
self.assertIn(responsible.name,unescaped)
|
||||
new_responsible = set(previous_responsible)
|
||||
new_responsible.add(RoleFactory(group__type_id='area',name_id='ad').person)
|
||||
postdict = dict(responsible=','.join([str(p.pk) for p in new_responsible]))
|
||||
postdict = dict(responsible=[str(p.pk) for p in new_responsible])
|
||||
r = self.client.post(url,postdict)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
updated_responsible = bofreq_responsible(doc)
|
||||
|
@ -256,11 +256,11 @@ This test section has some text.
|
|||
pks = set()
|
||||
pks.update([p.pk for p in good_batch])
|
||||
pks.update([p.pk for p in bad_batch])
|
||||
postdict = dict(responsible=','.join([str(pk) for pk in pks]))
|
||||
postdict = dict(responsible=[str(pk) for pk in pks])
|
||||
r = self.client.post(url,postdict)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
error_text = q('.is-invalid .alert').text()
|
||||
error_text = q('.invalid-feedback').text()
|
||||
for p in good_batch:
|
||||
self.assertNotIn(p.plain_name(), error_text)
|
||||
for p in bad_batch:
|
||||
|
|
|
@ -48,7 +48,6 @@ class Downref(TestCase):
|
|||
self.assertContains(r, 'Add downref')
|
||||
|
||||
def test_downref_registry_add(self):
|
||||
return # FIXME-LARS
|
||||
url = urlreverse('ietf.doc.views_downref.downref_registry_add')
|
||||
login_testing_unauthorized(self, "plain", url)
|
||||
|
||||
|
|
|
@ -1076,7 +1076,6 @@ class IndividualInfoFormsTests(TestCase):
|
|||
self.assertEqual(doc.ad, pre_ad, 'Pre-AD was not actually assigned')
|
||||
|
||||
def test_doc_change_shepherd(self):
|
||||
return # FIXME-LARS
|
||||
doc = Document.objects.get(name=self.docname)
|
||||
doc.shepherd = None
|
||||
doc.save_with_history([DocEvent.objects.create(doc=doc, rev=doc.rev, type="changed_shepherd", by=Person.objects.get(user__username="secretary"), desc="Test")])
|
||||
|
@ -1094,7 +1093,7 @@ class IndividualInfoFormsTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[id=id_shepherd]')),1)
|
||||
self.assertEqual(len(q('form select[id=id_shepherd]')),1)
|
||||
|
||||
# change the shepherd
|
||||
plain_email = Email.objects.get(person__name="Plain Man")
|
||||
|
@ -1116,7 +1115,7 @@ class IndividualInfoFormsTests(TestCase):
|
|||
self.assertTrue(any(['no changes have been made' in m.message for m in r.context['messages']]))
|
||||
|
||||
# Remove the shepherd
|
||||
r = self.client.post(url, dict(shepherd=''))
|
||||
r = self.client.post(url, dict(shepherd=[]))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
doc = Document.objects.get(name=self.docname)
|
||||
self.assertTrue(any(['Document shepherd changed to (None)' in x.desc for x in doc.docevent_set.filter(time=doc.time,type='added_comment')]))
|
||||
|
@ -1294,10 +1293,9 @@ class IndividualInfoFormsTests(TestCase):
|
|||
'Expected "Remove %s" button for' % role_name)
|
||||
|
||||
def _test_changing_ah(action_holders, reason):
|
||||
return # FIXME-LARS
|
||||
r = self.client.post(url, dict(
|
||||
reason=reason,
|
||||
action_holders=','.join([str(p.pk) for p in action_holders]),
|
||||
action_holders=[str(p.pk) for p in action_holders],
|
||||
))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
doc = Document.objects.get(name=self.docname)
|
||||
|
@ -1322,7 +1320,6 @@ class IndividualInfoFormsTests(TestCase):
|
|||
self.do_doc_change_action_holders_test('ad')
|
||||
|
||||
def do_doc_remind_action_holders_test(self, username):
|
||||
return # FIXME-LARS
|
||||
doc = Document.objects.get(name=self.docname)
|
||||
doc.action_holders.set(PersonFactory.create_batch(3))
|
||||
|
||||
|
@ -1840,7 +1837,6 @@ class ChangeReplacesTests(TestCase):
|
|||
|
||||
|
||||
def test_change_replaces(self):
|
||||
return # FIXME-LARS
|
||||
url = urlreverse('ietf.doc.views_draft.replaces', kwargs=dict(name=self.replacea.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
|
@ -1869,7 +1865,7 @@ class ChangeReplacesTests(TestCase):
|
|||
# Post that says replaceboth replaces both base a and base b
|
||||
url = urlreverse('ietf.doc.views_draft.replaces', kwargs=dict(name=self.replaceboth.name))
|
||||
self.assertEqual(self.baseb.get_state().slug,'expired')
|
||||
r = self.client.post(url, dict(replaces='%s,%s' % (self.basea.pk, self.baseb.pk)))
|
||||
r = self.client.post(url, dict(replaces=[self.basea.pk, self.baseb.pk]))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl')
|
||||
self.assertEqual(Document.objects.get(name='draft-test-base-b').get_state().slug,'repl')
|
||||
|
@ -1880,7 +1876,7 @@ class ChangeReplacesTests(TestCase):
|
|||
|
||||
# Post that undoes replaceboth
|
||||
empty_outbox()
|
||||
r = self.client.post(url, dict(replaces=""))
|
||||
r = self.client.post(url, dict(replaces=[]))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl') # Because A is still also replaced by replacea
|
||||
self.assertEqual(Document.objects.get(name='draft-test-base-b').get_state().slug,'expired')
|
||||
|
@ -1892,7 +1888,7 @@ class ChangeReplacesTests(TestCase):
|
|||
# Post that undoes replacea
|
||||
empty_outbox()
|
||||
url = urlreverse('ietf.doc.views_draft.replaces', kwargs=dict(name=self.replacea.name))
|
||||
r = self.client.post(url, dict(replaces=""))
|
||||
r = self.client.post(url, dict(replaces=[]))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'active')
|
||||
self.assertTrue('basea_author@' in outbox[-1]['To'])
|
||||
|
@ -1921,7 +1917,6 @@ class ChangeReplacesTests(TestCase):
|
|||
class MoreReplacesTests(TestCase):
|
||||
|
||||
def test_stream_state_changes_when_replaced(self):
|
||||
return # FIXME-LARS
|
||||
self.client.login(username='secretary',password='secretary+password')
|
||||
for stream in ('iab','irtf','ise'):
|
||||
old_doc = IndividualDraftFactory(stream_id=stream)
|
||||
|
|
|
@ -30,17 +30,21 @@ class EditAuthorsTests(IetfSeleniumTestCase):
|
|||
# To enter the person, type their name in the select2 search box, wait for the
|
||||
# search to offer the result, then press 'enter' to accept the result and close
|
||||
# the search input.
|
||||
person_span = form_elt.find_element(By.CLASS_NAME, 'select2-chosen')
|
||||
# self.driver.set_page_load_timeout(60)
|
||||
person_span = form_elt.find_element(By.CLASS_NAME, 'select2-selection')
|
||||
self.scroll_to_element(person_span)
|
||||
person_span.click()
|
||||
input = self.driver.switch_to.active_element
|
||||
input = self.driver.find_element(By.CLASS_NAME, 'select2-search__field')
|
||||
input.send_keys(name)
|
||||
result_selector = 'ul.select2-results > li > div.select2-result-label'
|
||||
self.wait.until(
|
||||
expected_conditions.text_to_be_present_in_element(
|
||||
(By.CSS_SELECTOR, result_selector),
|
||||
name
|
||||
))
|
||||
result_selector = 'ul.select2-results__options > li.select2-results__option--selectable'
|
||||
try:
|
||||
WebDriverWait(self.driver, 3).until(
|
||||
expected_conditions.text_to_be_present_in_element(
|
||||
(By.CSS_SELECTOR, result_selector),
|
||||
name
|
||||
))
|
||||
except:
|
||||
print(name, email, self.driver.find_element(By.CSS_SELECTOR, ".select2-results__message").text)
|
||||
input.send_keys('\n') # select the object
|
||||
|
||||
# After the author is selected, the email select options will be populated.
|
||||
|
@ -63,7 +67,7 @@ class EditAuthorsTests(IetfSeleniumTestCase):
|
|||
|
||||
Note: returns the Person instance named in the person field, not just their name.
|
||||
"""
|
||||
hidden_person_input = form_elt.find_element(By.CSS_SELECTOR, 'input[type="text"][name$="person"]')
|
||||
hidden_person_input = form_elt.find_element(By.CSS_SELECTOR, 'select[name$="person"]')
|
||||
email_select = form_elt.find_element(By.CSS_SELECTOR, 'select[name$="email"]')
|
||||
affil_input = form_elt.find_element(By.CSS_SELECTOR, 'input[name$="affiliation"]')
|
||||
country_input = form_elt.find_element(By.CSS_SELECTOR, 'input[name$="country"]')
|
||||
|
@ -94,8 +98,9 @@ class EditAuthorsTests(IetfSeleniumTestCase):
|
|||
# get the "add author" button so we can add blank author forms
|
||||
add_author_button = self.driver.find_element(By.ID, 'add-author-button')
|
||||
for index, auth in enumerate(authors):
|
||||
self.scroll_to_element(add_author_button) # Can only click if it's in view!
|
||||
add_author_button.click() # Create a new form. Automatically scrolls to it.
|
||||
self.driver.execute_script("arguments[0].click();", add_author_button) # FIXME-LARS: no idea why this fails:
|
||||
# self.scroll_to_element(add_author_button) # Can only click if it's in view!
|
||||
# add_author_button.click() # Create a new form. Automatically scrolls to it.
|
||||
author_forms = authors_list.find_elements(By.CLASS_NAME, 'author-panel')
|
||||
authors_added = index + 1
|
||||
self.assertEqual(len(author_forms), authors_added + 1) # Started with 1 author, hence +1
|
||||
|
@ -117,8 +122,9 @@ class EditAuthorsTests(IetfSeleniumTestCase):
|
|||
self.driver.find_element(By.ID, 'id_basis').send_keys('change testing')
|
||||
# Now click the 'submit' button and check that the update was accepted.
|
||||
submit_button = self.driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]')
|
||||
self.scroll_to_element(submit_button)
|
||||
submit_button.click()
|
||||
self.driver.execute_script("arguments[0].click();", submit_button) # FIXME-LARS: no idea why this fails:
|
||||
# self.scroll_to_element(submit_button)
|
||||
# submit_button.click()
|
||||
# Wait for redirect to the document_main view
|
||||
self.wait.until(
|
||||
expected_conditions.url_to_be(
|
||||
|
|
|
@ -1479,7 +1479,7 @@ def edit_action_holders(request, name):
|
|||
|
||||
if request.method == 'POST':
|
||||
form = ActionHoldersForm(request.POST)
|
||||
if form.is_valid() and 'action_holders' in request.POST:
|
||||
if form.is_valid():
|
||||
new_action_holders = form.cleaned_data['action_holders'] # Person queryset
|
||||
prev_action_holders = list(doc.action_holders.all())
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ class GroupPagesTests(TestCase):
|
|||
for url in [group.about_url(),] + group_urlreverse_list(group, 'ietf.group.views.group_about'):
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
||||
for role in group.role_set.all():
|
||||
self.assertContains(r, escape(role.person.plain_name()))
|
||||
|
||||
|
@ -595,7 +595,7 @@ class GroupEditTests(TestCase):
|
|||
self.assertEqual(len(q('form select[name=parent]')), 1)
|
||||
self.assertEqual(len(q('form input[name=acronym]')), 1)
|
||||
for role_slug in group.used_roles or group.features.default_used_roles:
|
||||
self.assertEqual(len(q('form input[name=%s_roles]'%role_slug)),1)
|
||||
self.assertEqual(len(q('form select[name=%s_roles]'%role_slug)),1)
|
||||
|
||||
# faulty post
|
||||
Group.objects.create(name="Collision Test Group", acronym="collide")
|
||||
|
@ -631,12 +631,12 @@ class GroupEditTests(TestCase):
|
|||
ad=ad.pk,
|
||||
state=state.pk,
|
||||
ad_roles=ad.email().address,
|
||||
chair_roles="aread@example.org, ad1@example.org",
|
||||
secr_roles="aread@example.org, ad1@example.org, ad2@example.org",
|
||||
liaison_contact_roles="ad1@example.org",
|
||||
liaison_cc_contact_roles="aread@example.org, ad2@example.org",
|
||||
techadv_roles="aread@example.org",
|
||||
delegate_roles="ad2@example.org",
|
||||
chair_roles=["aread@example.org", "ad1@example.org"],
|
||||
secr_roles=["aread@example.org", "ad1@example.org", "ad2@example.org"],
|
||||
liaison_contact_roles=["ad1@example.org"],
|
||||
liaison_cc_contact_roles=["aread@example.org", "ad2@example.org"],
|
||||
techadv_roles=["aread@example.org"],
|
||||
delegate_roles=["ad2@example.org"],
|
||||
list_email="mars@mail",
|
||||
list_subscribe="subscribe.mars",
|
||||
list_archive="archive.mars",
|
||||
|
@ -728,9 +728,9 @@ class GroupEditTests(TestCase):
|
|||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('div#content > form input[name=%s]' % field_name)), 1)
|
||||
self.assertEqual(len(q('div#content > form input[name=%s], div#content > form select[name=%s]' % (field_name, field_name))), 1)
|
||||
for prohibited_name in prohibited_form_names:
|
||||
self.assertEqual(len(q('div#content > form input[name=%s]' % prohibited_name)), 0)
|
||||
self.assertEqual(len(q('div#content > form input[name=%s], div#content > form select[name=%s]' % (prohibited_name, prohibited_name))), 0)
|
||||
|
||||
# edit info
|
||||
r = self.client.post(url, {field_name: field_content})
|
||||
|
@ -741,7 +741,7 @@ class GroupEditTests(TestCase):
|
|||
if field_name.endswith('_roles'):
|
||||
role_name = field_name[:-len('_roles')]
|
||||
self.assertSetEqual(
|
||||
{fc.strip() for fc in field_content.split(',')},
|
||||
{fc.strip() for fc in field_content},
|
||||
set(group.role_set.filter(name=role_name).values_list('email', flat=True))
|
||||
)
|
||||
else:
|
||||
|
@ -755,8 +755,8 @@ class GroupEditTests(TestCase):
|
|||
# Test various fields
|
||||
_test_field(group, 'name', 'Mars Not Special Interest Group', ['acronym'])
|
||||
_test_field(group, 'list_email', 'mars@mail', ['name'])
|
||||
_test_field(group, 'liaison_contact_roles', 'user@example.com, other_user@example.com', ['list_email'])
|
||||
_test_field(group, 'liaison_cc_contact_roles', 'user@example.com, other_user@example.com', ['liaison_contact'])
|
||||
_test_field(group, 'liaison_contact_roles', ['user@example.com', 'other_user@example.com'], ['list_email'])
|
||||
_test_field(group, 'liaison_cc_contact_roles', ['user@example.com', 'other_user@example.com'], ['liaison_contact'])
|
||||
|
||||
def test_edit_reviewers(self):
|
||||
group=GroupFactory(type_id='review',parent=GroupFactory(type_id='area'))
|
||||
|
@ -779,7 +779,7 @@ class GroupEditTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[name=reviewer_roles]')), 1)
|
||||
self.assertEqual(len(q('form select[name=reviewer_roles]')), 1)
|
||||
|
||||
# set reviewers
|
||||
empty_outbox()
|
||||
|
@ -935,16 +935,15 @@ class GroupFormTests(TestCase):
|
|||
)
|
||||
# fill in original values
|
||||
for rslug in group.get_used_roles():
|
||||
data['{}_roles'.format(rslug)] = ','.join(
|
||||
group.role_set.filter(name_id=rslug).values_list('email__address', flat=True),
|
||||
)
|
||||
data['{}_roles'.format(rslug)] = list(group.role_set.filter(name_id=rslug).values_list('email__address', flat=True).all())
|
||||
|
||||
return data
|
||||
|
||||
def _assert_cleaned_data_equal(self, cleaned_data, post_data):
|
||||
for attr, expected in post_data.items():
|
||||
value = cleaned_data[attr]
|
||||
if attr.endswith('_roles'):
|
||||
actual = ','.join(value.values_list('address', flat=True))
|
||||
actual = list(value.values_list('address', flat=True).all())
|
||||
elif attr == 'resources':
|
||||
# must handle resources specially
|
||||
actual = '\n'.join(self._format_resource(r) for r in value)
|
||||
|
@ -966,7 +965,7 @@ class GroupFormTests(TestCase):
|
|||
for rslug in group.get_used_roles():
|
||||
data = orig_data.copy()
|
||||
edit_field = '{}_roles'.format(rslug)
|
||||
data[edit_field] = new_email.address # comma-separated list of addresses with only one
|
||||
data[edit_field] = [new_email.address]
|
||||
|
||||
form = GroupForm(data, group=group, group_type=group.type_id, field=None)
|
||||
|
||||
|
@ -1061,7 +1060,6 @@ class MilestoneTests(TestCase):
|
|||
resolved="",
|
||||
state_id="charter")
|
||||
m2.docs.set([draft])
|
||||
|
||||
return (m1, m2, group)
|
||||
|
||||
def last_day_of_month(self, d):
|
||||
|
@ -1110,7 +1108,7 @@ class MilestoneTests(TestCase):
|
|||
'm-1-desc': "", # no description
|
||||
'm-1-due': due.strftime("%B %Y"),
|
||||
'm-1-resolved': "",
|
||||
'm-1-docs': ",".join(doc_pks),
|
||||
'm-1-docs': doc_pks,
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
@ -1125,7 +1123,7 @@ class MilestoneTests(TestCase):
|
|||
'm-1-desc': "Test 3",
|
||||
'm-1-due': due.strftime("%B %Y"),
|
||||
'm-1-resolved': "",
|
||||
'm-1-docs': ",".join(doc_pks),
|
||||
'm-1-docs': doc_pks,
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
@ -1201,7 +1199,7 @@ class MilestoneTests(TestCase):
|
|||
'm1-desc': m1.desc,
|
||||
'm1-due': m1.due.strftime("%B %Y"),
|
||||
'm1-resolved': m1.resolved,
|
||||
'm1-docs': ",".join(pklist(m1.docs)),
|
||||
'm1-docs': pklist(m1.docs),
|
||||
'm1-review': "accept",
|
||||
'action': "save",
|
||||
})
|
||||
|
@ -1227,7 +1225,7 @@ class MilestoneTests(TestCase):
|
|||
'm1-desc': m1.desc,
|
||||
'm1-due': m1.due.strftime("%B %Y"),
|
||||
'm1-resolved': "",
|
||||
'm1-docs': ",".join(pklist(m1.docs)),
|
||||
'm1-docs': pklist(m1.docs),
|
||||
'm1-delete': "checked",
|
||||
'action': "save",
|
||||
})
|
||||
|
@ -1257,7 +1255,7 @@ class MilestoneTests(TestCase):
|
|||
'm1-desc': "", # no description
|
||||
'm1-due': due.strftime("%B %Y"),
|
||||
'm1-resolved': "",
|
||||
'm1-docs': ",".join(doc_pks),
|
||||
'm1-docs': doc_pks,
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
@ -1275,7 +1273,7 @@ class MilestoneTests(TestCase):
|
|||
'm1-due': due.strftime("%B %Y"),
|
||||
'm1-resolved': "Done",
|
||||
'm1-resolved_checkbox': "checked",
|
||||
'm1-docs': ",".join(doc_pks),
|
||||
'm1-docs': doc_pks,
|
||||
'action': "save",
|
||||
})
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
@ -1343,7 +1341,7 @@ class DatelessMilestoneTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('#switch-date-use-form')),0)
|
||||
self.assertEqual(len(q('button[value="switch"]:submit')),0)
|
||||
|
||||
r = self.client.post(url, dict(action="switch"))
|
||||
self.assertEqual(r.status_code, 403)
|
||||
|
@ -1447,7 +1445,7 @@ class DatelessMilestoneTests(TestCase):
|
|||
post_data['%s-id' % prefix] = ms.id
|
||||
post_data['%s-desc' % prefix] = ms.desc
|
||||
post_data['%s-order' % prefix] = ms.order
|
||||
post_data['%s-docs' % prefix] = ""
|
||||
post_data['%s-docs' % prefix] = []
|
||||
|
||||
post_data['prefix'] = prefixes
|
||||
post_data['action'] = 'review'
|
||||
|
@ -1461,7 +1459,7 @@ class DatelessMilestoneTests(TestCase):
|
|||
r = self.client.post(url, post_data)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('.label:contains("Changed")')), 2)
|
||||
self.assertEqual(len(q('span.badge:contains("Changed")')), 2)
|
||||
|
||||
post_data['action'] = 'save'
|
||||
r = self.client.post(url, post_data)
|
||||
|
|
|
@ -28,7 +28,7 @@ class MilestoneTests(IetfSeleniumTestCase):
|
|||
"""Search for a draft and get the search result element"""
|
||||
draft_input.send_keys(search_string)
|
||||
|
||||
result_selector = 'ul.select2-results > li > div.select2-result-label'
|
||||
result_selector = '.select2-results > ul > li'
|
||||
self.wait.until(
|
||||
expected_conditions.text_to_be_present_in_element(
|
||||
(By.CSS_SELECTOR, result_selector),
|
||||
|
@ -91,10 +91,11 @@ class MilestoneTests(IetfSeleniumTestCase):
|
|||
|
||||
desc_input = edit_div.find_element(By.CSS_SELECTOR, 'input[id$="_desc"]')
|
||||
due_input = edit_div.find_element(By.CSS_SELECTOR, 'input[id$="_due"]')
|
||||
draft_input = edit_div.find_element(By.CSS_SELECTOR,
|
||||
'div.select2-container[id$="id_docs"] input.select2-input'
|
||||
)
|
||||
|
||||
draft_input = self.wait.until(
|
||||
expected_conditions.visibility_of_element_located(
|
||||
(By.CSS_SELECTOR, '.select2-container textarea[aria-describedby*="_docs"]')
|
||||
))
|
||||
|
||||
# fill in the edit milestone form
|
||||
desc_input.send_keys(description)
|
||||
due_input.send_keys(due_date.strftime('%m %Y\n')) # \n closes the date selector
|
||||
|
@ -151,9 +152,7 @@ class MilestoneTests(IetfSeleniumTestCase):
|
|||
|
||||
due_field = self.driver.find_element(By.ID, prefix + 'due')
|
||||
hidden_drafts_field = self.driver.find_element(By.ID, prefix + 'docs')
|
||||
draft_input = self.driver.find_element(By.CSS_SELECTOR,
|
||||
'div.select2-container[id*="%s"] input.select2-input' % prefix
|
||||
)
|
||||
draft_input = self.driver.find_element(By.CSS_SELECTOR, 'textarea[aria-describedby*="%sdocs"]' % prefix)
|
||||
self.assertEqual(due_field.get_attribute('value'), milestone.due.strftime('%B %Y'))
|
||||
self.assertEqual(hidden_drafts_field.get_attribute('value'),
|
||||
','.join([str(doc.pk) for doc in milestone.docs.all()]))
|
||||
|
|
|
@ -253,7 +253,7 @@ class IprTests(TestCase):
|
|||
"ietfer_contact_info": "555-555-0101",
|
||||
"iprdocrel_set-TOTAL_FORMS": 2,
|
||||
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||
"iprdocrel_set-0-document": "%s" % draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-document": draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-revisions": '00',
|
||||
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||
"patent_number": "SE12345678901",
|
||||
|
@ -309,7 +309,7 @@ class IprTests(TestCase):
|
|||
"ietfer_contact_info": "555-555-0101",
|
||||
"iprdocrel_set-TOTAL_FORMS": 2,
|
||||
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||
"iprdocrel_set-0-document": "%s" % draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-document": draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-revisions": '00',
|
||||
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||
"patent_number": "SE12345678901",
|
||||
|
@ -356,7 +356,7 @@ class IprTests(TestCase):
|
|||
"holder_legal_name": "Test Legal",
|
||||
"ietfer_contact_info": "555-555-0101",
|
||||
"ietfer_name": "Test Participant",
|
||||
"iprdocrel_set-0-document": "%s" % draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-document": draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-revisions": '00',
|
||||
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||
"iprdocrel_set-TOTAL_FORMS": 1,
|
||||
|
@ -367,10 +367,9 @@ class IprTests(TestCase):
|
|||
"patent_title": "A method of transfering bits",
|
||||
"submitter_email": "test@holder.com",
|
||||
"submitter_name": "Test Holder",
|
||||
"updates": "",
|
||||
"updates": [],
|
||||
}
|
||||
r = self.client.post(url, post_data, follow=True)
|
||||
print(r)
|
||||
self.assertContains(r, "Disclosure modified")
|
||||
|
||||
iprs = IprDisclosureBase.objects.filter(title__icontains=draft.name)
|
||||
|
@ -397,7 +396,7 @@ class IprTests(TestCase):
|
|||
# successful post
|
||||
empty_outbox()
|
||||
r = self.client.post(url, {
|
||||
"updates": str(original_ipr.pk),
|
||||
"updates": [original_ipr.pk],
|
||||
"holder_legal_name": "Test Legal",
|
||||
"holder_contact_name": "Test Holder",
|
||||
"holder_contact_email": "test@holder.com",
|
||||
|
@ -406,7 +405,7 @@ class IprTests(TestCase):
|
|||
"ietfer_contact_info": "555-555-0101",
|
||||
"iprdocrel_set-TOTAL_FORMS": 2,
|
||||
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||
"iprdocrel_set-0-document": "%s" % draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-document": draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-revisions": '00',
|
||||
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||
"patent_number": "SE12345678901",
|
||||
|
@ -437,13 +436,13 @@ class IprTests(TestCase):
|
|||
|
||||
empty_outbox()
|
||||
r = self.client.post(url, {
|
||||
"updates": "this is supposed to be an integer",
|
||||
"updates": "this is supposed to be an array of integers",
|
||||
"holder_legal_name": "Test Legal",
|
||||
"holder_contact_name": "Test Holder",
|
||||
"holder_contact_email": "test@holder.com",
|
||||
"iprdocrel_set-TOTAL_FORMS": 1,
|
||||
"iprdocrel_set-INITIAL_FORMS": 0,
|
||||
"iprdocrel_set-0-document": "%s" % draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-document": draft.docalias.first().pk,
|
||||
"iprdocrel_set-0-revisions": '00',
|
||||
"patent_number": "SE12345678901",
|
||||
"patent_inventor": "A. Nonymous",
|
||||
|
@ -456,7 +455,6 @@ class IprTests(TestCase):
|
|||
})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
# print(r.content)
|
||||
self.assertTrue(q("#id_updates").parents(".row").hasClass("is-invalid"))
|
||||
|
||||
def test_addcomment(self):
|
||||
|
@ -609,7 +607,6 @@ I would like to revoke this declaration.
|
|||
response_due=yesterday.isoformat())
|
||||
empty_outbox()
|
||||
r = self.client.post(url,data,follow=True)
|
||||
#print r.content
|
||||
self.assertEqual(r.status_code,200)
|
||||
q = Message.objects.filter(reply_to=data['reply_to'])
|
||||
self.assertEqual(q.count(),1)
|
||||
|
@ -665,7 +662,7 @@ Subject: test
|
|||
self.assertEqual(response.status_code,200)
|
||||
post_data = {
|
||||
'iprdocrel_set-TOTAL_FORMS' : 1,
|
||||
'iprdocrel_set-INITIAL_FORMS' : 1,
|
||||
'iprdocrel_set-INITIAL_FORMS' : 0,
|
||||
'iprdocrel_set-0-id': disclosure.pk,
|
||||
"iprdocrel_set-0-document": disclosure.docs.first().pk,
|
||||
"iprdocrel_set-0-revisions": disclosure.docs.first().document.rev,
|
||||
|
|
|
@ -1012,7 +1012,8 @@ class LiaisonManagementTests(TestCase):
|
|||
reply_from_group_id = str(liaison.to_groups.first().pk)
|
||||
self.assertEqual(q('#id_from_groups').find('option:selected').val(),reply_from_group_id)
|
||||
self.assertEqual(q('#id_to_groups').find('option:selected').val(),reply_to_group_id)
|
||||
self.assertEqual(q('#id_related_to').val(),str(liaison.pk))
|
||||
# FIXME-LARS need to check inside "data-pre" attribute
|
||||
# self.assertEqual(q('#id_related_to').val(),str(liaison.pk))
|
||||
|
||||
def test_search(self):
|
||||
# Statement 1
|
||||
|
@ -1159,4 +1160,4 @@ class LiaisonManagementTests(TestCase):
|
|||
|
||||
mailbox_before = len(outbox)
|
||||
possibly_send_deadline_reminder(liaison)
|
||||
self.assertEqual(len(outbox), mailbox_before)
|
||||
self.assertEqual(len(outbox), mailbox_before)
|
|
@ -43,6 +43,7 @@ if selenium_enabled():
|
|||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions
|
||||
from selenium.common.exceptions import NoSuchElementException, TimeoutException
|
||||
# from selenium.webdriver.common.keys import Keys
|
||||
|
||||
|
||||
@ifSeleniumEnabled
|
||||
|
@ -585,7 +586,8 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
|
|||
# option to swap. If we used the first or last day, a fencepost error in
|
||||
# disabling options by date might be hidden.
|
||||
clicked_index = 1
|
||||
future_swap_ts_buttons[clicked_index].click()
|
||||
self.driver.execute_script("arguments[0].click();", future_swap_ts_buttons[clicked_index]) # FIXME-LARS: not working:
|
||||
# future_swap_ts_buttons[clicked_index].click()
|
||||
try:
|
||||
modal = wait.until(
|
||||
expected_conditions.visibility_of_element_located(
|
||||
|
@ -998,7 +1000,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.driver.get(self.absreverse('ietf.meeting.views.agenda') + querystring)
|
||||
self.assert_agenda_item_visibility(visible_groups)
|
||||
self.assert_agenda_view_filter_matches_ics_filter(querystring)
|
||||
weekview_iframe = self.driver.find_element(By.ID, 'weekview')
|
||||
weekview_iframe = self.driver.find_element(By.CSS_SELECTOR, '#weekview iframe')
|
||||
if len(querystring) == 0:
|
||||
self.assertFalse(weekview_iframe.is_displayed(), 'Weekview should be hidden when filters off')
|
||||
else:
|
||||
|
@ -1215,7 +1217,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
"""Click the 'customize' anchor to reveal the group buttons"""
|
||||
customize_anchor = wait.until(
|
||||
expected_conditions.element_to_be_clickable(
|
||||
(By.CSS_SELECTOR, '#accordion a[data-bs-toggle="collapse"]')
|
||||
(By.CSS_SELECTOR, '#accordion button[data-bs-toggle="collapse"]')
|
||||
)
|
||||
)
|
||||
customize_anchor.click()
|
||||
|
@ -1390,7 +1392,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
# Click the 'customize' anchor to reveal the group buttons
|
||||
customize_anchor = WebDriverWait(self.driver, 2).until(
|
||||
expected_conditions.element_to_be_clickable(
|
||||
(By.CSS_SELECTOR, '#accordion a[data-bs-toggle="collapse"]')
|
||||
(By.CSS_SELECTOR, '#accordion button[data-bs-toggle="collapse"]')
|
||||
)
|
||||
)
|
||||
customize_anchor.click()
|
||||
|
@ -1612,13 +1614,11 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
)
|
||||
|
||||
tz_select_input = self.driver.find_element(By.ID, 'timezone-select')
|
||||
meeting_tz_link = self.driver.find_element(By.ID, 'meeting-timezone')
|
||||
local_tz_link = self.driver.find_element(By.ID, 'local-timezone')
|
||||
utc_tz_link = self.driver.find_element(By.ID, 'utc-timezone')
|
||||
tz_displays = self.driver.find_elements(By.CSS_SELECTOR, '.current-tz')
|
||||
self.assertGreaterEqual(len(tz_displays), 1)
|
||||
# we'll check that all current-tz elements are updated, but first check that at least one is in the nav sidebar
|
||||
self.assertIsNotNone(self.driver.find_element(By.CSS_SELECTOR, '.nav .current-tz'))
|
||||
meeting_tz_link = self.driver.find_element(By.CSS_SELECTOR, 'label[for="meeting-timezone"]')
|
||||
local_tz_link = self.driver.find_element(By.CSS_SELECTOR, 'label[for="local-timezone"]')
|
||||
utc_tz_link = self.driver.find_element(By.CSS_SELECTOR, 'label[for="utc-timezone"]')
|
||||
# we'll check that all tz-select elements are updated, but first check that at least one is in the nav sidebar
|
||||
self.assertIsNotNone(self.driver.find_element(By.CSS_SELECTOR, '.tz-select'))
|
||||
|
||||
# Moment.js guesses local time zone based on the behavior of Selenium's web client. This seems
|
||||
# to inherit Django's settings.TIME_ZONE but I don't know whether that's guaranteed to be consistent.
|
||||
|
@ -1636,8 +1636,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
# don't yet know local_tz, so can't check that it's deselected here
|
||||
self.assertFalse(arbitrary_tz_opt.is_selected())
|
||||
self.assertFalse(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), self.meeting.time_zone)
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), self.meeting.time_zone)
|
||||
|
||||
# Click 'local' button
|
||||
local_tz_link.click()
|
||||
|
@ -1646,8 +1645,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
# just identified the local_tz_opt as being selected, so no check here, either
|
||||
self.assertFalse(arbitrary_tz_opt.is_selected())
|
||||
self.assertFalse(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), local_tz)
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), local_tz)
|
||||
|
||||
# click 'utc' button
|
||||
utc_tz_link.click()
|
||||
|
@ -1656,8 +1654,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertFalse(local_tz_opt.is_selected()) # finally!
|
||||
self.assertFalse(arbitrary_tz_opt.is_selected())
|
||||
self.assertTrue(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), 'UTC')
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), 'UTC')
|
||||
|
||||
# click back to meeting
|
||||
meeting_tz_link.click()
|
||||
|
@ -1666,8 +1663,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertFalse(local_tz_opt.is_selected())
|
||||
self.assertFalse(arbitrary_tz_opt.is_selected())
|
||||
self.assertFalse(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), self.meeting.time_zone)
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), self.meeting.time_zone)
|
||||
|
||||
# and then back to UTC...
|
||||
utc_tz_link.click()
|
||||
|
@ -1676,8 +1672,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertFalse(local_tz_opt.is_selected())
|
||||
self.assertFalse(arbitrary_tz_opt.is_selected())
|
||||
self.assertTrue(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), 'UTC')
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), 'UTC')
|
||||
|
||||
# ... and test the switch from UTC to local
|
||||
local_tz_link.click()
|
||||
|
@ -1686,8 +1681,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertTrue(local_tz_opt.is_selected())
|
||||
self.assertFalse(arbitrary_tz_opt.is_selected())
|
||||
self.assertFalse(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), local_tz)
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), local_tz)
|
||||
|
||||
# Now select a different item from the select input
|
||||
arbitrary_tz_opt.click()
|
||||
|
@ -1696,8 +1690,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertFalse(local_tz_opt.is_selected())
|
||||
self.assertTrue(arbitrary_tz_opt.is_selected())
|
||||
self.assertFalse(utc_tz_opt.is_selected())
|
||||
for disp in tz_displays:
|
||||
self.assertEqual(disp.text.strip(), arbitrary_tz)
|
||||
self.assertEqual(self.driver.find_element(By.CSS_SELECTOR, '.tz-select option:checked').text.strip(), arbitrary_tz)
|
||||
|
||||
def test_agenda_time_zone_selection_updates_weekview(self):
|
||||
"""Changing the time zone should update the weekview to match"""
|
||||
|
@ -1727,7 +1720,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
# Now select a different item from the select input
|
||||
option.click()
|
||||
try:
|
||||
wait.until(in_iframe_href('tz=america/halifax', 'weekview'))
|
||||
wait.until(in_iframe_href('tz=america/halifax', self.driver.find_element(By.CSS_SELECTOR, '#weekview iframe')))
|
||||
except:
|
||||
self.fail('iframe href not updated to contain selected time zone')
|
||||
|
||||
|
@ -1763,8 +1756,8 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
farfut_button = self.driver.find_element(By.CSS_SELECTOR, 'button[data-filter-item="farfut"]')
|
||||
break_checkbox = self.driver.find_element(By.CSS_SELECTOR, 'input[type="checkbox"][name="selected-sessions"][data-filter-item="secretariat-sessb"]')
|
||||
registration_checkbox = self.driver.find_element(By.CSS_SELECTOR, 'input[type="checkbox"][name="selected-sessions"][data-filter-item="secretariat-sessa"]')
|
||||
self.driver.execute_script("arguments[0].click();", mars_sessa_checkbox) # select mars session; FIXME: no idea why a simple mars_sessa_checkbox.click() doesn't work
|
||||
|
||||
mars_sessa_checkbox.click() # select mars session
|
||||
try:
|
||||
wait.until(
|
||||
lambda driver: all('?show=mars-sessa' in el.get_attribute('href') for el in elements_to_check)
|
||||
|
@ -1776,7 +1769,7 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertFalse(break_checkbox.is_selected(), 'break checkbox was selected without being clicked')
|
||||
self.assertFalse(registration_checkbox.is_selected(), 'registration checkbox was selected without being clicked')
|
||||
|
||||
mars_sessa_checkbox.click() # deselect mars session
|
||||
self.driver.execute_script("arguments[0].click();", mars_sessa_checkbox) # deselect mars session
|
||||
try:
|
||||
wait.until(
|
||||
lambda driver: not any('?show=mars-sessa' in el.get_attribute('href') for el in elements_to_check)
|
||||
|
@ -1789,8 +1782,8 @@ class AgendaTests(IetfSeleniumTestCase):
|
|||
self.assertFalse(registration_checkbox.is_selected(), 'registration checkbox was selected without being clicked')
|
||||
|
||||
farfut_button.click() # turn on all farfut area sessions
|
||||
mars_sessa_checkbox.click() # but turn off mars session a
|
||||
break_checkbox.click() # also select the break
|
||||
self.driver.execute_script("arguments[0].click();", mars_sessa_checkbox) # but turn off mars session a
|
||||
self.driver.execute_script("arguments[0].click();", break_checkbox) # also select the break
|
||||
|
||||
try:
|
||||
wait.until(
|
||||
|
@ -2101,8 +2094,9 @@ class InterimTests(IetfSeleniumTestCase):
|
|||
button = self.wait.until(
|
||||
expected_conditions.element_to_be_clickable(
|
||||
(By.CSS_SELECTOR, 'div#calendar button.fc-next-button')))
|
||||
self.scroll_to_element(button)
|
||||
button.click()
|
||||
self.driver.execute_script("arguments[0].click();", button) # FIXME-LARS: no idea why this fails:
|
||||
# self.scroll_to_element(button)
|
||||
# button.click()
|
||||
|
||||
seen = set()
|
||||
not_visible = set()
|
||||
|
@ -2116,7 +2110,7 @@ class InterimTests(IetfSeleniumTestCase):
|
|||
# will usually contain the day 1 year from the start date.
|
||||
for _ in range(13):
|
||||
entries = self.driver.find_elements(By.CSS_SELECTOR,
|
||||
'div#calendar div.fc-content'
|
||||
'div#calendar div.fc-event-main'
|
||||
)
|
||||
for entry in entries:
|
||||
meetings = [m for m in visible_meetings if m.calendar_label in entry.text]
|
||||
|
@ -2447,7 +2441,7 @@ class InterimTests(IetfSeleniumTestCase):
|
|||
_assert_ietf_tz_correct(ietf_meetings, arbitrary_tz)
|
||||
|
||||
def test_upcoming_materials_modal(self):
|
||||
"""Test opening and closing a materals modal
|
||||
"""Test opening and closing a materials modal
|
||||
|
||||
This does not test dynamic reloading of the meeting materials - it relies on the main
|
||||
agenda page testing that. If the materials modal handling diverges between here and
|
||||
|
|
|
@ -406,7 +406,7 @@ class MeetingTests(BaseMeetingTestCase):
|
|||
url = urlreverse("ietf.meeting.views.week_view",kwargs=dict(num=meeting.number)) + "?show=farfut"
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
self.assertTrue(all([x in unicontent(r) for x in ['var all_items', 'maximize', 'draw_calendar', ]]))
|
||||
self.assertTrue(all([x in unicontent(r) for x in ['redraw_weekview', 'draw_calendar', ]]))
|
||||
|
||||
# Specifying a time zone should not change the output (time zones are handled by the JS)
|
||||
url = urlreverse("ietf.meeting.views.week_view",kwargs=dict(num=meeting.number)) + "?show=farfut&tz=Asia/Bangkok"
|
||||
|
@ -456,11 +456,11 @@ class MeetingTests(BaseMeetingTestCase):
|
|||
nav_tab_anchors = q('ul.nav.nav-tabs > li > a')
|
||||
for anchor in nav_tab_anchors.items():
|
||||
text = anchor.text().strip()
|
||||
if text in ['Agenda', 'UTC Agenda', 'Select Sessions']:
|
||||
if text in ['Agenda', 'UTC Agenda', 'Personalize Agenda']:
|
||||
expected_elements.append(anchor)
|
||||
for btn in q('.buttonlist a.btn').items():
|
||||
text = btn.text().strip()
|
||||
if text in ['View customized agenda', 'Download as .ics', 'Subscribe with webcal']:
|
||||
if text in ['View personal agenda', 'Download .ics of personal agenda', 'Subscribe to personal agenda']:
|
||||
expected_elements.append(btn)
|
||||
|
||||
# Check that all the expected elements have the correct classes
|
||||
|
@ -718,7 +718,7 @@ class MeetingTests(BaseMeetingTestCase):
|
|||
self.assertIn('%s?show=%s' % (ical_url, g.parent.acronym.lower()), content)
|
||||
|
||||
# The 'non-area events' are those whose keywords are in the last column of buttons
|
||||
na_col = q('#customize td.view:last-child') # find the column
|
||||
na_col = q('#customize .col-1:last') # find the column
|
||||
non_area_labels = [e.attrib['data-filter-item']
|
||||
for e in na_col.find('button.pickview')]
|
||||
assert len(non_area_labels) > 0 # test setup must produce at least one label for this test
|
||||
|
@ -3084,24 +3084,24 @@ class EditTests(TestCase):
|
|||
r, q = _set_date_offset_and_retrieve_page(meeting,
|
||||
0 - 2 - meeting.days, # Meeting ended 2 days ago
|
||||
self.client)
|
||||
self.assertTrue(q("""em:contains("You can't edit this schedule")"""))
|
||||
self.assertTrue(q("""em:contains("This is the official schedule for a meeting in the past")"""))
|
||||
self.assertTrue(q(""".alert:contains("You can't edit this schedule")"""))
|
||||
self.assertTrue(q(""".alert:contains("This is the official schedule for a meeting in the past")"""))
|
||||
|
||||
# 2) An ongoing meeting
|
||||
#######################################################
|
||||
r, q = _set_date_offset_and_retrieve_page(meeting,
|
||||
0, # Meeting starts today
|
||||
self.client)
|
||||
self.assertFalse(q("""em:contains("You can't edit this schedule")"""))
|
||||
self.assertFalse(q("""em:contains("This is the official schedule for a meeting in the past")"""))
|
||||
self.assertFalse(q(""".alert:contains("You can't edit this schedule")"""))
|
||||
self.assertFalse(q(""".alert:contains("This is the official schedule for a meeting in the past")"""))
|
||||
|
||||
# 3) A meeting in the future
|
||||
#######################################################
|
||||
r, q = _set_date_offset_and_retrieve_page(meeting,
|
||||
7, # Meeting starts next week
|
||||
self.client)
|
||||
self.assertFalse(q("""em:contains("You can't edit this schedule")"""))
|
||||
self.assertFalse(q("""em:contains("This is the official schedule for a meeting in the past")"""))
|
||||
self.assertFalse(q(""".alert:contains("You can't edit this schedule")"""))
|
||||
self.assertFalse(q(""".alert:contains("This is the official schedule for a meeting in the past")"""))
|
||||
|
||||
def test_edit_meeting_schedule(self):
|
||||
meeting = make_meeting_test_data()
|
||||
|
@ -3203,7 +3203,7 @@ class EditTests(TestCase):
|
|||
|
||||
self.assertEqual(len(q("#session{}.readonly".format(base_session.pk))), 1)
|
||||
|
||||
self.assertTrue(q("em:contains(\"You can't edit this schedule\")"))
|
||||
self.assertTrue(q(".alert:contains(\"You can't edit this schedule\")"))
|
||||
|
||||
# can't change anything
|
||||
r = self.client.post(url, {
|
||||
|
@ -3845,7 +3845,7 @@ class SessionDetailsTests(TestCase):
|
|||
r = self.client.post(url,dict(drafts=[new_draft.pk, old_draft.pk]))
|
||||
self.assertTrue(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertIn("Already linked:", q('form .alert-danger').text())
|
||||
self.assertIn("Already linked:", q('form .text-danger').text())
|
||||
|
||||
self.assertEqual(1,session.sessionpresentation_set.count())
|
||||
r = self.client.post(url,dict(drafts=[new_draft.pk,]))
|
||||
|
@ -6164,12 +6164,12 @@ class AgendaFilterTests(TestCase):
|
|||
# Test with/without custom button text
|
||||
context = Context({'customize_button_text': None, 'filter_categories': []})
|
||||
q = PyQuery(template.render(context))
|
||||
self.assertIn('Customize...', q('h4.card-title').text())
|
||||
self.assertIn('Customize...', q('h2.accordion-header').text())
|
||||
self.assertEqual(q('table'), []) # no filter_categories, so no button table
|
||||
|
||||
context['customize_button_text'] = 'My custom text...'
|
||||
q = PyQuery(template.render(context))
|
||||
self.assertIn(context['customize_button_text'], q('h4.card-title').text())
|
||||
self.assertIn(context['customize_button_text'], q('h2.accordion-header').text())
|
||||
self.assertEqual(q('table'), []) # no filter_categories, so no button table
|
||||
|
||||
# Now add a non-trivial set of filters
|
||||
|
@ -6251,24 +6251,24 @@ class AgendaFilterTests(TestCase):
|
|||
]
|
||||
|
||||
q = PyQuery(template.render(context))
|
||||
self.assertIn(context['customize_button_text'], q('h4.card-title').text())
|
||||
self.assertNotEqual(q('table'), []) # should now have table
|
||||
self.assertIn(context['customize_button_text'], q('h2.accordion-header').text())
|
||||
self.assertNotEqual(q('button.pickview'), []) # should now have group buttons
|
||||
|
||||
# Check that buttons are present for the expected things
|
||||
header_row = q('thead tr')
|
||||
self.assertEqual(len(header_row), 1)
|
||||
button_row = q('tbody tr')
|
||||
self.assertEqual(len(button_row), 1)
|
||||
header_row = q('.col-1 .row:first')
|
||||
self.assertEqual(len(header_row), 4)
|
||||
button_row = q('.row.view')
|
||||
self.assertEqual(len(button_row), 4)
|
||||
|
||||
# verify correct headers
|
||||
header_cells = header_row('th')
|
||||
self.assertEqual(len(header_cells), 6) # 4 columns and 2 spacers
|
||||
header_cells = header_row('.row')
|
||||
self.assertEqual(len(header_cells), 4)
|
||||
header_buttons = header_cells('button.pickview')
|
||||
self.assertEqual(len(header_buttons), 3) # last column has blank header, so only 3
|
||||
|
||||
# verify buttons
|
||||
button_cells = button_row('td')
|
||||
|
||||
button_cells = button_row('.btn-group-vertical')
|
||||
|
||||
# area0
|
||||
_assert_button_ok(header_cells.eq(0)('button.keyword0'),
|
||||
expected_label='area0',
|
||||
|
@ -6301,12 +6301,11 @@ class AgendaFilterTests(TestCase):
|
|||
expected_filter_keywords='keyword1,bof')
|
||||
|
||||
# area2
|
||||
# Skip column index 2, which is a spacer column
|
||||
_assert_button_ok(header_cells.eq(3)('button.keyword2'),
|
||||
_assert_button_ok(header_cells.eq(2)('button.keyword2'),
|
||||
expected_label='area2',
|
||||
expected_filter_item='keyword2')
|
||||
|
||||
buttons = button_cells.eq(3)('button.pickview')
|
||||
buttons = button_cells.eq(2)('button.pickview')
|
||||
self.assertEqual(len(buttons), 2) # two children
|
||||
_assert_button_ok(buttons('.keyword20'),
|
||||
expected_label='child20',
|
||||
|
@ -6318,9 +6317,8 @@ class AgendaFilterTests(TestCase):
|
|||
expected_filter_keywords='keyword2')
|
||||
|
||||
# area3 (no label for this one)
|
||||
# Skip column index 4, which is a spacer column
|
||||
self.assertEqual([], header_cells.eq(5)('button')) # no header button
|
||||
buttons = button_cells.eq(5)('button.pickview')
|
||||
self.assertEqual([], header_cells.eq(3)('button')) # no header button
|
||||
buttons = button_cells.eq(3)('button.pickview')
|
||||
self.assertEqual(len(buttons), 2) # two children
|
||||
_assert_button_ok(buttons('.keyword30'),
|
||||
expected_label='child30',
|
||||
|
|
|
@ -356,9 +356,7 @@ class NomcomViewsTest(TestCase):
|
|||
q = PyQuery(response.content)
|
||||
self.assertTrue(q("form .is-invalid"))
|
||||
|
||||
test_data = {"secondary_emails": """%s,
|
||||
%s,
|
||||
%s""" % (nominees[1], nominees[2], nominees[3]),
|
||||
test_data = {"secondary_emails": [nominees[1], nominees[2], nominees[3]],
|
||||
"primary_email": nominees[0]}
|
||||
|
||||
response = self.client.post(self.private_merge_nominee_url, test_data)
|
||||
|
@ -409,7 +407,7 @@ class NomcomViewsTest(TestCase):
|
|||
self.client.logout()
|
||||
|
||||
def change_members(self, members):
|
||||
members_emails = ','.join(['%s%s' % (member, EMAIL_DOMAIN) for member in members])
|
||||
members_emails = ['%s%s' % (member, EMAIL_DOMAIN) for member in members]
|
||||
test_data = {'members': members_emails,}
|
||||
self.client.post(self.edit_members_url, test_data)
|
||||
|
||||
|
@ -2539,7 +2537,7 @@ class VolunteerTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('#id_nomcoms div.checkbox')), 2)
|
||||
self.assertEqual(len(q('#id_nomcoms input[type="checkbox"]')), 2)
|
||||
r = self.client.post(url, dict(nomcoms=[nomcom.pk, nomcom2.pk], affiliation='something'))
|
||||
self.assertRedirects(r, reverse('ietf.ietfauth.views.profile'))
|
||||
self.assertEqual(person.volunteer_set.count(), 2)
|
||||
|
@ -2558,7 +2556,7 @@ class VolunteerTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('#id_nomcoms div.checkbox')), 1)
|
||||
self.assertEqual(len(q('#id_nomcoms input[type="checkbox"]')), 1)
|
||||
self.assertNotIn(f'{nomcom.year()}/', q('#already-volunteered').text())
|
||||
self.assertIn(f'{nomcom2.year()}/', q('#already-volunteered').text())
|
||||
|
||||
|
|
|
@ -35,10 +35,13 @@ def person_by_name(name):
|
|||
def person_link(person, **kwargs):
|
||||
title = kwargs.get('title', '')
|
||||
cls = kwargs.get('class', '')
|
||||
name = person.name if person.alias_set.filter(name=person.name).exists() else ''
|
||||
plain_name = person.plain_name()
|
||||
email = person.email_address()
|
||||
return {'name': name, 'plain_name': plain_name, 'email': email, 'title': title, 'class': cls}
|
||||
if person:
|
||||
name = person.name if person.alias_set.filter(name=person.name).exists() else ''
|
||||
plain_name = person.plain_name()
|
||||
email = person.email_address()
|
||||
return {'name': name, 'plain_name': plain_name, 'email': email, 'title': title, 'class': cls}
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
@register.inclusion_tag('person/person_link.html')
|
||||
|
|
|
@ -8,7 +8,7 @@ function getCookie(name) {
|
|||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = jQuery.trim(cookies[i]);
|
||||
var cookie = cookies[i].trim();
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
|
@ -104,7 +104,7 @@ function change_material_type(obj) {
|
|||
|
||||
function init_proceedings_upload() {
|
||||
// dynamic help message
|
||||
$('#id_material_type').change(function() {
|
||||
$('#id_material_type').on("change", function() {
|
||||
if(this.value == "slides") {
|
||||
//alert('Presentation handler called');
|
||||
$('div#id_file_help').html("Note 1: You can only upload a presentation file in txt, pdf, doc, or ppt/pptx. System will not accept presentation files in any other format.<br><br>Note 2: All uploaded files will be available to the public immediately on the Preliminary Page. However, for the Proceedings, ppt/pptx files will be converted to html format and doc files will be converted to pdf format manually by the Secretariat staff.");
|
||||
|
@ -168,21 +168,21 @@ function init_proceedings_table() {
|
|||
$(document).ready(function() {
|
||||
// set focus --------------------------------
|
||||
if ( $("form[id^=group-role-assignment-form]").length > 0) {
|
||||
$("#id_role_type").focus();
|
||||
$("#id_role_type").trigger("focus");
|
||||
} else if ( $("form[id=draft-search-form]").length > 0) {
|
||||
$("#id_filename").focus();
|
||||
$("#id_filename").trigger("focus");
|
||||
} else if ( $("form[id=drafts-add-form]").length > 0) {
|
||||
$("#id_title").focus();
|
||||
$("#id_title").trigger("focus");
|
||||
} else if ( $("form[id=proceedings-add-form]").length > 0) {
|
||||
$("#id_start_date").focus();
|
||||
$("#id_start_date").trigger("focus");
|
||||
} else if ( $("form[id=proceedings-upload-form]").length > 0) {
|
||||
$("#id_group_name").focus();
|
||||
$("#id_group_name").trigger("focus");
|
||||
} else if ( $("form[id=session-request-form]").length > 0) {
|
||||
$("#id_num_session").focus();
|
||||
$("#id_num_session").trigger("focus");
|
||||
} else if ( $(".rooms-times-nav").length > 0){
|
||||
$("li.selected a").focus();
|
||||
$("li.selected a").trigger("focus");
|
||||
} else {
|
||||
$("input:text:visible:enabled:first").focus();
|
||||
$("input:text:visible:enabled:first").trigger("focus");
|
||||
}
|
||||
|
||||
|
||||
|
@ -221,7 +221,7 @@ $(document).ready(function() {
|
|||
}
|
||||
|
||||
// auto populate Area Director List when primary area selected (add form)
|
||||
$('#id_primary_area').change(function(){
|
||||
$('#id_primary_area').on("change", function(){
|
||||
$.getJSON('/secr/groups/get_ads/',{"area":$(this).val()},function(data) {
|
||||
$('#id_primary_area_director option').remove();
|
||||
$.each(data,function(i,item) {
|
||||
|
@ -231,7 +231,7 @@ $(document).ready(function() {
|
|||
});
|
||||
|
||||
// auto populate Area Director List when area selected (edit form)
|
||||
$('#id_ietfwg-0-primary_area').change(function(){
|
||||
$('#id_ietfwg-0-primary_area').on("change", function(){
|
||||
$.getJSON('/secr/groups/get_ads/',{"area":$(this).val()},function(data) {
|
||||
$('#id_ietfwg-0-area_director option').remove();
|
||||
$.each(data,function(i,item) {
|
||||
|
@ -250,4 +250,4 @@ $(document).ready(function() {
|
|||
init_proceedings_upload();
|
||||
}
|
||||
|
||||
});
|
||||
});
|
|
@ -492,6 +492,9 @@ BOOTSTRAP5 = {
|
|||
# Field class to use in horiozntal forms
|
||||
'horizontal_field_class': 'col-md-10',
|
||||
|
||||
# Field class used for horizontal fields withut a label.
|
||||
'horizontal_field_offset_class': 'offset-md-2',
|
||||
|
||||
# Set placeholder attributes to label if no placeholder is provided
|
||||
'set_placeholder': False,
|
||||
|
||||
|
@ -500,7 +503,6 @@ BOOTSTRAP5 = {
|
|||
|
||||
'field_renderers': {
|
||||
'default': 'ietf.utils.bootstrap.SeparateErrorsFromHelpTextFieldRenderer',
|
||||
'inline': 'bootstrap5.renderers.InlineFieldRenderer',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
1
ietf/static/css/datepicker.scss
Normal file
1
ietf/static/css/datepicker.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import "~/node_modules/bootstrap-datepicker/dist/css//bootstrap-datepicker3.css";
|
0
ietf/static/css/edit-meeting-schedule.scss
Normal file
0
ietf/static/css/edit-meeting-schedule.scss
Normal file
|
@ -190,4 +190,647 @@ $timeline-even-hover-color: shift-color($timeline-even-color, $link-shade-percen
|
|||
|
||||
.position-norecord {
|
||||
// background-color: $secondary;
|
||||
}
|
||||
|
||||
/* === Edit Meeting Schedule ====================================== */
|
||||
|
||||
.edit-meeting-schedule .edit-grid {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .room-label-column {
|
||||
/* make sure we cut this column off - the time slots will determine
|
||||
how much of it is shown */
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 8em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day {
|
||||
margin-left: 1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .room-label-column .day {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-label {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-label .swap-days {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-label .swap-days:hover {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #swap-days-modal .modal-body label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-flow {
|
||||
margin-left: 8em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .room-group:not(:last-child) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .time-header {
|
||||
position: relative;
|
||||
height: 1.5em;
|
||||
padding-bottom: 0.15em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .time-header .time-label {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .time-header .time-label.would-violate-hint {
|
||||
background-color: #ffe0e0;
|
||||
outline: #ffe0e0 solid 0.4em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .time-header .time-label span {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslots {
|
||||
position: relative;
|
||||
height: 4.5em;
|
||||
padding-bottom: 0.15em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
background-color: #f4f4f4;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot .time-label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot .drop-target {
|
||||
position: relative;
|
||||
/* this is merely to make sure we are positioned above the time labels */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot.dropping {
|
||||
background-color: #ccc;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot.overfull {
|
||||
border-right: 0.3em dashed #f55000;
|
||||
/* cut-off illusion */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot.would-violate-hint {
|
||||
background-color: #ffe0e0;
|
||||
outline: #ffe0e0 solid 0.4em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot.would-violate-hint.dropping {
|
||||
background-color: #ccb3b3;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .constraints .encircled,
|
||||
.edit-meeting-schedule .formatted-constraints .encircled {
|
||||
border: 1px solid #000;
|
||||
border-radius: 1em;
|
||||
padding: 0 0.3em;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .formatted-constraints .encircled {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
/* sessions */
|
||||
.edit-meeting-schedule .session {
|
||||
background-color: #fff;
|
||||
margin: 0.2em;
|
||||
padding-right: 0.2em;
|
||||
padding-left: 0.5em;
|
||||
line-height: 1.3em;
|
||||
border-radius: 0.4em;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.selected {
|
||||
cursor: grabbing;
|
||||
outline: #0000ff solid 0.2em;
|
||||
/* blue, width matches margin on .session */
|
||||
z-index: 2;
|
||||
/* render above timeslot outlines */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.other-session-selected {
|
||||
outline: #00008b solid 0.2em;
|
||||
/* darkblue, width matches margin on .session */
|
||||
z-index: 2;
|
||||
/* render above timeslot outlines */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .read-only .session.selected {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.readonly {
|
||||
cursor: default;
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.hidden-parent * {
|
||||
/* This makes .session.hidden-parent's children transparent but keeps the
|
||||
* .session itself opaque so the timeslot label does not show through. */
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.selected .session-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.highlight {
|
||||
outline-color: #ff8c00;
|
||||
/* darkorange */
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.would-violate-hint {
|
||||
outline: 0.3em solid #F55000;
|
||||
z-index: 1;
|
||||
/* raise up so the outline is not overdrawn */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.highlight .session-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.dragging {
|
||||
opacity: 0.1;
|
||||
transition: opacity 0.4s;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .timeslot.overfull .session {
|
||||
border-radius: 0.4em 0 0 0.4em;
|
||||
/* remove right-side rounding to allude to being cut off */
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid,
|
||||
.edit-meeting-schedule .session {
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .session-label {
|
||||
flex-grow: 1;
|
||||
margin-left: 0.1em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .session-label .bof-tag {
|
||||
font-style: normal;
|
||||
font-size: smaller;
|
||||
color: #8b0000;
|
||||
font-weight: bold;
|
||||
float: right;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session.too-many-attendees .attendees {
|
||||
font-weight: bold;
|
||||
color: #8432d4;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .constraints {
|
||||
margin-right: 0.2em;
|
||||
text-align: right;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .constraints>span {
|
||||
display: none;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .constraints>span .encircled {
|
||||
border: 1px solid #b35eff;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .constraints>span.violated-hint {
|
||||
display: inline-block;
|
||||
color: #8432d4;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .constraints>span.would-violate-hint {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
color: #f55;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .constraints>span.would-violate-hint .encircled {
|
||||
border: 1px solid #f99;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions .session .constraints>span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .session-info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* scheduling panel */
|
||||
.edit-meeting-schedule .scheduling-panel {
|
||||
position: sticky;
|
||||
display: flex;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 0.2em solid #ccc;
|
||||
margin-bottom: 2em;
|
||||
background-color: #fff;
|
||||
opacity: 0.95;
|
||||
z-index: 5;
|
||||
/* raise above edit-grid items */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .unassigned-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions {
|
||||
margin-top: 0.5em;
|
||||
min-height: 4em;
|
||||
max-height: 13em;
|
||||
overflow-y: auto;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions.dropping {
|
||||
background-color: #e5e5e5;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions .drop-target {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
min-height: 5em;
|
||||
/* do not disappear when empty */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .preferences {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .preferences>span {
|
||||
margin-top: 0;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .sort-unassigned select {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body>div {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body .individual-timeslots {
|
||||
/*column-count: 3;*/
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body .individual-timeslots>* {
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body .individual-timeslots label {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session-parent-toggles {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .toggle-inputs label {
|
||||
font-weight: normal;
|
||||
margin-right: 1em;
|
||||
padding: 0 1em;
|
||||
border: 0.1em solid #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .modal .day-options {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .modal .timeslot-options {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .modal .room-group {
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .session-info-container {
|
||||
padding-left: 0.5em;
|
||||
flex: 0 0 25em;
|
||||
height: 20em;
|
||||
font-size: 14px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .session-info-container .comments {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .session-info-container .other-session:hover {
|
||||
cursor: default;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
/* A modified .container-fluid without padding on very narrow devices*/
|
||||
.container-fluid-narrow {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.container-fluid-narrow {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* === Edit Meeting Timeslots and Misc Sessions =================== */
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .day {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .day-label {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .room-row {
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .room-label {
|
||||
width: 12em;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeline {
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeline.hover {
|
||||
background: radial-gradient(#999 1px, transparent 1px);
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeline.selected.hover,
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeline.selected {
|
||||
background: radial-gradient(#999 2px, transparent 2px);
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeslot {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
background-color: #f0f0f0;
|
||||
opacity: 0.8;
|
||||
height: 19px;
|
||||
top: 0px;
|
||||
font-size: 13px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
padding-left: 0.2em;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #999;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeslot:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeslot.selected {
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .timeslot .session.cancelled {
|
||||
color: #a00;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 0.2em solid #ccc;
|
||||
padding-top: 0.2em;
|
||||
margin-bottom: 2em;
|
||||
background-color: #fff;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel form {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel form button {
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form .form-group {
|
||||
margin-right: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form label {
|
||||
display: inline-block;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form .form-control {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form [name=time],
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form [name=duration] {
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form [name=name] {
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.edit-meeting-timeslots-and-misc-sessions .scheduling-panel .flowing-form [name=short] {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable div.timeslot {
|
||||
border: #000000 solid 1px;
|
||||
border-radius: 0.5em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable .timeslot .ts-name {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable .timeslot .ts-type {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable .timeslot .timeslot-buttons {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable .timeslot.in-official-use {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable .timeslot.in-unofficial-use {
|
||||
background-color: #f8f8e0;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable td.timeslot-collision {
|
||||
background-color: #ffa0a0;
|
||||
}
|
||||
|
||||
.timeslot-edit .tstable .tstype_unavail {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.timeslot-edit .official-use-warning {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.rightmarker,
|
||||
.leftmarker {
|
||||
width: 3px;
|
||||
padding-right: 0px !important;
|
||||
padding-left: 0px !important;
|
||||
}
|
||||
|
||||
.ongoing>td:first-child {
|
||||
background-color: red !important;
|
||||
}
|
||||
|
||||
.ongoing>td:last-child {
|
||||
background-color: red !important;
|
||||
}
|
||||
|
||||
.timetooltip {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timetooltip .timetooltiptext {
|
||||
visibility: hidden;
|
||||
background-color: #eee;
|
||||
color: #000;
|
||||
text-align: left;
|
||||
border-radius: 6px;
|
||||
padding: 5px 5px;
|
||||
position: absolute;
|
||||
z-index: 110;
|
||||
bottom: 125%;
|
||||
left: 50%;
|
||||
margin-left: -60px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
width: 60em;
|
||||
}
|
||||
|
||||
.reschedtimetooltip .timetooltiptext {
|
||||
margin-left: -300px;
|
||||
}
|
||||
|
||||
.timetooltiptext table tr td {
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
.timetooltiptext table tr th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.timehead {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.timetooltip:hover .timetooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#current-time {
|
||||
display: inline-block;
|
||||
}
|
|
@ -1 +1,3 @@
|
|||
@import "~/node_modules/jquery-ui/themes/base/all.css";
|
||||
@import "~node_modules/jquery-ui-dist/jquery-ui.css";
|
||||
@import "~node_modules/jquery-ui-dist/jquery-ui.structure.css";
|
||||
@import "~node_modules/jquery-ui-dist/jquery-ui.theme.min.css";
|
|
@ -34,8 +34,11 @@ $(document)
|
|||
|
||||
function setSubmitButtonState() {
|
||||
var action;
|
||||
if (milestonesForm.find("input[name$=delete]:visible")
|
||||
.length > 0 || milestone_order_has_changed)
|
||||
var milestone_cnt = milestonesForm.find(".milestonerow").length;
|
||||
var milestone_hidden_cnt = milestonesForm.find(".edit-milestone.visually-hidden").length;
|
||||
var milestone_change_cnt = milestonesForm.find(".edit-milestone.changed").length;
|
||||
var milestone_delete_cnt = milestonesForm.find(".edit-milestone.delete").length;
|
||||
if (milestone_cnt != milestone_hidden_cnt || milestone_order_has_changed)
|
||||
action = "review";
|
||||
else
|
||||
action = "save";
|
||||
|
@ -45,11 +48,11 @@ $(document)
|
|||
|
||||
var submit = milestonesForm.find("[type=submit]");
|
||||
submit.text(submit.data("label" + action));
|
||||
if (milestonesForm.find(".edit-milestone.changed,.edit-milestone.delete")
|
||||
.length > 0 || action == "review")
|
||||
if (milestone_change_cnt + milestone_delete_cnt > 0 || action == "review") {
|
||||
submit.removeClass("visually-hidden");
|
||||
else
|
||||
} else {
|
||||
submit.addClass("visually-hidden");
|
||||
}
|
||||
}
|
||||
|
||||
milestonesForm.find(".milestone")
|
||||
|
@ -130,6 +133,7 @@ $(document)
|
|||
if (!group_uses_milestone_dates) {
|
||||
setOrderControlValue();
|
||||
}
|
||||
setSubmitButtonState();
|
||||
});
|
||||
|
||||
function setResolvedState() {
|
||||
|
|
85
ietf/static/js/edit_action_holders.js
Normal file
85
ietf/static/js/edit_action_holders.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
local_js = function () {
|
||||
let select2_elem = $('.select2-field');
|
||||
let role_ids = select2_elem.data('role-ids');
|
||||
|
||||
function update_selection(elem, entries, selected) {
|
||||
elem.children("option")
|
||||
.each(function () {
|
||||
if (entries.some(x => x == $(this)
|
||||
.val())) {
|
||||
$(this)
|
||||
.prop("selected", selected);
|
||||
}
|
||||
})
|
||||
.trigger('change');
|
||||
}
|
||||
|
||||
function add_ah(role) {
|
||||
if (role_ids[role]) {
|
||||
update_selection(select2_elem, role_ids[role], true);
|
||||
}
|
||||
}
|
||||
|
||||
function del_ah(role) {
|
||||
if (role_ids[role] && select2_elem.val()) {
|
||||
update_selection(select2_elem, role_ids[role], false);
|
||||
}
|
||||
}
|
||||
|
||||
function all_selected(elem, role) {
|
||||
if (!elem.val()) { return false; }
|
||||
let data_ids = elem.val()
|
||||
.map(Number);
|
||||
for (let ii = 0; ii < role_ids[role].length; ii++) {
|
||||
if (-1 === data_ids.indexOf(role_ids[role][ii])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function none_selected(elem, role) {
|
||||
if (!elem.val()) { return true; }
|
||||
|
||||
let data_ids = elem.val()
|
||||
.map(Number);
|
||||
for (let ii = 0; ii < role_ids[role].length; ii++) {
|
||||
if (-1 !== data_ids.indexOf(role_ids[role][ii])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function update_buttons() {
|
||||
for (let role_slug in role_ids) {
|
||||
if (!role_ids.hasOwnProperty(role_slug)) { return; }
|
||||
|
||||
if (all_selected(select2_elem, role_slug)) {
|
||||
$('#add-' + role_slug)
|
||||
.attr('disabled', true);
|
||||
} else {
|
||||
$('#add-' + role_slug)
|
||||
.attr('disabled', false);
|
||||
}
|
||||
|
||||
if (none_selected(select2_elem, role_slug)) {
|
||||
$('#del-' + role_slug)
|
||||
.attr('disabled', true);
|
||||
} else {
|
||||
$('#del-' + role_slug)
|
||||
.attr('disabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
select2_elem.on('change', update_buttons);
|
||||
$(document)
|
||||
.ready(update_buttons);
|
||||
|
||||
return {
|
||||
add_ah: add_ah,
|
||||
del_ah: del_ah
|
||||
};
|
||||
}();
|
90
ietf/static/js/edit_authors.js
Normal file
90
ietf/static/js/edit_authors.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
local_js = function () {
|
||||
const sortable_list_id = 'authors-list'; // id of the container element for Sortable
|
||||
const prefix = 'author'; // formset prefix - must match the prefix in the edit_authors() view
|
||||
var list_container;
|
||||
var form_counter;
|
||||
var author_template;
|
||||
var person_select2_input_selector = 'select.select2-field[name^="author-"][name$="-person"]';
|
||||
|
||||
function handle_drag_end() {
|
||||
// after dragging, set order inputs to match new positions in list
|
||||
$(list_container)
|
||||
.find('.draggable input[name^="' + prefix + '"][name$="ORDER"]')
|
||||
.each(
|
||||
function (index, elt) {
|
||||
$(elt)
|
||||
.val(index + 1);
|
||||
});
|
||||
}
|
||||
|
||||
function add_author() {
|
||||
// __prefix__ is the unique prefix for each list item, indexed from 0
|
||||
var new_html = $(author_template)
|
||||
.html()
|
||||
.replaceAll('__prefix__', form_counter.value);
|
||||
var new_elt = $(new_html);
|
||||
$(list_container)
|
||||
.append(new_elt);
|
||||
var new_person_select = new_elt.find(person_select2_input_selector);
|
||||
setupSelect2Field(new_person_select);
|
||||
new_person_select.on('change', person_changed);
|
||||
|
||||
var form_count = Number(form_counter.value);
|
||||
form_counter.value = String(form_count + 1);
|
||||
|
||||
new_elt[0].scrollIntoView(true);
|
||||
}
|
||||
|
||||
function update_email_options_cb_factory(email_select) {
|
||||
// factory method creates a closure for the callback
|
||||
return function (ajax_data) {
|
||||
// keep the first item - it's the 'blank' option
|
||||
$(email_select)
|
||||
.children()
|
||||
.not(':first')
|
||||
.remove();
|
||||
$.each(ajax_data, function (index, email) {
|
||||
$(email_select)
|
||||
.append(
|
||||
$('<option></option>')
|
||||
.attr('value', email.address)
|
||||
.text(email.address)
|
||||
);
|
||||
});
|
||||
if (ajax_data.length > 0) {
|
||||
$(email_select)
|
||||
.val(ajax_data[0].address);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function person_changed() {
|
||||
var person_elt = $(this);
|
||||
var email_select = $('#' + person_elt.attr('id')
|
||||
.replace(/-person$/, '-email'));
|
||||
$.get(
|
||||
ajax_url.replace('123454321', $(this)
|
||||
.val()),
|
||||
null,
|
||||
update_email_options_cb_factory(email_select)
|
||||
);
|
||||
}
|
||||
|
||||
list_container = document.getElementById(sortable_list_id);
|
||||
form_counter = document.getElementsByName(prefix + '-TOTAL_FORMS')[0];
|
||||
author_template = document.getElementById('empty-author-form');
|
||||
|
||||
Sortable.create(
|
||||
list_container, {
|
||||
handle: '.handle',
|
||||
onEnd: handle_drag_end
|
||||
});
|
||||
|
||||
// register handler
|
||||
$(person_select2_input_selector)
|
||||
.on('change', person_changed);
|
||||
|
||||
return {
|
||||
add_author: add_author
|
||||
};
|
||||
}();
|
|
@ -109,7 +109,7 @@ $(document)
|
|||
$(document)
|
||||
.ready(function () {
|
||||
var headings = $("#content")
|
||||
.find("h1, h2, h3, h4, h5, h6");
|
||||
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible");
|
||||
|
||||
if ($(headings)
|
||||
.length > 0 && $(headings)
|
||||
|
@ -132,7 +132,7 @@ $(document)
|
|||
</nav>
|
||||
</div>
|
||||
`))
|
||||
.find("h1, h2, h3, h4, h5, h6")
|
||||
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible")
|
||||
.each(function () {
|
||||
var id = $(this)
|
||||
.attr("id");
|
||||
|
|
21
ietf/static/js/jquery-ui.js
vendored
21
ietf/static/js/jquery-ui.js
vendored
|
@ -1,20 +1 @@
|
|||
var accordion = require("jquery-ui/ui/widgets/accordion");
|
||||
var autocomplete = require("jquery-ui/ui/widgets/autocomplete");
|
||||
var button = require("jquery-ui/ui/widgets/button");
|
||||
var checkboxradio = require("jquery-ui/ui/widgets/checkboxradio");
|
||||
var controlgroup = require("jquery-ui/ui/widgets/controlgroup");
|
||||
var datepicker = require("jquery-ui/ui/widgets/datepicker");
|
||||
var dialog = require("jquery-ui/ui/widgets/dialog");
|
||||
var draggable = require("jquery-ui/ui/widgets/draggable");
|
||||
var droppable = require("jquery-ui/ui/widgets/droppable");
|
||||
var menu = require("jquery-ui/ui/widgets/menu");
|
||||
var mouse = require("jquery-ui/ui/widgets/mouse");
|
||||
var progressbar = require("jquery-ui/ui/widgets/progressbar");
|
||||
var resizable = require("jquery-ui/ui/widgets/resizable");
|
||||
var selectable = require("jquery-ui/ui/widgets/selectable");
|
||||
var selectmenu = require("jquery-ui/ui/widgets/selectmenu");
|
||||
var slider = require("jquery-ui/ui/widgets/slider");
|
||||
var sortable = require("jquery-ui/ui/widgets/sortable");
|
||||
var spinner = require("jquery-ui/ui/widgets/spinner");
|
||||
var tabs = require("jquery-ui/ui/widgets/tabs");
|
||||
var tooltip = require("jquery-ui/ui/widgets/tooltip");
|
||||
import "jquery-ui-dist/jquery-ui.js";
|
|
@ -24,9 +24,8 @@ window.setupSelect2Field = function (e) {
|
|||
var maxEntries = e.data("max-entries");
|
||||
var options = e.data("pre");
|
||||
for (var id in options) {
|
||||
e.append(new Option(options[id].text, options[id].id, true, true));
|
||||
e.append(new Option(options[id].text, options[id].id, false, options[id].selected));
|
||||
}
|
||||
// e.trigger("change");
|
||||
|
||||
e.select2({
|
||||
multiple: maxEntries !== 1,
|
||||
|
|
62
ietf/static/js/upload-material.js
Normal file
62
ietf/static/js/upload-material.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright The IETF Trust 2021, All Rights Reserved
|
||||
(
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Hide the inactive input form-group
|
||||
* @param form form to process
|
||||
*/
|
||||
function showUrlOrFile(form) {
|
||||
const useUrlInput = form.elements.namedItem('id_use_url');
|
||||
const urlGroup = form.elements.namedItem('id_external_url')
|
||||
.closest('div');
|
||||
const fileGroup = form.elements.namedItem('id_file')
|
||||
.closest('div');
|
||||
|
||||
if (useUrlInput.checked) {
|
||||
urlGroup.hidden = false;
|
||||
fileGroup.hidden = true;
|
||||
} else {
|
||||
urlGroup.hidden = true;
|
||||
fileGroup.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch showUrlOrFile from a UI event on the enclosing form
|
||||
* @param evt change event instance
|
||||
*/
|
||||
function handleFormChange(evt) {
|
||||
showUrlOrFile(evt.currentTarget); // currentTarget is the form
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear hidden file input values before submitting form to avoid
|
||||
* needlessly sending a file when use_url is selected
|
||||
* @param evt submit event instance
|
||||
*/
|
||||
function handleFormSubmit(evt) {
|
||||
const form = evt.currentTarget;
|
||||
const fileInput = form.elements.namedItem('file');
|
||||
if (fileInput.hidden) {
|
||||
fileInput.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register event handlers and other initialization tasks.
|
||||
*/
|
||||
function initialize() {
|
||||
const forms = document.querySelectorAll('form.upload-material');
|
||||
for (let i = 0; i < forms.length; i++) {
|
||||
const form = forms[i];
|
||||
form.addEventListener('change', handleFormChange);
|
||||
form.addEventListener('submit', handleFormSubmit);
|
||||
showUrlOrFile(form);
|
||||
}
|
||||
}
|
||||
|
||||
initialize();
|
||||
}
|
||||
)();
|
|
@ -166,9 +166,8 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
r = self.client.post(url, files)
|
||||
if r.status_code != 302:
|
||||
q = PyQuery(r.content)
|
||||
print(q('div.is-invalid div.alert').text())
|
||||
|
||||
self.assertNoFormPostErrors(r, ".is-invalid,.alert-danger")
|
||||
print(q('div.invalid-feedback').text())
|
||||
self.assertNoFormPostErrors(r, ".invalid-feedback,.alert-danger")
|
||||
|
||||
for format in formats:
|
||||
self.assertTrue(os.path.exists(os.path.join(self.staging_dir, "%s-%s.%s" % (name, rev, format))))
|
||||
|
@ -232,12 +231,8 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
if r.status_code == 302:
|
||||
submission = Submission.objects.get(name=name)
|
||||
self.assertEqual(submission.submitter, email.utils.formataddr((submitter_name, submitter_email)))
|
||||
self.assertEqual(submission.replaces,
|
||||
",".join(
|
||||
d.name for d in DocAlias.objects.filter(
|
||||
pk__in=replaces.split(",") if replaces else []
|
||||
)
|
||||
))
|
||||
self.assertEqual([] if submission.replaces == "" else submission.replaces.split(','),
|
||||
[ d.name for d in DocAlias.objects.filter(pk__in=replaces) ])
|
||||
self.assertCountEqual(
|
||||
[str(r) for r in submission.external_resources.all()],
|
||||
[str(r) for r in extresources] if extresources else [],
|
||||
|
@ -296,7 +291,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
mailbox_before = len(outbox)
|
||||
replaced_alias = draft.docalias.first()
|
||||
r = self.supply_extra_metadata(name, status_url, author.ascii, author.email().address.lower(),
|
||||
replaces=str(replaced_alias.pk) + "," + str(sug_replaced_alias.pk))
|
||||
replaces=[str(replaced_alias.pk), str(sug_replaced_alias.pk)])
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
|
@ -400,7 +395,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
# supply submitter info, then draft should be in and ready for approval
|
||||
mailbox_before = len(outbox)
|
||||
self.client.login(username=username, password=username+'+password') # log in as the author
|
||||
r = self.supply_extra_metadata(name, status_url, author.ascii, author.email().address.lower(), replaces='')
|
||||
r = self.supply_extra_metadata(name, status_url, author.ascii, author.email().address.lower(), replaces=[])
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
|
||||
|
@ -446,7 +441,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
{'submitter-name': author.name,
|
||||
'submitter-email': username,
|
||||
'action': 'autopost',
|
||||
'replaces': ''})
|
||||
'replaces': []})
|
||||
# Attempt should fail and draft should remain in the uploaded state
|
||||
self.assertEqual(r.status_code, 403)
|
||||
submission = Submission.objects.get(name=name, rev=rev)
|
||||
|
@ -554,7 +549,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
# supply submitter info, then previous authors get a confirmation email
|
||||
mailbox_before = len(outbox)
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "submitter@example.com", replaces="")
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "submitter@example.com", replaces=[])
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
r = self.client.get(status_url)
|
||||
|
@ -752,7 +747,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
{'submitter-name': author.name,
|
||||
'submitter-email': 'submitter@example.com',
|
||||
'action': 'autopost',
|
||||
'replaces': ''})
|
||||
'replaces': []})
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
|
||||
|
@ -803,7 +798,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
# supply submitter info, then draft should be be ready for email auth
|
||||
mailbox_before = len(outbox)
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "submitter@example.com", replaces="")
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "submitter@example.com", replaces=[])
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
|
@ -862,7 +857,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
name, '00', author, formats=formats, base_filename='test_submission_no_org_or_address'
|
||||
)
|
||||
status_url = r['Location']
|
||||
r = self.supply_extra_metadata(name, status_url, 'Submitter name', 'submitter@example.com', replaces='')
|
||||
r = self.supply_extra_metadata(name, status_url, 'Submitter name', 'submitter@example.com', replaces=[])
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
# force post of submission
|
||||
|
@ -957,7 +952,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
SubmissionExtResource(name_id='faq', value='https://faq.example.com/'),
|
||||
SubmissionExtResource(name_id='wiki', value='https://wiki.example.com', display_name='Test Wiki'),
|
||||
]
|
||||
r = self.supply_extra_metadata(name, status_url, 'Submitter name', 'submitter@example.com', replaces='',
|
||||
r = self.supply_extra_metadata(name, status_url, 'Submitter name', 'submitter@example.com', replaces=[],
|
||||
extresources=resources)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r['Location']
|
||||
|
@ -985,7 +980,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
# supply submitter info, then draft should be be ready for email auth
|
||||
mailbox_before = len(outbox)
|
||||
r = self.supply_extra_metadata(name, status_url, author.name, username, replaces="")
|
||||
r = self.supply_extra_metadata(name, status_url, author.name, username, replaces=[])
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
|
@ -1041,7 +1036,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
SubmissionExtResource(name_id='faq', value='https://faq.example.com/'),
|
||||
SubmissionExtResource(name_id='wiki', value='https://wiki.example.com', display_name='Test Wiki'),
|
||||
]
|
||||
r = self.supply_extra_metadata(name, status_url, author.name, username, replaces='',
|
||||
r = self.supply_extra_metadata(name, status_url, author.name, username, replaces=[],
|
||||
extresources=resources)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r['Location']
|
||||
|
@ -1071,14 +1066,14 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
mailbox_before = len(outbox)
|
||||
|
||||
replaced_alias = draft.docalias.first()
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=str(replaced_alias.pk))
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=[str(replaced_alias.pk)])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, 'cannot replace itself')
|
||||
self._assert_extresources_in_table(r, [])
|
||||
self._assert_extresources_form(r, [])
|
||||
|
||||
replaced_alias = DocAlias.objects.get(name='draft-ietf-random-thing')
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=str(replaced_alias.pk))
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=[str(replaced_alias.pk)])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, 'cannot replace an RFC')
|
||||
self._assert_extresources_in_table(r, [])
|
||||
|
@ -1086,13 +1081,13 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
replaced_alias.document.set_state(State.objects.get(type='draft-iesg',slug='approved'))
|
||||
replaced_alias.document.set_state(State.objects.get(type='draft',slug='active'))
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=str(replaced_alias.pk))
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=[str(replaced_alias.pk)])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, 'approved by the IESG and cannot')
|
||||
self._assert_extresources_in_table(r, [])
|
||||
self._assert_extresources_form(r, [])
|
||||
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces='')
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=[])
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
r = self.client.get(status_url)
|
||||
|
@ -1145,7 +1140,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
# Update with an empty set of resources
|
||||
r = self.supply_extra_metadata(orig_draft.name, status_url, author.name, author.user.email,
|
||||
replaces='', extresources=[])
|
||||
replaces=[], extresources=[])
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r['Location']
|
||||
|
||||
|
@ -1179,7 +1174,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
status_url,
|
||||
"Submitter Name",
|
||||
"submitter@example.com",
|
||||
replaces=str(replaced_draft.docalias.first().pk),
|
||||
replaces=[str(replaced_draft.docalias.first().pk)],
|
||||
)
|
||||
|
||||
submission = Submission.objects.get(name=name, rev=rev)
|
||||
|
@ -1213,7 +1208,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
rev = '%02d'%(int(draft.rev)+1)
|
||||
status_url, author = self.do_submission(name, rev)
|
||||
mailbox_before = len(outbox)
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces='')
|
||||
r = self.supply_extra_metadata(name, status_url, "Submitter Name", "author@example.com", replaces=[])
|
||||
self.assertEqual(r.status_code, 302)
|
||||
status_url = r["Location"]
|
||||
r = self.client.get(status_url)
|
||||
|
@ -1336,7 +1331,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
"edit-pages": "123",
|
||||
"submitter-name": "Some Random Test Person",
|
||||
"submitter-email": "random@example.com",
|
||||
"replaces": str(draft.docalias.first().pk),
|
||||
"replaces": [str(draft.docalias.first().pk)],
|
||||
"edit-note": "no comments",
|
||||
"authors-0-name": "Person 1",
|
||||
"authors-0-email": "person1@example.com",
|
||||
|
@ -1346,7 +1341,7 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
"authors-2-email": "person3@example.com",
|
||||
"authors-prefix": ["authors-", "authors-0", "authors-1", "authors-2"],
|
||||
})
|
||||
self.assertNoFormPostErrors(r, ".is-invalid,.alert-danger")
|
||||
self.assertNoFormPostErrors(r, ".invalid-feedback,.alert-danger")
|
||||
|
||||
submission = Submission.objects.get(name=name)
|
||||
self.assertEqual(submission.title, "some title")
|
||||
|
@ -1599,8 +1594,8 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q("form .is-invalid")) > 0)
|
||||
m = q('div.is-invalid div.alert').text()
|
||||
self.assertTrue(len(q("form .invalid-feedback")) > 0)
|
||||
m = q('div.invalid-feedback').text()
|
||||
|
||||
return r, q, m
|
||||
|
||||
|
@ -1619,8 +1614,8 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q("form .is-invalid")) > 0)
|
||||
m = q('div.is-invalid div.alert').text()
|
||||
self.assertTrue(len(q("form .invalid-feedback")) > 0)
|
||||
m = q('div.invalid-feedback').text()
|
||||
|
||||
return r, q, m
|
||||
|
||||
|
@ -1672,12 +1667,11 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
with io.open(fn, 'w') as f:
|
||||
f.write("a" * 2000)
|
||||
files[format], author = submission_file(name, rev, group, format, "test_submission.%s" % format)
|
||||
|
||||
r = self.client.post(url, files)
|
||||
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
m = q('div.alert-danger').text()
|
||||
m = q('.text-danger').text()
|
||||
|
||||
self.assertIn('Unexpected files already in the archive', m)
|
||||
|
||||
|
@ -2064,24 +2058,23 @@ class SubmitTests(BaseSubmitTestCase):
|
|||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
q = PyQuery(r.content)
|
||||
|
||||
# The removed resource should appear once (for the doc current value), tagged as removed
|
||||
removed_div = q('td>div:contains("Resource to be removed")')
|
||||
self.assertEqual(len(removed_div), 1)
|
||||
self.assertEqual(len(removed_div('span.label:contains("Removed")')), 1)
|
||||
self.assertEqual(len(removed_div('span.label:contains("New")')), 0)
|
||||
self.assertEqual(len(removed_div('span.badge:contains("Removed")')), 1)
|
||||
self.assertEqual(len(removed_div('span.badge:contains("New")')), 0)
|
||||
|
||||
# The added resource should appear once (for the submission), tagged as new
|
||||
added_div = q('td>div:contains("Resource to be added")')
|
||||
self.assertEqual(len(added_div), 1)
|
||||
self.assertEqual(len(added_div('span.label:contains("Removed")')), 0)
|
||||
self.assertEqual(len(added_div('span.label:contains("New")')), 1)
|
||||
self.assertEqual(len(added_div('span.badge:contains("Removed")')), 0)
|
||||
self.assertEqual(len(added_div('span.badge:contains("New")')), 1)
|
||||
|
||||
# The kept resource should appear twice (once for the doc, once for the submission), with no tag
|
||||
kept_div = q('td>div:contains("Resource to be kept")')
|
||||
self.assertEqual(len(kept_div), 2)
|
||||
self.assertEqual(len(kept_div('span.label:contains("Removed")')), 0)
|
||||
self.assertEqual(len(kept_div('span.label:contains("New")')), 0)
|
||||
self.assertEqual(len(kept_div('span.badge:contains("Removed")')), 0)
|
||||
self.assertEqual(len(kept_div('span.badge:contains("New")')), 0)
|
||||
|
||||
class ApprovalsTestCase(BaseSubmitTestCase):
|
||||
def test_approvals(self):
|
||||
|
@ -2225,7 +2218,7 @@ class ApprovalsTestCase(BaseSubmitTestCase):
|
|||
r = self.client.post(url, dict(name="draft-test-nonexistingwg-something"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q("form .is-invalid")) > 0)
|
||||
self.assertTrue(len(q("form .invalid-feedback")) > 0)
|
||||
|
||||
# add
|
||||
name = "draft-ietf-mars-foo"
|
||||
|
@ -2659,7 +2652,7 @@ Subject: test
|
|||
r = self.client.post(url, files)
|
||||
if r.status_code != 302:
|
||||
q = PyQuery(r.content)
|
||||
print(q('div.is-invalid span.help-block div').text())
|
||||
print(q('div.invalid-feedback span.help-block div').text())
|
||||
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
{% endif %}
|
||||
<link rel="apple-touch-icon"
|
||||
href="{% static 'ietf/images/apple-touch-icon.png' %}"/>
|
||||
<script src="{% static 'ietf/js/ietf.js' %}"/></script>
|
||||
<script src="{% static 'ietf/js/ietf.js' %}"></script>
|
||||
</head>
|
||||
<body class="position-relative"
|
||||
data-group-menu-data-url="{% url 'ietf.group.views.group_menu_data' %}">
|
||||
|
@ -74,7 +74,7 @@
|
|||
in
|
||||
</a>
|
||||
{% endif %}
|
||||
<form class="d-flex d-none d-lg-block" action="/doc/search/">
|
||||
<form class="navbar-form d-flex d-none d-lg-block" action="/doc/search/">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
name="name"
|
||||
|
@ -116,7 +116,7 @@
|
|||
class="btn-close float-end"
|
||||
data-bs-dismiss="alert"
|
||||
aria-label="Close"></button>
|
||||
{{ message }}
|
||||
{{ message.message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% block content %}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
{% else %}
|
||||
{% regroup reqs by get_state_slug as grouped_reqs %}
|
||||
{% for req_group in grouped_reqs %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{req_group.grouper|capfirst}} BOF Requests</div>
|
||||
<div class="card-body">
|
||||
<table id="bofreqs-{{req_group.grouper}}" class="table table-sm table-striped tablesorter">
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{doc.name}}-{{doc.rev}}</div>
|
||||
<div class="card-body">
|
||||
{{ content|sanitize|safe }}
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
<div id='materials-content'>
|
||||
{% if doc.rev and content != None %}
|
||||
{% if content_is_html %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-body">
|
||||
{{ content|sanitize|safe }}
|
||||
</div>
|
||||
|
|
|
@ -1,38 +1,24 @@
|
|||
{# bs5ok #}
|
||||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load django_bootstrap5 %}
|
||||
|
||||
{% block title %}Change documents replaced by {{ doc }}{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media.css }}
|
||||
{% endblock %}
|
||||
|
||||
{% block pagehead %}{{ form.media.css }}{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Change documents replaced by<br><small class="text-muted">{{ doc }}</small></h1>
|
||||
|
||||
<h3>Instructions</h3>
|
||||
|
||||
<p class="alert alert-warning">Do not include <code>-00</code> and do not include a file extension like <code>.txt</code> in the document name.</p>
|
||||
|
||||
<h1>
|
||||
Change documents replaced by
|
||||
<br>
|
||||
<small class="text-muted">{{ doc }}</small>
|
||||
</h1>
|
||||
<h2>Instructions</h2>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{% bootstrap_form form %}
|
||||
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a class="btn btn-secondary float-end" href="{{ doc.get_absolute_url }}">Back</a>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
{% block js %}{{ form.media.js }}{% endblock %}
|
|
@ -1,23 +1,20 @@
|
|||
[# bs5ok #}
|
||||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load django_bootstrap5 %}
|
||||
|
||||
{% block title %}Change stream for {{ doc }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Change stream<br><small class="text-muted">{{ doc }}</small></h1>
|
||||
|
||||
<h1>
|
||||
Change stream
|
||||
<br>
|
||||
<small class="text-muted">{{ doc }}</small>
|
||||
</h1>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a class="btn btn-secondary float-end" href="{{ doc.get_absolute_url }}">Back</a>
|
||||
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -54,7 +54,7 @@
|
|||
{% endif %}
|
||||
</td>
|
||||
<td>{{ doc.intended_std_level.name }}</td>
|
||||
<td>{% person_link doc.ad %}</td>
|
||||
<td><a href="mailto:{{ doc.ad.email_address|urlencode }}">{{ doc.ad.plain_name }}</a><</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -1,138 +1,52 @@
|
|||
{# bs5ok #]}
|
||||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2020, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load django_bootstrap5 %}
|
||||
|
||||
{% block title %}
|
||||
Edit action holders for {{ titletext }}
|
||||
{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media.css}}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Edit action holders for {{ titletext }}{% endblock %}
|
||||
{% block pagehead %}{{ form.media.css }}{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Edit action holders<br><small class="text-muted">{{titletext}}</small></h1>
|
||||
|
||||
<h1>
|
||||
Edit action holders
|
||||
<br>
|
||||
<small class="text-muted">{{ titletext }}</small>
|
||||
</h1>
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="role-toolbar">Related people</label>
|
||||
<div class="btn-toolbar" role="toolbar" id="role-toolbar-{{ role_type_label|slugify }}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="role-toolbar">Related people</label>
|
||||
<div class="btn-toolbar"
|
||||
role="toolbar"
|
||||
id="role-toolbar-{{ role_type_label|slugify }}">
|
||||
{% for doc_role in role_labels %}
|
||||
<div class="btn-group-vertical btn-group-sm" role="group">
|
||||
<button type="button" class="btn btn-primary"
|
||||
id="add-{{ doc_role.slug }}"
|
||||
onclick="local_js.add_ah('{{ doc_role.slug }}')">
|
||||
<button type="button"
|
||||
class="btn btn-primary"
|
||||
id="add-{{ doc_role.slug }}"
|
||||
onclick="local_js.add_ah('{{ doc_role.slug }}')">
|
||||
Add {{ doc_role.label }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary"
|
||||
id="del-{{ doc_role.slug }}"
|
||||
onclick="local_js.del_ah('{{ doc_role.slug }}')">
|
||||
<button type="button"
|
||||
class="btn btn-primary"
|
||||
id="del-{{ doc_role.slug }}"
|
||||
onclick="local_js.del_ah('{{ doc_role.slug }}')">
|
||||
Remove {{ doc_role.label }}
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-primary" name="submit" value="Save">Submit</button>
|
||||
<a class="btn btn-secondary float-end" href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">Back</a>
|
||||
|
||||
|
||||
<a class="btn btn-secondary float-end"
|
||||
href="{% url "ietf.doc.views_doc.document_main" name=doc.canonical_name %}">
|
||||
Back
|
||||
</a>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ form.media.js }}
|
||||
<script type="text/javascript">
|
||||
local_js = function () {
|
||||
let select2_elem = $('.select2-field');
|
||||
let role_ids = select2_elem.data('role-ids');
|
||||
|
||||
/* Updates select2 selection in element elem. Data should be an array of
|
||||
* objects with id and text as keys. */
|
||||
function update_selection(elem, entries) {
|
||||
elem.val(entries.join(',')).trigger('change');
|
||||
}
|
||||
|
||||
function add_ah(role) {
|
||||
if (role_ids[role]) {
|
||||
let ids;
|
||||
if (select2_elem.val()) {
|
||||
ids = select2_elem.val().split(',').map(Number).concat(role_ids[role]);
|
||||
} else {
|
||||
ids = role_ids[role];
|
||||
}
|
||||
update_selection(select2_elem, ids);
|
||||
}
|
||||
}
|
||||
|
||||
function del_ah(role) {
|
||||
if (role_ids[role] && select2_elem.val()) {
|
||||
update_selection(select2_elem, select2_elem.val().split(',').filter(
|
||||
function(id){return -1 === role_ids[role].indexOf(Number(id))}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function all_selected(elem, role) {
|
||||
if (!elem.val()) {return false}
|
||||
|
||||
let data_ids = elem.val().split(',').map(Number);
|
||||
for (let ii=0; ii < role_ids[role].length; ii++) {
|
||||
if (-1 === data_ids.indexOf(role_ids[role][ii])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function none_selected(elem, role) {
|
||||
if (!elem.val()) {return true}
|
||||
|
||||
let data_ids = elem.val().split(',').map(Number);
|
||||
for (let ii=0; ii < role_ids[role].length; ii++) {
|
||||
if (-1 !== data_ids.indexOf(role_ids[role][ii])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function update_buttons() {
|
||||
for (let role_slug in role_ids) {
|
||||
if (!role_ids.hasOwnProperty(role_slug)) { return };
|
||||
|
||||
if (all_selected(select2_elem, role_slug)) {
|
||||
$('#add-' + role_slug).attr('disabled', true);
|
||||
} else {
|
||||
$('#add-' + role_slug).attr('disabled', false);
|
||||
}
|
||||
|
||||
if (none_selected(select2_elem, role_slug)) {
|
||||
$('#del-' + role_slug).attr('disabled', true);
|
||||
} else {
|
||||
$('#del-' + role_slug).attr('disabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
select2_elem.on('change', update_buttons);
|
||||
$(document).ready(update_buttons);
|
||||
|
||||
return {
|
||||
add_ah: add_ah, del_ah: del_ah
|
||||
};
|
||||
}();
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
<script src="{% static "ietf/js/edit_action_holders.js" %}"></script>
|
||||
{% endblock %}
|
|
@ -36,7 +36,7 @@
|
|||
{% bootstrap_form formset.management_form %}
|
||||
<div id="authors-list" class="well">
|
||||
{% for form in formset %}
|
||||
<div class="panel author-panel">
|
||||
<div class="card author-panel">
|
||||
<div class="card-body draggable">
|
||||
<span class="handle bi bi-list"></span>
|
||||
<div class="form-horizontal">
|
||||
|
@ -47,7 +47,7 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
<div id="empty-author-form" class="template">
|
||||
<div class="panel author-panel">
|
||||
<div class="card author-panel">
|
||||
<div class="card-body draggable">
|
||||
<span class="handle bi bi-list"></span>
|
||||
<div class="form-horizontal">
|
||||
|
@ -71,92 +71,9 @@
|
|||
{% block js %}
|
||||
<script src="{% static 'ietf/js/sortable.js' %}"></script>
|
||||
<script src="{% static 'ietf/js/select2.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
const local_js = (
|
||||
function () {
|
||||
const sortable_list_id = 'authors-list';{# id of the container element for Sortable #}
|
||||
const prefix = 'author'; {# formset prefix - must match the prefix in the edit_authors() view #}
|
||||
var list_container;
|
||||
var form_counter;
|
||||
var author_template;
|
||||
var ajax_url = '{% url "ietf.person.ajax.person_email_json" personid="123454321" %}';
|
||||
var person_select2_input_selector = 'input.select2-field[name^="author-"][name$="-person"]';
|
||||
|
||||
function handle_drag_end() {
|
||||
// after dragging, set order inputs to match new positions in list
|
||||
$(list_container).find('.draggable input[name^="' + prefix + '"][name$="ORDER"]').each(
|
||||
function (index, elt) {
|
||||
$(elt).val(index + 1);
|
||||
})
|
||||
}
|
||||
|
||||
function add_author() {
|
||||
// __prefix__ is the unique prefix for each list item, indexed from 0
|
||||
var new_html = $(author_template).html().replaceAll('__prefix__', form_counter.value);
|
||||
var new_elt = $(new_html)
|
||||
$(list_container).append(new_elt);
|
||||
var new_person_select = new_elt.find(person_select2_input_selector);
|
||||
setupSelect2Field(new_person_select);
|
||||
new_person_select.on('change', person_changed);
|
||||
|
||||
var form_count = Number(form_counter.value);
|
||||
form_counter.value = String(form_count + 1);
|
||||
|
||||
new_elt[0].scrollIntoView(true);
|
||||
}
|
||||
|
||||
function update_email_options_cb_factory(email_select) {
|
||||
// factory method creates a closure for the callback
|
||||
return function(ajax_data) {
|
||||
// keep the first item - it's the 'blank' option
|
||||
$(email_select).children().not(':first').remove();
|
||||
$.each(ajax_data, function(index, email) {
|
||||
$(email_select).append(
|
||||
$('<option></option>')
|
||||
.attr('value', email.address)
|
||||
.text(email.address)
|
||||
);
|
||||
});
|
||||
if (ajax_data.length > 0) {
|
||||
$(email_select).val(ajax_data[0].address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function person_changed(event) {
|
||||
var person_elt = $(this);
|
||||
var email_select = $('#' + person_elt.attr('id').replace(/-person$/, '-email'));
|
||||
$.get(
|
||||
ajax_url.replace('123454321', $(this).val()),
|
||||
null,
|
||||
update_email_options_cb_factory(email_select)
|
||||
);
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
list_container = document.getElementById(sortable_list_id)
|
||||
form_counter = document.getElementsByName(prefix + '-TOTAL_FORMS')[0];
|
||||
author_template = document.getElementById('empty-author-form');
|
||||
|
||||
Sortable.create(
|
||||
list_container,
|
||||
{
|
||||
handle: '.handle',
|
||||
onEnd: handle_drag_end
|
||||
});
|
||||
|
||||
// register handler
|
||||
$(person_select2_input_selector).on('change', person_changed);
|
||||
}
|
||||
|
||||
return {
|
||||
add_author: add_author,
|
||||
initialize: initialize
|
||||
}
|
||||
}
|
||||
)()
|
||||
|
||||
$(document).ready(local_js.initialize);
|
||||
var ajax_url = '{% url "ietf.person.ajax.person_email_json" personid="123454321" %}';
|
||||
</script>
|
||||
<script src="{% static 'ietf/js/edit_authors.js' %}"></script>
|
||||
|
||||
{% endblock %}
|
|
@ -20,7 +20,7 @@
|
|||
<div class="col-md-11">
|
||||
{% for letter in alphabet_blocks %}
|
||||
<div class="row anchor-target" id="{{letter.grouper}}">
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{letter.grouper}}</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-inline">
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
{% for label, groups in sections.items %}
|
||||
<div class="anchor-target" id="{{label}}">
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{label}}</div>
|
||||
<div class="card-body">
|
||||
|
||||
|
@ -56,7 +56,7 @@
|
|||
{% regroup groups by parent as grouped_by_areas %}
|
||||
{% for area_grouping in grouped_by_areas %}
|
||||
<div class="anchor-target" id="{{label}}-{{area_grouping.grouper.name|default:'unknown'|slugify}}">
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{area_grouping.grouper.name|default:'Unknown area'}}</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<div class="col-md-10">
|
||||
{% for role_name in role_groups %}
|
||||
<div class="row anchor-target" id="{{role_name.grouper|urlencode}}">
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{role_name.grouper}}{{role_name.list|pluralize}}</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-inline">
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<form class="review-requests" method="post">{% csrf_token %}
|
||||
|
||||
{% for r in review_requests %}
|
||||
<div class="panel review-request">
|
||||
<div class="card review-request">
|
||||
<div class="card-header">
|
||||
|
||||
<h5 class="card-title">
|
||||
|
|
|
@ -1,48 +1,35 @@
|
|||
{# bs5ok #}
|
||||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load ietf_filters %}
|
||||
{% load django_bootstrap5 %}
|
||||
|
||||
{% block title %}Manage {{ group.name }} RFC stream{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media.css }}
|
||||
{% endblock %}
|
||||
|
||||
{% block pagehead %}{{ form.media.css }}{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>Manage {{ group.name }} RFC stream</h1>
|
||||
|
||||
<p>
|
||||
<b>Chair{{ chairs|pluralize }}:</b>
|
||||
{% for chair in chairs %}
|
||||
{{ chair.person.plain_name }} <{{ chair.address }}>
|
||||
{% if not forloop.last %}, {% endif %}
|
||||
{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Delegates can be assigned with permission to do the tasks of the
|
||||
chair{{ chairs|pluralize }}. Note that in order to actually do so, the delegates need a
|
||||
datatracker account. New accounts can be <a href="{% url "ietf.ietfauth.views.create_account" %}">created here</a>.
|
||||
datatracker account. New accounts can be
|
||||
<a href="{% url "ietf.ietfauth.views.create_account" %}">created here</a>
|
||||
.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a class="btn btn-secondary float-end" href="{% url "ietf.group.views.streams" %}{{ group.acronym }}">Back</a>
|
||||
|
||||
|
||||
|
||||
<a class="btn btn-secondary float-end"
|
||||
href="{% url "ietf.group.views.streams" %}{{ group.acronym }}">Back</a>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
{% block js %}{{ form.media.js }}{% endblock %}
|
|
@ -13,7 +13,7 @@
|
|||
<h1>Milestones under review</h1>
|
||||
|
||||
{% for ad in ads %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{ ad.plain_name }}</div>
|
||||
<div class="card-body">
|
||||
{% for g in ad.groups_needing_review %}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
{% endif %}
|
||||
|
||||
<div class="alert alert-info">This form will link additional drafts to this session with a revision of "Current at time of presentation". For more fine grained control of versions, or to remove a draft from a session, adjust the sessions associated with a draft from the draft's main page.</div>
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Drafts already linked to this sesssion</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
|
@ -37,7 +37,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Additional drafts to link to this session</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#weekview iframe { height: 25em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyAttrs %}data-bs-spy="scroll" data-bs-target="#affix" data-bs-offset="0" tabindex="0"{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
|
||||
|
@ -523,7 +521,6 @@
|
|||
{% if personalize %}
|
||||
agenda_filter.set_update_callback(function (e) {
|
||||
handleFilterParamUpdate(e);
|
||||
update_view(e);
|
||||
});
|
||||
|
||||
document.getElementById('agenda-table')
|
||||
|
|
|
@ -5,7 +5,7 @@ Required parameter: meeting - meeting being displayed
|
|||
{% endcomment %}
|
||||
{% load agenda_custom_tags %}
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-3 buttonlist">
|
||||
<a class="btn btn-sm btn-outline-primary visually-hidden ical-link agenda-link filterable"
|
||||
href="{% webcal_url 'ietf.meeting.views.agenda_ical' num=meeting.number %}">
|
||||
Subscribe to personal agenda
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
.edit-meeting-schedule .edit-grid .timeslot.hidden-timeslot-type .time-label { color: transparent; ); }
|
||||
.edit-meeting-schedule .session.hidden-purpose,
|
||||
.edit-meeting-schedule .session.hidden-timeslot-type { filter: blur(3px); }
|
||||
{% endblock morecss %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ schedule.name }}: IETF {{ meeting.number }} meeting agenda{% endblock %}
|
||||
|
||||
|
@ -44,35 +44,29 @@
|
|||
|
||||
<p class="float-end">
|
||||
{% if can_edit_properties %}
|
||||
<a href="{% url "ietf.meeting.views.edit_schedule_properties" schedule.meeting.number schedule.owner_email schedule.name %}">Edit properties</a>
|
||||
·
|
||||
<a class="btn btn-primary" href="{% url "ietf.meeting.views.edit_schedule_properties" schedule.meeting.number schedule.owner_email schedule.name %}">Edit properties</a>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<a href="{% url "ietf.meeting.views.new_meeting_schedule" num=meeting.number owner=schedule.owner_email name=schedule.name %}">Copy agenda</a>
|
||||
·
|
||||
<a class="btn btn-primary" href="{% url "ietf.meeting.views.new_meeting_schedule" num=meeting.number owner=schedule.owner_email name=schedule.name %}">Copy agenda</a>
|
||||
|
||||
<a href="{% url "ietf.meeting.views.list_schedules" num=meeting.number %}">Other Agendas</a>
|
||||
|
||||
<a class="btn btn-primary" href="{% url "ietf.meeting.views.list_schedules" num=meeting.number %}">Other Agendas</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<h1>
|
||||
Agenda name: {{ schedule.name }}
|
||||
|
||||
·
|
||||
|
||||
Owner: {{ schedule.owner }}
|
||||
|
||||
<br>
|
||||
<small class="text-muted">
|
||||
Owner: {{ schedule.owner }}</small>
|
||||
</h1>
|
||||
{% if not can_edit %}
|
||||
·
|
||||
|
||||
<strong>
|
||||
<em>
|
||||
<div class="alert alert-info">
|
||||
You can't edit this schedule.
|
||||
{% if schedule.is_official_record %}This is the official schedule for a meeting in the past.{% endif %}
|
||||
Make a <a href="{% url "ietf.meeting.views.new_meeting_schedule" num=meeting.number owner=schedule.owner_email name=schedule.name %}">new agenda from this</a>.
|
||||
</em>
|
||||
</strong>
|
||||
</div>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="edit-grid {% if not can_edit %}read-only{% endif %}">
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<span class="time pull-right"></span>
|
||||
{{ session.scheduling_label }} · {{ session.requested_duration_in_hours }}h
|
||||
{% if session.purpose_label %} · {{ session.purpose_label }} {% endif %}
|
||||
{% if session.attendees != None %} · {{ session.attendees }} <i class="fa fa-user-o"></i> {% endif %}
|
||||
{% if session.attendees != None %} · {{ session.attendees }} <i class="bi bi-person"></i> {% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<div class="panel col-md-5">
|
||||
<div class="card col-md-5">
|
||||
<div class="card-header">
|
||||
Finalize IETF{{meeting.number}} Proceedings
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
{# Note: if called with show_agenda=True, calling template must load agenda_materials.js, needed by session_agenda_include.html #}
|
||||
{% include "meeting/session_agenda_include.html" with slug=item.slug session=session timeslot=item.timeslot only %}
|
||||
<!-- agenda pop-up button -->
|
||||
<a data-bs-toggle="modal" data-bs-target="#modal-{{item.slug}}" title="Show meeting materials"><span class="bi bi-arrows-fullscreen"></span></a>
|
||||
<a data-bs-toggle="modal" data-bs-target="#modal-{{item.slug}}"><span title="Show meeting materials" class="bi bi-arrows-fullscreen"></span></a>
|
||||
<!-- materials tar file -->
|
||||
<a href="/meeting/{{meeting.number}}/agenda/{{acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="bi bi-file-zip"></span></a>
|
||||
<!-- materials PDF file -->
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyAttrs %}data-bs-spy="scroll" data-bs-target="#affix"{% endblock %}
|
||||
|
||||
{% block title %}IETF {{ meeting.number }} preliminary & interim materials{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -286,4 +284,4 @@
|
|||
|
||||
{% block js %}
|
||||
<script src="{% static "ietf/js/list.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -54,30 +54,30 @@
|
|||
{% if user|has_role:"Secretariat,Area Director,IAB" %}
|
||||
{% if schedule != meeting.schedule %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "by-room" %}active{% endif %}"
|
||||
<a class="nav-link {% if selected == "by-room" %}active{% endif %}"
|
||||
href="{% url 'ietf.meeting.views.agenda_by_room' num=meeting.number name=schedule.name owner=schedule.owner.email %}">by
|
||||
Room</a></li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "by-type" %}active{% endif %}"
|
||||
<a class="nav-link {% if selected == "by-type" %}active{% endif %}"
|
||||
href="{% url 'ietf.meeting.views.agenda_by_type' num=meeting.number name=schedule.name owner=schedule.owner.email %}">by
|
||||
Type</a></li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "room-view" %}active{% endif %}"
|
||||
<a class="nav-link {% if selected == "room-view" %}active{% endif %}"
|
||||
href="{% url 'ietf.meeting.views.room_view' num=meeting.number name=schedule.name owner=schedule.owner.email %}">Room
|
||||
grid</a></li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "by-room" %}active{% endif %}" href="{% url 'ietf.meeting.views.agenda_by_room' num=meeting.number %}">by Room</a></li>
|
||||
<a class="nav-link {% if selected == "by-room" %}active{% endif %}" href="{% url 'ietf.meeting.views.agenda_by_room' num=meeting.number %}">by Room</a></li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "by-type" %}active{% endif %}" href="{% url 'ietf.meeting.views.agenda_by_type' num=meeting.number %}">by Type</a></li>
|
||||
<a class="nav-link {% if selected == "by-type" %}active{% endif %}" href="{% url 'ietf.meeting.views.agenda_by_type' num=meeting.number %}">by Type</a></li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "room-view" %}active{% endif %}" href="{% url 'ietf.meeting.views.room_view' num=meeting.number %}">Room grid</a></li>
|
||||
<a class="nav-link {% if selected == "room-view" %}active{% endif %}" href="{% url 'ietf.meeting.views.room_view' num=meeting.number %}">Room grid</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link agenda-link filterable {% if selected == "floor-plan" %}active{% endif %}" href="{% url 'ietf.meeting.views.floor_plan' num=meeting.number %}">Floor plan</a></li>
|
||||
<a class="nav-link {% if selected == "floor-plan" %}active{% endif %}" href="{% url 'ietf.meeting.views.floor_plan' num=meeting.number %}">Floor plan</a></li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link"agenda-link filterable href="{% url 'ietf.meeting.views.agenda' num=meeting.number ext='.txt' %}">
|
||||
<a class="nav-link" href="{% url 'ietf.meeting.views.agenda' num=meeting.number ext='.txt' %}">
|
||||
Plaintext
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyAttrs %}data-bs-spy="scroll" data-bs-target="#affix"{% endblock %}
|
||||
|
||||
{% block title %}Past Meetings{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -71,4 +69,4 @@
|
|||
|
||||
{% block js %}
|
||||
<script src="{% static "ietf/js/list.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -14,7 +14,7 @@
|
|||
<h1>
|
||||
{% block content_header %}
|
||||
Edit Proceedings Material<br>
|
||||
<small>
|
||||
<small class="text-muted">
|
||||
{{ meeting }} {{ material_type.name }}
|
||||
</small>
|
||||
{% endblock %}
|
||||
|
@ -58,4 +58,4 @@
|
|||
{% endblock %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock content %}
|
||||
{% endblock content %}
|
|
@ -18,7 +18,7 @@
|
|||
{% endif %}
|
||||
|
||||
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Proceedings Materials</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
{# bs5ok #}
|
||||
{% extends "meeting/proceedings/edit_material_base.html" %}
|
||||
{# Copyright The IETF Trust 2015-2021, All Rights Reserved #}
|
||||
|
||||
{% load django_bootstrap5 %}
|
||||
|
||||
{% block morecss %}
|
||||
{{ form.media.css }}
|
||||
{% endblock %}
|
||||
{% block title %}
|
||||
Upload {{ material_type.name }} for {{ meeting }} Proceedings
|
||||
{% endblock %}
|
||||
|
||||
{% block morecss %}{{ form.media.css }}{% endblock %}
|
||||
{% block title %}Upload {{ material_type.name }} for {{ meeting }} Proceedings{% endblock %}
|
||||
{% block content_header %}
|
||||
Upload Proceedings Material<br>
|
||||
<small>
|
||||
{{ meeting }} {{ material_type.name }}
|
||||
</small>
|
||||
Upload Proceedings Material
|
||||
<br>
|
||||
<small class="text-muted">{{ meeting }} {{ material_type.name }}</small>
|
||||
{% endblock %}
|
||||
|
||||
{% block intro %}
|
||||
<p>
|
||||
{% if material is None %}
|
||||
|
@ -28,16 +20,11 @@
|
|||
{% endif %}
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block edit_form %}
|
||||
<form class="upload-material" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
{% block form_buttons %}{{ block.super }}{% endblock %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ form.media.js }}
|
||||
{% endblock %}
|
||||
{% block js %}{{ form.media.js }}{% endblock %}
|
|
@ -8,8 +8,6 @@
|
|||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyAttrs %}data-bs-spy="scroll" data-bs-target="#affix"{% endblock %}
|
||||
|
||||
{% block title %}IETF {{ meeting.number }} timeslot requests{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -142,4 +140,4 @@
|
|||
|
||||
{% block js %}
|
||||
<script src="{% static "ietf/js/list.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -15,7 +15,7 @@
|
|||
{% endif %}
|
||||
|
||||
{% for schedules, own, label in schedule_groups %}
|
||||
<div class="panel">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
{{ label }}
|
||||
{% if own %}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
{% with acronym=session.historic_group.acronym %}
|
||||
{% if session.agenda and show_agenda %}
|
||||
<!-- agenda pop-up button -->
|
||||
<a class="btn btn-outline-primary" role="button" data-bs-toggle="modal" data-bs-target="#modal-{{slug}}" title="Show meeting materials"><span class="bi bi-arrows-fullscreen"></span></a>
|
||||
<button class="btn btn-outline-primary" role="button" data-bs-toggle="modal" data-bs-target="#modal-{{slug}}"><span title="Show meeting materials" class="bi bi-arrows-fullscreen"></span></button>
|
||||
<!-- materials tar file -->
|
||||
<a class="btn btn-outline-primary" role="button" href="/meeting/{{meeting.number}}/agenda/{{acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="bi bi-file-zip"></span></a>
|
||||
<!-- materials PDF file -->
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
{% with use_panels=unscheduled_sessions %}
|
||||
{% if use_panels %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Scheduled Sessions</div>
|
||||
<div class="card-body">
|
||||
{% endif %}
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Agenda, Minutes, and Bluesheets</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
|
@ -93,7 +93,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header" data-bs-toggle="tooltip" title="Drag and drop to reorder slides">Slides</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped slides" id="slides_{{session.pk}}">
|
||||
|
@ -125,7 +125,7 @@
|
|||
<div class="small">Drag-and-drop to reorder slides</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Drafts
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
<th class="day-label"
|
||||
colspan="{{date_slices|colWidth:day}}">
|
||||
{{day|date:'D'}} ({{day}})
|
||||
<span class="fa fa-trash delete-button"
|
||||
<span class="bi bi-trash delete-button"
|
||||
title="Delete all on this day"
|
||||
data-delete-scope="day"
|
||||
data-date-id="{{ day.isoformat }}">
|
||||
|
@ -85,7 +85,7 @@
|
|||
{% for slot in slot_slices|lookup:day %}
|
||||
<th class="time-label">
|
||||
{{slot.time|date:'H:i'}}-{{slot.end_time|date:'H:i'}}
|
||||
<span class="fa fa-trash delete-button"
|
||||
<span class="bi bi-trash delete-button"
|
||||
data-delete-scope="column"
|
||||
data-date-id="{{ day.isoformat }}"
|
||||
data-col-id="{{ day.isoformat }}T{{slot.time|date:'H:i'}}-{{slot.end_time|date:'H:i'}}"
|
||||
|
@ -118,7 +118,7 @@
|
|||
{% endif %}
|
||||
<a class="new-timeslot-link {% if cell_ts %}hidden{% endif %}"
|
||||
href="{% url "ietf.meeting.views.create_timeslot" num=meeting.number %}?day={{ day.toordinal }}&date={{ day|date:"Y-m-d" }}&location={{ room.pk }}&time={{ slot.time|date:'H:i' }}&duration={{ slot.duration }}">
|
||||
<span class="fa fa-plus-square"></span>
|
||||
<span class="bi bi-plus-square"></span>
|
||||
</a>
|
||||
{% endwith %}{% endfor %}
|
||||
</td>
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
</div>
|
||||
<div class="timeslot-buttons">
|
||||
<a href="{% url 'ietf.meeting.views.edit_timeslot' num=ts.meeting.number slot_id=ts.id %}">
|
||||
<span class="fa fa-pencil-square-o"></span>
|
||||
<span class="bi bi-pencil"></span>
|
||||
</a>
|
||||
<span class="fa fa-trash delete-button" data-delete-scope="timeslot" title="Delete this timeslot"></span>
|
||||
<span class="bi bi-trash delete-button" data-delete-scope="timeslot" title="Delete this timeslot"></span>
|
||||
</div>
|
||||
<div class="ts-type">{{ ts.type }}</div>
|
||||
</div>
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
||||
<link rel="stylesheet" href="{% static "ietf/css/fullcalendar.css" %}">
|
||||
|
||||
<link rel="stylesheet" href="{% static "ietf/js/fullcalendar.css" %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Upcoming Meetings{% endblock %}
|
||||
|
@ -35,12 +34,7 @@
|
|||
{% block content %}
|
||||
{% origin %}
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<h1>Upcoming Meetings</h1>
|
||||
</div>
|
||||
<div class="title-buttons col-xs-6">
|
||||
<div>
|
||||
<a title="iCalendar subscription for upcoming meetings" href="webcal://{{request.get_host}}{% url 'ietf.meeting.views.upcoming_ical' %}">
|
||||
<i class="bi bi-share"></i>
|
||||
|
@ -62,8 +56,6 @@
|
|||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>For more on regular IETF meetings see <a href="https://www.ietf.org/meeting/upcoming.html">here</a></p>
|
||||
<p>Meeting important dates are not included in upcoming meeting calendars. They have <a href="{% url 'ietf.meeting.views.important_dates' %}">their own calendar</a></p>
|
||||
|
||||
|
@ -150,10 +142,8 @@
|
|||
<h3>No upcoming meetings</h3>
|
||||
{% endif %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<div class="tz-display text-right">
|
||||
<label for="timezone-select-bottom">Time zone: </label>
|
||||
<small>
|
||||
|
@ -162,13 +152,10 @@
|
|||
</small>
|
||||
<select class="tz-select" id="timezone-select-bottom"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<div id="calendar"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
|
@ -279,14 +266,14 @@
|
|||
*/
|
||||
var calendarEl = document.getElementById('calendar')
|
||||
event_calendar = new FullCalendar(calendarEl, {
|
||||
plugins: ['dayGridPlugin'],
|
||||
plugins: [ dayGridPlugin ],
|
||||
initialView: 'dayGridMonth',
|
||||
// displayEventTime: false,
|
||||
// events: function (fInfo, success) {success(display_events)},
|
||||
// eventRender: function (info) {
|
||||
// $(info.el).tooltip({ title: info.event.title })
|
||||
// },
|
||||
// timeFormat: 'H:mm',
|
||||
displayEventTime: false,
|
||||
events: function (fInfo, success) {success(display_events)},
|
||||
eventDidMount: function (info) {
|
||||
$(info.el).tooltip({ title: info.event.title })
|
||||
},
|
||||
eventDisplay: 'block'
|
||||
})
|
||||
event_calendar.render()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}{% origin %}
|
||||
{% load static %}
|
||||
{# FIXME: the weekview only renders correctly in quirks mode, i.e., not in HTML5 #}
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header"><h3>{{title}}</h3></div>
|
||||
<div class="card-body">
|
||||
{% for n in list %}{{n.email.address}}{% if not forloop.last %}, {%endif %}{% endfor %}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
{% with title='Accepted Nominees Without a Questionnaire Response' list=noresp %}
|
||||
{% include 'nomcom/email_list_panel.html' %}
|
||||
{% endwith %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header"><h3>Accepted Nominees by Position</h3></div>
|
||||
<div class="card-body">
|
||||
{% for pos, accepts in bypos.items %}
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
|
||||
</form>
|
||||
{% if form.topic %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">Description: {{form.topic.subject}}</div>
|
||||
<div class="card-body">{{form.topic.get_description|safe}}</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header"><a data-bs-toggle="collapse" href="#generic_iesg_reqs_{{position.name|slugify}}" class="generic_iesg_reqs_header">General IESG Requirements</a></div>
|
||||
<div id="generic_iesg_reqs_{{position.name|slugify}}" class="card-body collapse in">
|
||||
{{generic_iesg_reqs|safe}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{position.name}} Specific Requirements</div>
|
||||
<div class="card-body">
|
||||
{{specific_reqs|safe}}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
{% if positions %}
|
||||
{% regroup positions by is_open as posgroups %}
|
||||
{% for group in posgroups %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header"><h3>{{ group.grouper| yesno:"Open Positions,Closed Positions"}}</h3></div>
|
||||
<div class="card-body">
|
||||
{% for position in group.list %}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
{% endif %}
|
||||
</dl>
|
||||
|
||||
<div class = "panel ">
|
||||
<div class = "card ">
|
||||
<p class='pasted'>{{ template.content }}</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
{% regroup nominees_feedback by nominee.staterank as stateranked_nominees %}
|
||||
{% for staterank in stateranked_nominees %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">
|
||||
{% if staterank.grouper == 0 %}
|
||||
<h6 class="anchor-target" id="accepted">Accepted nomination for at least one position</h6>
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
<h2 class="anchor-target" id="topics">Feedback related to topics</h2>
|
||||
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
{% regroup volunteers by eligible as volunteers_by_eligibility %}
|
||||
|
||||
{% for eligibility_group in volunteers_by_eligibility %}
|
||||
<div class="panel ">
|
||||
<div class="card ">
|
||||
<div class="card-header">{{ eligibility_group.grouper|yesno:"Eligible, Not Eligible"}}</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm table-striped tablesorter">
|
||||
|
|
|
@ -257,28 +257,69 @@ class SearchableField(forms.MultipleChoiceField):
|
|||
)
|
||||
|
||||
def prepare_value(self, value):
|
||||
result = super(SearchableField, self).prepare_value(value)
|
||||
# print("prepare_value", 1, value)
|
||||
# result = super(SearchableField, self).prepare_value(value)
|
||||
|
||||
if not value:
|
||||
value = ""
|
||||
# if not value:
|
||||
# value = ""
|
||||
# print("prepare_value", 2, value)
|
||||
|
||||
if isinstance(value, list):
|
||||
if len(value) == 0:
|
||||
value = None
|
||||
elif len(value) == 1:
|
||||
value = value[0]
|
||||
else:
|
||||
if not isinstance(value[0], self.model):
|
||||
qs = self.get_model_instances(value[0])
|
||||
for val in value[1:]:
|
||||
qs = qs.union(self.get_model_instances(val))
|
||||
value = qs
|
||||
# print("prepare_value", 3, value)
|
||||
if isinstance(value, int):
|
||||
value = str(value)
|
||||
if type(value) in (str, list):
|
||||
value = self.get_model_instances(value)
|
||||
# print("prepare_value", 4, value)
|
||||
if isinstance(value, str):
|
||||
if value == "":
|
||||
value = self.model.objects.none()
|
||||
else:
|
||||
value = self.get_model_instances([value])
|
||||
# print("prepare_value", 5, value)
|
||||
if isinstance(value, self.model):
|
||||
value = [value]
|
||||
if value.count() > 0:
|
||||
# print("prepare_value", 6, value)
|
||||
|
||||
if value:
|
||||
pre = self.make_select2_data(value)
|
||||
# print("value", value)
|
||||
# print("pre", pre)
|
||||
for d in pre:
|
||||
# print("d", d)
|
||||
if isinstance(value, list):
|
||||
# print(dir(value[0]))
|
||||
# if hasattr(value[0], "id"):
|
||||
d["selected"] = any([v.pk == d["id"] for v in value])
|
||||
else:
|
||||
d["selected"] = value.exists() and value.filter(pk__in=[d["id"]]).exists()
|
||||
self.widget.attrs["data-pre"] = json.dumps({
|
||||
d['id']: d for d in self.make_select2_data(value)
|
||||
d['id']: d for d in pre
|
||||
})
|
||||
# print(self.widget.attrs["data-pre"])
|
||||
# print("prepare_value", 7, value)
|
||||
|
||||
# doing this in the constructor is difficult because the URL
|
||||
# patterns may not have been fully constructed there yet
|
||||
self.widget.attrs["data-ajax-url"] = self.ajax_url()
|
||||
|
||||
result = value
|
||||
# print("prepare_value", 99, result)
|
||||
return result
|
||||
|
||||
def clean(self, pks):
|
||||
if pks is None:
|
||||
return None
|
||||
# print("clean", 1, pks)
|
||||
|
||||
try:
|
||||
objs = self.model.objects.filter(pk__in=pks)
|
||||
except ValueError as e:
|
||||
|
@ -295,6 +336,8 @@ class SearchableField(forms.MultipleChoiceField):
|
|||
'entry' if self.max_entries == 1 else 'entries',
|
||||
))
|
||||
|
||||
# print("clean", 99, self.max_entries, objs)
|
||||
|
||||
return objs.first() if self.max_entries == 1 else objs
|
||||
|
||||
|
||||
|
|
988
package-lock.json
generated
988
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@
|
|||
"flot": "^4.2.2",
|
||||
"highcharts": "^9.3.1",
|
||||
"jquery": "^3.6.0",
|
||||
"jquery-ui": "^1.13.0",
|
||||
"jquery-ui-dist": "^1.13.0",
|
||||
"js-cookie": "^3.0.1",
|
||||
"list.js": "^2.3.1",
|
||||
"moment": "^2.29.1",
|
||||
|
@ -30,6 +30,7 @@
|
|||
"ietf": {
|
||||
"distDir": "ietf/static/dist/ietf",
|
||||
"source": [
|
||||
"ietf/static/css/datepicker.scss",
|
||||
"ietf/static/css/ietf.scss",
|
||||
"ietf/static/css/jquery-ui.scss",
|
||||
"ietf/static/css/liaisons.css",
|
||||
|
@ -57,6 +58,8 @@
|
|||
"ietf/static/js/edit-meeting-schedule.js",
|
||||
"ietf/static/js/edit-meeting-timeslots-and-misc-sessions.js",
|
||||
"ietf/static/js/edit-milestones.js",
|
||||
"ietf/static/js/edit_action_holders.js",
|
||||
"ietf/static/js/edit_authors.js",
|
||||
"ietf/static/js/flot.js",
|
||||
"ietf/static/js/fullcalendar.js",
|
||||
"ietf/static/js/highcharts-export-data.js",
|
||||
|
@ -85,6 +88,7 @@
|
|||
"ietf/static/js/stats.js",
|
||||
"ietf/static/js/status-change-edit-relations.js",
|
||||
"ietf/static/js/timezone.js",
|
||||
"ietf/static/js/upload-material.js",
|
||||
"ietf/static/js/upload_bofreq.js",
|
||||
"ietf/static/js/week-view.js",
|
||||
"ietf/static/js/zxcvbn.js"
|
||||
|
|
Loading…
Reference in a new issue