commit
4635e3dd42
|
@ -434,7 +434,7 @@ function reconnectScrollObservers () {
|
|||
scrollObserver.disconnect()
|
||||
visibleDays.length = 0
|
||||
for (const mDay of agendaStore.meetingDays) {
|
||||
const el = document.getElementById(`agenda-day-${mDay.slug}`)
|
||||
const el = document.getElementById(mDay.slug)
|
||||
el.dataset.dayId = mDay.slug.toString()
|
||||
el.dataset.dayTs = mDay.ts
|
||||
scrollObserver.observe(el)
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
<script setup>
|
||||
import { computed, h } from 'vue'
|
||||
|
||||
import {
|
||||
NBadge,
|
||||
NDropdown,
|
||||
|
@ -51,21 +50,48 @@ const siteStore = useSiteStore()
|
|||
|
||||
// Meeting Days
|
||||
|
||||
function optionToLink(opts){
|
||||
const { key, label, icon } = opts
|
||||
|
||||
return {
|
||||
...opts,
|
||||
type: 'render',
|
||||
render: () => h(
|
||||
'a',
|
||||
{
|
||||
class: 'dropdown-link',
|
||||
'data-testid': 'mobile-link',
|
||||
href: `#${key}`
|
||||
},
|
||||
[
|
||||
h(
|
||||
'span',
|
||||
icon()
|
||||
),
|
||||
h(
|
||||
'span',
|
||||
label
|
||||
)
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const jumpToDayOptions = computed(() => {
|
||||
const days = []
|
||||
if (agendaStore.isMeetingLive) {
|
||||
days.push({
|
||||
days.push(optionToLink({
|
||||
label: 'Jump to Now',
|
||||
key: 'now',
|
||||
icon: () => h('i', { class: 'bi bi-arrow-down-right-square text-red' })
|
||||
})
|
||||
}))
|
||||
}
|
||||
for (const day of agendaStore.meetingDays) {
|
||||
days.push({
|
||||
days.push(optionToLink({
|
||||
label: `Jump to ${day.label}`,
|
||||
key: day.slug,
|
||||
icon: () => h('i', { class: 'bi bi-arrow-down-right-square' })
|
||||
})
|
||||
}))
|
||||
}
|
||||
return days
|
||||
})
|
||||
|
@ -90,14 +116,13 @@ const downloadIcsOptions = [
|
|||
function jumpToDay (dayId) {
|
||||
if (dayId === 'now') {
|
||||
const lastEventId = agendaStore.findCurrentEventId()
|
||||
|
||||
if (lastEventId) {
|
||||
document.getElementById(`agenda-rowid-${lastEventId}`)?.scrollIntoView(true)
|
||||
} else {
|
||||
message.warning('There is no event happening right now.')
|
||||
}
|
||||
} else {
|
||||
document.getElementById(`agenda-day-${dayId}`)?.scrollIntoView(true)
|
||||
document.getElementById(dayId)?.scrollIntoView(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,4 +187,19 @@ function downloadIcs (key) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-link {
|
||||
display: flex;
|
||||
text-decoration:none;
|
||||
gap: 0.2rem 0.5rem;
|
||||
padding: 0.5em;
|
||||
color: var(--bs-body-color);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--bs-dark-bg-subtle);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
li.nav-item(v-for='day of agendaStore.meetingDays')
|
||||
a.nav-link(
|
||||
:class='agendaStore.dayIntersectId === day.slug ? `active` : ``'
|
||||
:href='`#slot-` + day.slug'
|
||||
:href='`#${day.slug}`'
|
||||
@click='scrollToDay(day.slug, $event)'
|
||||
)
|
||||
i.bi.bi-arrow-right-short.d-none.d-xxl-inline.me-2
|
||||
|
@ -109,7 +109,6 @@
|
|||
<script setup>
|
||||
import { computed, h } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { DateTime } from 'luxon'
|
||||
import {
|
||||
NAffix,
|
||||
NBadge,
|
||||
|
@ -200,14 +199,11 @@ function pickerDiscard () {
|
|||
}
|
||||
}
|
||||
|
||||
function scrollToDay (dayId, ev) {
|
||||
ev.preventDefault()
|
||||
document.getElementById(`agenda-day-${dayId}`)?.scrollIntoView(true)
|
||||
function scrollToDay (daySlug, ev) {
|
||||
document.getElementById(daySlug)?.scrollIntoView(true)
|
||||
}
|
||||
|
||||
function scrollToNow (ev) {
|
||||
ev.preventDefault()
|
||||
|
||||
const lastEventId = agendaStore.findCurrentEventId()
|
||||
|
||||
if (lastEventId) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
)
|
||||
//- ROW - DAY HEADING -----------------------
|
||||
template(v-if='item.displayType === `day`')
|
||||
td(:id='`agenda-day-` + item.id', :colspan='pickerModeActive ? 6 : 5') {{item.date}}
|
||||
td(:id='item.slug', :colspan='pickerModeActive ? 6 : 5') {{item.date}}
|
||||
//- ROW - SESSION HEADING -------------------
|
||||
template(v-else-if='item.displayType === `session-head`')
|
||||
td.agenda-table-cell-check(v-if='pickerModeActive')
|
||||
|
@ -200,7 +200,7 @@ import {
|
|||
|
||||
import AgendaDetailsModal from './AgendaDetailsModal.vue'
|
||||
|
||||
import { useAgendaStore } from './store'
|
||||
import { useAgendaStore, daySlugPrefix, daySlug } from './store'
|
||||
import { useSiteStore } from '../shared/store'
|
||||
import { getUrl } from '../shared/urls'
|
||||
|
||||
|
@ -248,6 +248,7 @@ const meetingEvents = computed(() => {
|
|||
if (itemDate.toISODate() !== acc.lastDate) {
|
||||
acc.result.push({
|
||||
id: item.id,
|
||||
slug: daySlug(item),
|
||||
key: `day-${itemDate.toISODate()}`,
|
||||
displayType: 'day',
|
||||
date: itemDate.toLocaleString(DateTime.DATE_HUGE),
|
||||
|
@ -575,6 +576,30 @@ function recalculateRedLine () {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On page load when browser location hash contains '#now' or '#agenda-day-*' then scroll accordingly
|
||||
*/
|
||||
;(function scrollToHashInit() {
|
||||
if (!window.location.hash) {
|
||||
return
|
||||
}
|
||||
if (!(window.location.hash === "#now" || window.location.hash.startsWith(`#${daySlugPrefix}`))) {
|
||||
return
|
||||
}
|
||||
const unsubscribe = agendaStore.$subscribe((_mutation, agendaStoreState) => {
|
||||
if (agendaStoreState.schedule.length === 0) {
|
||||
return
|
||||
}
|
||||
unsubscribe() // we only need to scroll once, so unsubscribe from future updates
|
||||
if(window.location.hash === "#now") {
|
||||
const lastEventId = agendaStore.findCurrentEventId()
|
||||
document.getElementById(`agenda-rowid-${lastEventId}`)?.scrollIntoView(true)
|
||||
} else if(window.location.hash.startsWith(`#${daySlugPrefix}`)) {
|
||||
document.getElementById(window.location.hash.substring(1))?.scrollIntoView(true)
|
||||
}
|
||||
})
|
||||
})()
|
||||
|
||||
// MOUNTED
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -121,7 +121,7 @@ export const useAgendaStore = defineStore('agenda', {
|
|||
meetingDays () {
|
||||
const siteStore = useSiteStore()
|
||||
return uniqBy(this.scheduleAdjusted, 'adjustedStartDate').sort().map(s => ({
|
||||
slug: s.id.toString(),
|
||||
slug: daySlug(s),
|
||||
ts: s.adjustedStartDate,
|
||||
label: siteStore.viewport < 1350 ? DateTime.fromISO(s.adjustedStartDate).toFormat('ccc LLL d') : DateTime.fromISO(s.adjustedStartDate).toLocaleString(DateTime.DATE_HUGE)
|
||||
}))
|
||||
|
@ -292,3 +292,8 @@ function findFirstConferenceUrl (txt) {
|
|||
} catch (err) { }
|
||||
return null
|
||||
}
|
||||
|
||||
export const daySlugPrefix = 'agenda-day-'
|
||||
export function daySlug(s) {
|
||||
return `${daySlugPrefix}${s.adjustedStartDate}` // eg 'agenda-day-2024-08-13'
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import piniaPersist from 'pinia-plugin-persist'
|
||||
import Embedded from './Embedded.vue'
|
||||
import { createPiniaSingleton } from './shared/create-pinia-singleton'
|
||||
|
||||
// Initialize store (Pinia)
|
||||
|
||||
const pinia = createPinia()
|
||||
const pinia = createPiniaSingleton()
|
||||
pinia.use(piniaPersist)
|
||||
|
||||
// Mount App
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import piniaPersist from 'pinia-plugin-persist'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import { createPiniaSingleton } from './shared/create-pinia-singleton'
|
||||
|
||||
const app = createApp(App, {})
|
||||
|
||||
// Initialize store (Pinia)
|
||||
|
||||
const pinia = createPinia()
|
||||
const pinia = createPiniaSingleton()
|
||||
pinia.use(piniaPersist)
|
||||
app.use(pinia)
|
||||
|
||||
|
|
6
client/shared/create-pinia-singleton.js
Normal file
6
client/shared/create-pinia-singleton.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { createPinia } from 'pinia'
|
||||
|
||||
export function createPiniaSingleton(){
|
||||
window.pinia = window.pinia ?? createPinia()
|
||||
return window.pinia
|
||||
}
|
30
ietf/doc/migrations/0023_bofreqspamstate.py
Normal file
30
ietf/doc/migrations/0023_bofreqspamstate.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Copyright The IETF Trust 2024, All Rights Reserved
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
State = apps.get_model("doc", "State")
|
||||
State.objects.get_or_create(
|
||||
type_id="bofreq",
|
||||
slug="spam",
|
||||
defaults={"name": "Spam", "desc": "The BOF request is spam", "order": 5},
|
||||
)
|
||||
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
State = apps.get_model("doc", "State")
|
||||
Document = apps.get_model("doc", "Document")
|
||||
assert not Document.objects.filter(
|
||||
states__type="bofreq", states__slug="spam"
|
||||
).exists()
|
||||
State.objects.filter(type_id="bofreq", slug="spam").delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("doc", "0022_remove_dochistory_internal_comments_and_more"),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(forward, reverse)]
|
|
@ -96,9 +96,14 @@ def ballot_icon(context, doc):
|
|||
positions = list(ballot.active_balloter_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
request = context.get("request")
|
||||
ballot_edit_return_point_param = f"ballot_edit_return_point={request.path}"
|
||||
|
||||
right_click_string = ''
|
||||
if has_role(user, "Area Director"):
|
||||
right_click_string = 'oncontextmenu="window.location.href=\'%s\';return false;"' % urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
|
||||
right_click_string = 'oncontextmenu="window.location.href=\'{}?{}\';return false;"'.format(
|
||||
urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
ballot_edit_return_point_param)
|
||||
|
||||
my_blocking = False
|
||||
for i, (balloter, pos) in enumerate(positions):
|
||||
|
@ -114,9 +119,13 @@ def ballot_icon(context, doc):
|
|||
else:
|
||||
typename = "IESG"
|
||||
|
||||
modal_url = "{}?{}".format(
|
||||
urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
ballot_edit_return_point_param)
|
||||
|
||||
res = ['<a %s href="%s" data-bs-toggle="modal" data-bs-target="#modal-%d" aria-label="%s positions" title="%s positions (click to show more)" class="ballot-icon"><table' % (
|
||||
right_click_string,
|
||||
urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
modal_url,
|
||||
ballot.pk,
|
||||
typename,
|
||||
typename,)]
|
||||
|
|
29
ietf/doc/templatetags/document_type_badge.py
Normal file
29
ietf/doc/templatetags/document_type_badge.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Copyright The IETF Trust 2015-2020, All Rights Reserved
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.template.loader import render_to_string
|
||||
from ietf.utils.log import log
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def document_type_badge(doc, snapshot, submission, resurrected_by):
|
||||
context = {"doc": doc, "snapshot": snapshot, "submission": submission, "resurrected_by": resurrected_by}
|
||||
if doc.type_id == "rfc":
|
||||
return render_to_string(
|
||||
"doc/badge/doc-badge-rfc.html",
|
||||
context,
|
||||
)
|
||||
elif doc.type_id == "draft":
|
||||
return render_to_string(
|
||||
"doc/badge/doc-badge-draft.html",
|
||||
context,
|
||||
)
|
||||
else:
|
||||
error_message = f"Unsupported document type {doc.type_id}."
|
||||
if settings.SERVER_MODE != 'production':
|
||||
raise ValueError(error_message)
|
||||
else:
|
||||
log(error_message)
|
||||
return ""
|
|
@ -230,6 +230,9 @@ class EditPositionTests(TestCase):
|
|||
r = self.client.post(url, dict(position="discuss", discuss="Test discuss text"))
|
||||
self.assertEqual(r.status_code, 403)
|
||||
|
||||
# N.B. This test needs to be rewritten to exercise all types of ballots (iesg, irsg, rsab)
|
||||
# and test against the output of the mailtriggers instead of looking for hardcoded values
|
||||
# in the To and CC results. See #7864
|
||||
def test_send_ballot_comment(self):
|
||||
ad = Person.objects.get(user__username="ad")
|
||||
draft = WgDraftFactory(ad=ad,group__acronym='mars')
|
||||
|
@ -1455,18 +1458,14 @@ class BallotContentTests(TestCase):
|
|||
|
||||
class ReturnToUrlTests(TestCase):
|
||||
def test_invalid_return_to_url(self):
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: parse_ballot_edit_return_point('/doc/', 'draft-ietf-opsawg-ipfix-tcpo-v6eh', '998718'),
|
||||
)
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: parse_ballot_edit_return_point('/a-route-that-does-not-exist/', 'draft-ietf-opsawg-ipfix-tcpo-v6eh', '998718'),
|
||||
)
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: parse_ballot_edit_return_point('https://example.com/phishing', 'draft-ietf-opsawg-ipfix-tcpo-v6eh', '998718'),
|
||||
)
|
||||
with self.assertRaises(ValueError):
|
||||
parse_ballot_edit_return_point('/', 'draft-ietf-opsawg-ipfix-tcpo-v6eh', '998718')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
parse_ballot_edit_return_point('/a-route-that-does-not-exist/', 'draft-ietf-opsawg-ipfix-tcpo-v6eh', '998718')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
parse_ballot_edit_return_point('https://example.com/phishing', 'draft-ietf-opsawg-ipfix-tcpo-v6eh', '998718')
|
||||
|
||||
def test_valid_default_return_to_url(self):
|
||||
self.assertEqual(parse_ballot_edit_return_point(
|
||||
|
|
|
@ -54,8 +54,8 @@ This test section has some text.
|
|||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
for state in states:
|
||||
self.assertEqual(len(q(f'#bofreqs-{state.slug}')), 1)
|
||||
self.assertEqual(len(q(f'#bofreqs-{state.slug} tbody tr')), 3)
|
||||
self.assertEqual(len(q(f'#bofreqs-{state.slug}')), 1 if state.slug!="spam" else 0)
|
||||
self.assertEqual(len(q(f'#bofreqs-{state.slug} tbody tr')), 3 if state.slug!="spam" else 0)
|
||||
self.assertFalse(q('#start_button'))
|
||||
PersonFactory(user__username='nobody')
|
||||
self.client.login(username='nobody', password='nobody+password')
|
||||
|
@ -63,6 +63,13 @@ This test section has some text.
|
|||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(q('#start_button'))
|
||||
self.client.logout()
|
||||
self.client.login(username='secretary', password='secretary+password')
|
||||
r = self.client.get(url)
|
||||
q = PyQuery(r.content)
|
||||
for state in states:
|
||||
self.assertEqual(len(q(f'#bofreqs-{state.slug}')), 1)
|
||||
self.assertEqual(len(q(f'#bofreqs-{state.slug} tbody tr')), 3)
|
||||
|
||||
|
||||
def test_bofreq_main_page(self):
|
||||
|
|
|
@ -323,6 +323,8 @@ def build_position_email(balloter, doc, pos):
|
|||
|
||||
if doc.stream_id == "irtf":
|
||||
addrs = gather_address_lists('irsg_ballot_saved',doc=doc)
|
||||
elif doc.stream_id == "editorial":
|
||||
addrs = gather_address_lists('rsab_ballot_saved',doc=doc)
|
||||
else:
|
||||
addrs = gather_address_lists('iesg_ballot_saved',doc=doc)
|
||||
|
||||
|
@ -1314,10 +1316,23 @@ def rsab_ballot_status(request):
|
|||
def parse_ballot_edit_return_point(path, doc_name, ballot_id):
|
||||
get_default_path = lambda: urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=doc_name, ballot_id=ballot_id))
|
||||
allowed_path_handlers = {
|
||||
"ietf.community.views.view_list",
|
||||
"ietf.doc.views_doc.document_ballot",
|
||||
"ietf.doc.views_doc.document_irsg_ballot",
|
||||
"ietf.doc.views_doc.document_rsab_ballot",
|
||||
"ietf.doc.views_ballot.irsg_ballot_status",
|
||||
"ietf.doc.views_ballot.rsab_ballot_status",
|
||||
"ietf.doc.views_search.search",
|
||||
"ietf.doc.views_search.docs_for_ad",
|
||||
"ietf.doc.views_search.drafts_in_last_call",
|
||||
"ietf.doc.views_search.recent_drafts",
|
||||
"ietf.group.views.chartering_groups",
|
||||
"ietf.group.views.group_documents",
|
||||
"ietf.group.views.stream_documents",
|
||||
"ietf.iesg.views.agenda",
|
||||
"ietf.iesg.views.agenda_documents",
|
||||
"ietf.iesg.views.discusses",
|
||||
"ietf.iesg.views.past_documents",
|
||||
}
|
||||
return validate_return_to_path(path, get_default_path, allowed_path_handlers)
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ from pathlib import Path
|
|||
|
||||
from django.core.cache import caches
|
||||
from django.db.models import Max
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.http import HttpResponse, Http404, HttpResponseBadRequest
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse as urlreverse
|
||||
|
@ -73,6 +73,7 @@ from ietf.ietfauth.utils import ( has_role, is_authorized_in_doc_stream, user_is
|
|||
role_required, is_individual_draft_author, can_request_rfc_publication)
|
||||
from ietf.name.models import StreamName, BallotPositionName
|
||||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.doc.views_ballot import parse_ballot_edit_return_point
|
||||
from ietf.doc.forms import InvestigateForm, TelechatForm, NotifyForm, ActionHoldersForm, DocAuthorForm, DocAuthorChangeBasisForm
|
||||
from ietf.doc.mails import email_comment, email_remind_action_holders
|
||||
from ietf.mailtrigger.utils import gather_relevant_expansions
|
||||
|
@ -1586,11 +1587,18 @@ def ballot_popup(request, name, ballot_id):
|
|||
doc = get_object_or_404(Document, name=name)
|
||||
c = document_ballot_content(request, doc, ballot_id=ballot_id, editable=False)
|
||||
ballot = get_object_or_404(BallotDocEvent,id=ballot_id)
|
||||
|
||||
try:
|
||||
return_to_url = parse_ballot_edit_return_point(request.GET.get('ballot_edit_return_point'), name, ballot_id)
|
||||
except ValueError:
|
||||
return HttpResponseBadRequest('ballot_edit_return_point is invalid')
|
||||
|
||||
return render(request, "doc/ballot_popup.html",
|
||||
dict(doc=doc,
|
||||
ballot_content=c,
|
||||
ballot_id=ballot_id,
|
||||
ballot_type_slug=ballot.ballot_type.slug,
|
||||
ballot_edit_return_point=return_to_url,
|
||||
editable=True,
|
||||
))
|
||||
|
||||
|
|
|
@ -2617,6 +2617,19 @@
|
|||
"model": "doc.state",
|
||||
"pk": 180
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The BOF request is spam",
|
||||
"name": "Spam",
|
||||
"next_states": [],
|
||||
"order": 5,
|
||||
"slug": "spam",
|
||||
"type": "bofreq",
|
||||
"used": true
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 182
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"label": "State"
|
||||
|
|
|
@ -320,6 +320,11 @@ tbody.meta tr {
|
|||
background-color: $danger;
|
||||
}
|
||||
|
||||
.badge-generic {
|
||||
color: white;
|
||||
background-color: $danger;
|
||||
}
|
||||
|
||||
#toc-nav {
|
||||
width: inherit;
|
||||
overscroll-behavior-y: none; // Prevent overscrolling from scrolling the main content
|
||||
|
|
16
ietf/templates/doc/badge/doc-badge-draft.html
Normal file
16
ietf/templates/doc/badge/doc-badge-draft.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load ietf_filters %}
|
||||
{% load person_filters %}
|
||||
{% origin %}
|
||||
{# Non-RFC #}
|
||||
|
||||
{% if doc.became_rfc %}
|
||||
<div{% if document_html %} class="alert alert-warning small"{% endif %}>This is an older version of an Internet-Draft that was ultimately published as <a href="{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.became_rfc.name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.became_rfc.name %}{% endif %}">{{doc.became_rfc.name|prettystdname}}</a>.</div>
|
||||
{% elif snapshot and doc.rev != latest_rev %}
|
||||
<div{% if document_html %} class="alert alert-warning small p-2 mt-2"{% endif %}>This is an older version of an Internet-Draft whose latest revision state is "{{ doc.doc.get_state }}".</div>
|
||||
{% else %}
|
||||
<span class="{% if doc.get_state_slug == 'active' %}text-success{% elif doc.get_state_slug == 'expired' or doc.get_state_slug == 'repl' %}text-danger{% endif %}">{% if snapshot and doc.rev == latest_rev %}{{ doc.doc.get_state }}{% else %}{{ doc.get_state }}{% endif %} Internet-Draft</span>
|
||||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
{% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %}
|
||||
{% endif %}
|
13
ietf/templates/doc/badge/doc-badge-rfc.html
Normal file
13
ietf/templates/doc/badge/doc-badge-rfc.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load ietf_filters %}
|
||||
{% load person_filters %}
|
||||
{% origin %}
|
||||
|
||||
<span class="text-success">RFC
|
||||
{% if not document_html %}
|
||||
- {{ doc.std_level }}
|
||||
{% else %}
|
||||
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}generic{% endif %}">{{ doc.std_level }}</span>
|
||||
{% endif %}
|
||||
</span>
|
|
@ -27,7 +27,7 @@
|
|||
{% if editable and user|has_role:"Area Director,Secretariat,IRSG Member,RSAB Member" %}
|
||||
{% if user|can_ballot:doc %}
|
||||
<a class="btn btn-primary"
|
||||
href="{% url "ietf.doc.views_ballot.edit_position" name=doc.name ballot_id=ballot_id %}?ballot_edit_return_point={{ request.path|urlencode }}">
|
||||
href="{% url "ietf.doc.views_ballot.edit_position" name=doc.name ballot_id=ballot_id %}?ballot_edit_return_point={{ ballot_edit_return_point|urlencode }}">
|
||||
Edit position
|
||||
</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2021 All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load person_filters %}
|
||||
{% load person_filters ietf_filters %}
|
||||
{% load static %}
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
|
||||
|
@ -26,6 +26,7 @@
|
|||
{% else %}
|
||||
{% regroup reqs by get_state_slug as grouped_reqs %}
|
||||
{% for req_group in grouped_reqs %}
|
||||
{% if req_group.grouper != "spam" or request.user|has_role:"Secretariat" %}
|
||||
<h2 class="mt-5">{{ req_group.grouper|capfirst }} BOF Requests</h2>
|
||||
<table id="bofreqs-{{ req_group.grouper }}"
|
||||
class="table table-sm table-striped tablesorter">
|
||||
|
@ -60,6 +61,7 @@
|
|||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load ietf_filters textfilters %}
|
||||
{% load document_type_badge %}
|
||||
{% load django_vite %}
|
||||
{% origin %}
|
||||
<html data-bs-theme="auto" lang="en">
|
||||
|
@ -107,6 +108,7 @@
|
|||
{{ doc.name }}-{{ doc.rev }}
|
||||
{% endif %}
|
||||
<br class="d-sm-none">
|
||||
|
||||
<span class="ms-sm-3 badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">
|
||||
{% if not snapshot %}
|
||||
{{ doc.std_level }}
|
||||
|
@ -185,13 +187,7 @@
|
|||
{{ doc.name }}-{{ doc.rev }}
|
||||
{% endif %}
|
||||
<br>
|
||||
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">
|
||||
{% if not snapshot %}
|
||||
{{ doc.std_level }}
|
||||
{% else %}
|
||||
Internet-Draft
|
||||
{% endif %}
|
||||
</span>
|
||||
{% document_type_badge doc snapshot submission resurrected_by %}
|
||||
</p>
|
||||
</div>
|
||||
{% if request.COOKIES.htmlconf and request.COOKIES.htmlconf != 'html' and html %}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
{% load static %}
|
||||
{% load ietf_filters %}
|
||||
{% load person_filters %}
|
||||
{% load document_type_badge %}
|
||||
{% origin %}
|
||||
|
||||
<tbody class="meta align-top {% if not document_html %} border-top{% endif %}">
|
||||
|
@ -11,14 +12,8 @@
|
|||
<th scope="row">{% if document_html %}Document type{% else %}Type{% endif %}</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
{% document_type_badge doc snapshot submission resurrected_by %}
|
||||
{% if doc.type_id == "rfc" %}
|
||||
<span class="text-success">RFC
|
||||
{% if not document_html %}
|
||||
- {{ doc.std_level }}
|
||||
{% else %}
|
||||
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">{{ doc.std_level }}</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if doc.pub_date %}
|
||||
{% if document_html %}<br>{% else %}({% endif %}{{ doc.pub_date|date:"F Y" }}{% if not document_html %}){% endif %}
|
||||
{% else %}
|
||||
|
@ -59,16 +54,6 @@
|
|||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if doc.became_rfc %}
|
||||
<div{% if document_html %} class="alert alert-warning small"{% endif %}>This is an older version of an Internet-Draft that was ultimately published as <a href="{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.became_rfc.name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.became_rfc.name %}{% endif %}">{{doc.became_rfc.name|prettystdname}}</a>.</div>
|
||||
{% elif snapshot and doc.rev != latest_rev %}
|
||||
<div{% if document_html %} class="alert alert-warning small p-2 mt-2"{% endif %}>This is an older version of an Internet-Draft whose latest revision state is "{{ doc.doc.get_state }}".</div>
|
||||
{% else %}
|
||||
<span class="{% if doc.get_state_slug == 'active' %}text-success{% elif doc.get_state_slug == 'expired' or doc.get_state_slug == 'repl' %}text-danger{% endif %}">{% if snapshot and doc.rev == latest_rev %}{{ doc.doc.get_state }}{% else %}{{ doc.get_state }}{% endif %} Internet-Draft</span>
|
||||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
{% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if doc.get_state_slug != "active" and doc.get_state_slug != "rfc" and doc.type_id != "rfc" %}
|
||||
<div class="badge rounded-pill text-bg-warning{% if not document_html %} float-end{% endif %}">
|
||||
|
|
|
@ -1431,7 +1431,7 @@ test.describe('past - small screens', () => {
|
|||
|
||||
// can open the jump to day dropdown
|
||||
await barBtnLocator.first().click()
|
||||
const jumpDayDdnLocator = page.locator('.n-dropdown-menu > .n-dropdown-option')
|
||||
const jumpDayDdnLocator = page.locator('.n-dropdown-menu [data-testid=mobile-link]')
|
||||
await expect(jumpDayDdnLocator).toHaveCount(7)
|
||||
for (let idx = 0; idx < 7; idx++) {
|
||||
const localDateTime = DateTime.fromISO(meetingData.meeting.startDate, { zone: meetingData.meeting.timezone })
|
||||
|
|
Loading…
Reference in a new issue