Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-base-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
echo "IMGVERSION=$CURDATE" >> $GITHUB_ENV

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:
echo "${{ env.IMGVERSION }}" > dev/build/TARGET_BASE

- name: Commit CHANGELOG.md
uses: stefanzweifel/git-auto-commit-action@v6
uses: stefanzweifel/git-auto-commit-action@v7
with:
branch: ${{ github.ref_name }}
commit_message: 'ci: update base image target version to ${{ env.IMGVERSION }}'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-mq-broker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- uses: actions/checkout@v6

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ jobs:

- name: Download a Coverage Results
if: ${{ github.event.inputs.skiptests == 'false' || github.ref_name == 'release' }}
uses: actions/download-artifact@v6.0.0
uses: actions/download-artifact@v8.0.1
with:
name: coverage

Expand Down Expand Up @@ -291,7 +291,7 @@ jobs:

- name: Download Coverage Results
if: ${{ github.event.inputs.skiptests == 'false' || github.ref_name == 'release' }}
uses: actions/download-artifact@v6.0.0
uses: actions/download-artifact@v8.0.1
with:
name: coverage

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests-az.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
ssh-keyscan -t rsa $vminfo >> ~/.ssh/known_hosts
- name: Remote SSH into VM
uses: appleboy/ssh-action@2ead5e36573f08b82fbfce1504f1a4b05a647c6f
uses: appleboy/ssh-action@0ff4204d59e8e51228ff73bce53f80d53301dee2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
path: geckodriver.log

- name: Upload Coverage Results to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
disable_search: true
files: coverage.xml
Expand Down
2 changes: 1 addition & 1 deletion dev/build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ghcr.io/ietf-tools/datatracker-app-base:20260323T1533
FROM ghcr.io/ietf-tools/datatracker-app-base:20260408T1908
LABEL maintainer="IETF Tools Team <tools-discuss@ietf.org>"

ENV DEBIAN_FRONTEND=noninteractive
Expand Down
2 changes: 1 addition & 1 deletion dev/build/TARGET_BASE
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20260323T1533
20260408T1908
28 changes: 14 additions & 14 deletions dev/deploy-to-container/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dev/deploy-to-container/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"fs-extra": "^11.3.4",
"nanoid": "5.1.7",
"nanoid-dictionary": "5.0.0",
"slugify": "1.6.8",
"tar": "^7.5.12",
"slugify": "1.6.9",
"tar": "^7.5.13",
"yargs": "^17.7.2"
},
"engines": {
Expand Down
28 changes: 27 additions & 1 deletion ietf/api/serializers_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
update_action_holders,
update_rfcauthors,
)
from ietf.group.models import Group
from ietf.group.models import Group, Role
from ietf.group.serializers import AreaSerializer
from ietf.name.models import StreamName, StdLevelName
from ietf.person.models import Person
Expand Down Expand Up @@ -97,6 +97,21 @@ class Meta:
fields = ["draft_name", "authors"]


class WgChairSerializer(serializers.Serializer):
"""Serialize a WG chair's name and email from a Role"""

name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()

@extend_schema_field(serializers.CharField)
def get_name(self, role: Role) -> str:
return role.person.plain_name()

@extend_schema_field(serializers.EmailField)
def get_email(self, role: Role) -> str:
return role.email.email_address()


class DocumentAuthorSerializer(serializers.ModelSerializer):
"""Serializer for a Person in a response"""

Expand Down Expand Up @@ -126,6 +141,7 @@ class FullDraftSerializer(serializers.ModelSerializer):
source="shepherd.person", read_only=True
)
consensus = serializers.SerializerMethodField()
wg_chairs = serializers.SerializerMethodField()

class Meta:
model = Document
Expand All @@ -145,11 +161,21 @@ class Meta:
"consensus",
"shepherd",
"ad",
"wg_chairs",
]

def get_consensus(self, doc: Document) -> Optional[bool]:
return default_consensus(doc)

@extend_schema_field(WgChairSerializer(many=True))
def get_wg_chairs(self, doc: Document):
if doc.group is None:
return []
chairs = doc.group.role_set.filter(name_id="chair").select_related(
"person", "email"
)
return WgChairSerializer(chairs, many=True).data

def get_source_format(
self, doc: Document
) -> Literal["unknown", "xml-v2", "xml-v3", "txt"]:
Expand Down
6 changes: 6 additions & 0 deletions ietf/group/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ class AreaDirectorSerializer(serializers.Serializer):
Works with Email or Role
"""

name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()

@extend_schema_field(serializers.CharField)
def get_name(self, instance: Email | Role):
person = getattr(instance, 'person', None)
return person.plain_name() if person else None

@extend_schema_field(serializers.EmailField)
def get_email(self, instance: Email | Role):
if isinstance(instance, Role):
Expand Down
12 changes: 9 additions & 3 deletions ietf/group/tests_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_serializes_role(self):
serialized = AreaDirectorSerializer(role).data
self.assertEqual(
serialized,
{"email": role.email.email_address()},
{"email": role.email.email_address(), "name": role.person.plain_name()},
)

def test_serializes_email(self):
Expand All @@ -40,7 +40,10 @@ def test_serializes_email(self):
serialized = AreaDirectorSerializer(email).data
self.assertEqual(
serialized,
{"email": email.email_address()},
{
"email": email.email_address(),
"name": email.person.plain_name() if email.person else None,
},
)


Expand All @@ -63,7 +66,10 @@ def test_serializes_active_area(self):
self.assertEqual(serialized["name"], area.name)
self.assertCountEqual(
serialized["ads"],
[{"email": ad.email.email_address()} for ad in ad_roles],
[
{"email": ad.email.email_address(), "name": ad.person.plain_name()}
for ad in ad_roles
],
)

def test_serializes_inactive_area(self):
Expand Down
17 changes: 17 additions & 0 deletions ietf/static/css/ietf.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1216,3 +1216,20 @@ iframe.status {
.overflow-shadows--bottom-only {
box-shadow: inset 0px -21px 18px -20px var(--bs-body-color);
}

#navbar-doc-search-wrapper {
position: relative;
}

#navbar-doc-search-results {
max-height: 400px;
overflow-y: auto;
min-width: auto;
left: 0;
right: 0;

.dropdown-item {
white-space: normal;
overflow-wrap: break-word;
}
}
113 changes: 113 additions & 0 deletions ietf/static/js/navbar-doc-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
$(function () {
var $input = $('#navbar-doc-search');
var $results = $('#navbar-doc-search-results');
var ajaxUrl = $input.data('ajax-url');
var debounceTimer = null;
var highlightedIndex = -1;
var keyboardHighlight = false;
var currentItems = [];

function showDropdown() {
$results.addClass('show');
}

function hideDropdown() {
$results.removeClass('show');
highlightedIndex = -1;
keyboardHighlight = false;
updateHighlight();
}

function updateHighlight() {
$results.find('.dropdown-item').removeClass('active');
if (highlightedIndex >= 0 && highlightedIndex < currentItems.length) {
$results.find('.dropdown-item').eq(highlightedIndex).addClass('active');
}
}

function doSearch(query) {
if (query.length < 2) {
hideDropdown();
return;
}
$.ajax({
url: ajaxUrl,
dataType: 'json',
data: { q: query },
success: function (data) {
currentItems = data;
highlightedIndex = -1;
$results.empty();
if (data.length === 0) {
$results.append('<li><span class="dropdown-item text-muted">No results found</span></li>');
} else {
data.forEach(function (item) {
var $li = $('<li>');
var $a = $('<a class="dropdown-item" href="' + item.url + '">' + item.text + '</a>');
$li.append($a);
$results.append($li);
});
}
showDropdown();
}
});
}

$input.on('input', function () {
clearTimeout(debounceTimer);
var query = $(this).val().trim();
debounceTimer = setTimeout(function () {
doSearch(query);
}, 250);
});

$input.on('keydown', function (e) {
if (e.key === 'ArrowDown') {
e.preventDefault();
if (highlightedIndex < currentItems.length - 1) {
highlightedIndex++;
keyboardHighlight = true;
updateHighlight();
}
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (highlightedIndex > 0) {
highlightedIndex--;
keyboardHighlight = true;
updateHighlight();
}
} else if (e.key === 'Enter') {
e.preventDefault();
if (keyboardHighlight && highlightedIndex >= 0 && highlightedIndex < currentItems.length) {
window.location.href = currentItems[highlightedIndex].url;
} else {
var query = $(this).val().trim();
if (query) {
window.location.href = '/doc/search/?name=' + encodeURIComponent(query) + '&rfcs=on&activedrafts=on&olddrafts=on';
}
}
} else if (e.key === 'Escape') {
hideDropdown();
$input.blur();
}
});

// Hover highlights (visual only — Enter still submits the text)
$results.on('mouseenter', '.dropdown-item', function () {
highlightedIndex = $results.find('.dropdown-item').index(this);
keyboardHighlight = false;
updateHighlight();
});

$results.on('mouseleave', '.dropdown-item', function () {
highlightedIndex = -1;
updateHighlight();
});

// Click outside closes dropdown
$(document).on('click', function (e) {
if (!$(e.target).closest('#navbar-doc-search-wrapper').length) {
hideDropdown();
}
});
});
Loading
Loading