Skip to content

feat: add key-based filter in OpenLake leaderboard#192

Open
VarshiniGunti wants to merge 2 commits intoOpenLake:mainfrom
VarshiniGunti:feat/openlake-pr-key-filter
Open

feat: add key-based filter in OpenLake leaderboard#192
VarshiniGunti wants to merge 2 commits intoOpenLake:mainfrom
VarshiniGunti:feat/openlake-pr-key-filter

Conversation

@VarshiniGunti
Copy link
Contributor

@VarshiniGunti VarshiniGunti commented Feb 25, 2026

Feature: Key-Based Filter for OpenLake Leaderboard

Resolves #141

What this PR adds

This PR introduces a PR title key filter for the OpenLake leaderboard so contributors can be ranked by contributions tied to a specific initiative key, such as:

  • [FOSSOVERFLOW-2025]
  • [DEVLABS-2025]

Highlights

  1. Backend support for key-scoped leaderboard data
  • Extended the OpenLake endpoint to accept a pr_key query param:
    • GET /openlake/?pr_key=FOSSOVERFLOW-2025
  • The API now computes contribution counts using OpenLake PRs whose titles include the requested bracketed key.
  1. Frontend key filter UI in OpenLake leaderboard
  • Added a filter input and controls:
    • Apply Key
    • Clear
  • Users can type a key (e.g. FOSSOVERFLOW-2025) and instantly view contributions for PRs matching [KEY].
  1. Preserved existing behavior
  • Existing OpenLake leaderboard behavior remains unchanged when no key is applied.
  • Search and Friends filtering continue to work with key-filtered data.

Why this is useful

This enables event- and campaign-specific visibility, making it easy to analyze contributor activity for focused initiatives without affecting the default global leaderboard view.

Validation

  • Frontend lint passed.
  • Backend syntax validation passed.

Summary by CodeRabbit

  • New Features
    • Added pull request key-based filtering to the leaderboard, allowing users to filter contributors by a specific PR key.
    • New UI controls enable users to input, apply, and clear PR key filters with loading indicators during data fetch.
    • Applied PR key displays in the interface for user reference.

@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Warning

Rate limit exceeded

@VarshiniGunti has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 9 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between c9d7f70 and 947a39a.

📒 Files selected for processing (2)
  • api/leaderboard/views.py
  • app/src/components/OpenlakeTable.jsx

Walkthrough

This PR adds a key-based filtering feature to the OpenLake Leaderboard, enabling users to filter PR contributions by keys found in PR titles (e.g., [DEVLABS-2025]). The backend integrates with GitHub API to fetch matching PRs, while the frontend provides input controls and displays filtered contributor data.

Changes

Cohort / File(s) Summary
Backend GitHub API Integration
api/leaderboard/views.py
Added _github_headers() to construct Authorization headers from optional environment token, and _get_pr_key_contributions() to query GitHub Issues API for PRs matching a key, aggregate contributions by username, and return sorted contributor list. Enhanced get() to handle pr_key query parameter.
Frontend PR Key Filter UI
app/src/components/OpenlakeTable.jsx
Introduced PR-key filtering state and effect to fetch key-filtered users from backend. Replaced single search input with composite control (search + PR-key input with Apply/Clear actions). Updated data source logic to conditionally use filtered or original user data, added loading indicators and applied-key display feedback.

Sequence Diagram

sequenceDiagram
    actor User
    participant Frontend as OpenlakeTable
    participant Backend as GithubOrganisationAPI
    participant GitHub as GitHub API

    User->>Frontend: Enter PR key & click Apply
    Frontend->>Frontend: Update appliedPrKey state
    Frontend->>Frontend: Trigger useEffect watching appliedPrKey
    Frontend->>Backend: GET /leaderboard?pr_key=[key]
    Backend->>Backend: _get_pr_key_contributions(key)
    Backend->>GitHub: Query Issues API for PRs with key
    GitHub-->>Backend: Return matching PRs
    Backend->>Backend: Aggregate contributions by username
    Backend-->>Frontend: Return sorted contributors list
    Frontend->>Frontend: Update keyFilteredUsers state
    Frontend->>Frontend: Set isFetchingPrKeyData = false
    Frontend->>User: Display filtered contributors & applied key
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A key unlocks treasures in PRs so fine,
Square brackets reveal the work divine,
Filter and fetch with GitHub's grace,
Leaderboard now shows each contributor's place! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a key-based filter feature to the OpenLake leaderboard, which matches the PR's primary objective.
Linked Issues check ✅ Passed The PR successfully implements the key requirement from issue #141: extracting keys from PR titles (text in square brackets) and filtering contributions by key through both backend and frontend changes.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the key-based filter feature in both frontend and backend components as specified in issue #141.
Description check ✅ Passed The pull request description comprehensively covers all required template sections including a clear description, related issues, key changes, type of change, and helpful notes for reviewers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

This comment has been minimized.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
app/src/components/OpenlakeTable.jsx (1)

151-183: Consolidate filtering effects to remove duplicated/stale state transitions.

Line 160-167 filters with todisplayusers immediately after setTodisplayusers, then Line 171-183 repeats filtering again. This adds extra renders and transient stale updates.

Proposed fix
 useEffect(() => {
   if (showOLFriends) {
     setTodisplayusers(
       sourceUsers.filter((OLUser) => OLFriends.includes(OLUser.username)),
     );
   } else {
     setTodisplayusers(sourceUsers);
   }
-  if (searchfield === "") {
-    setFilteredusers(todisplayusers);
-  } else {
-    setFilteredusers(
-      todisplayusers.filter((cfUser) => {
-        return cfUser.username
-          .toLowerCase()
-          .includes(searchfield.toLowerCase());
-      }),
-    );
-  }
-}, [showOLFriends, OLFriends, searchfield, sourceUsers]);
+}, [showOLFriends, OLFriends, sourceUsers]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/components/OpenlakeTable.jsx` around lines 151 - 183, The two
useEffect blocks duplicate filtering and cause transient stale state; replace
them with a single useEffect that computes a local newTodisplay (based on
showOLFriends, OLFriends, sourceUsers), calls setTodisplayusers(newTodisplay),
then computes filtered = searchfield === "" ? newTodisplay :
newTodisplay.filter(u =>
u.username.toLowerCase().includes(searchfield.toLowerCase())) and calls
setFilteredusers(filtered); keep the dependency array [showOLFriends, OLFriends,
searchfield, sourceUsers] and remove the second useEffect to avoid extra renders
and stale reads of todisplayusers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/leaderboard/views.py`:
- Around line 177-178: The handler currently swallows non-200 GitHub responses
by breaking the loop when response.status_code != 200 and later always returning
HTTP 200, which masks upstream failures; update the logic around response (the
check using response.status_code) to propagate errors to the client instead of
treating them as "no results"—for non-200 responses return an appropriate error
response (use the actual response.status_code and include error details/body or
a clear message) or raise an HTTPException so callers can distinguish GitHub
failures from legitimately empty PR results; adjust the return path that
currently always returns 200 (the code after the loop that returns successful
results) to only return 200 on success.
- Around line 160-186: The loop in _get_pr_key_contributions currently counts
any PR whose title contains the key anywhere; update the per-item handling
inside the items loop to fetch the PR title (item.get("title")), trim leading
whitespace, and only increment contributions[username] if the trimmed title
starts with f'[{normalized_key}]' (otherwise continue); keep using the existing
contributions Counter and username extraction logic so only PRs with the key at
the title start are counted.

In `@app/src/components/OpenlakeTable.jsx`:
- Around line 127-149: The effect that fetches users for appliedPrKey (useEffect
→ getPrKeyFilteredUsers) can suffer stale-response races; fix it by creating an
AbortController (or a requestId token) inside the effect, pass controller.signal
to fetch, and on cleanup call controller.abort() so any previous fetch is
cancelled; ensure the catch distinguishes abort errors (don’t reset
keyFilteredUsers on abort) and still toggles setIsFetchingPrKeyData(false) in
finally so the state reflects the latest request.

---

Nitpick comments:
In `@app/src/components/OpenlakeTable.jsx`:
- Around line 151-183: The two useEffect blocks duplicate filtering and cause
transient stale state; replace them with a single useEffect that computes a
local newTodisplay (based on showOLFriends, OLFriends, sourceUsers), calls
setTodisplayusers(newTodisplay), then computes filtered = searchfield === "" ?
newTodisplay : newTodisplay.filter(u =>
u.username.toLowerCase().includes(searchfield.toLowerCase())) and calls
setFilteredusers(filtered); keep the dependency array [showOLFriends, OLFriends,
searchfield, sourceUsers] and remove the second useEffect to avoid extra renders
and stale reads of todisplayusers.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02c46c6 and c9d7f70.

📒 Files selected for processing (2)
  • api/leaderboard/views.py
  • app/src/components/OpenlakeTable.jsx

@github-actions
Copy link

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

Unrecognized words (608)
actionlist
addfriend
addlink
aditya
adn
aec
alignof
amazonaws
amqp
antialiased
apexcharts
api
apk
APPS
args
argv
Arial
arrowright
asc
asgi
asm
atcoder
atcoderuser
atlaskit
atn
attr
atv
authtoken
autocomplete
autodiscover
axios
AZERBAIJANI
backend
barcode
bbb
bdsw
bebec
bitbucket
bitcoin
bitset
Bitstream
blang
blinenums
blockquote
blog
bradlc
breadcrumb
bsd
btc
btn
calendarbox
calendarin
calendarlink
calendarnav
Cantarell
ccc
CCPS
CCPSAPI
ccpsleetcoderanking
ccshowfriends
cdata
cdn
changelink
changelist
charset
checkbox
checkboxes
chmod
chooseall
cjs
classmethod
clearall
clickjacking
clockbox
clocklink
clojure
closelink
cls
clsx
cmdk
cnt
cny
codechef
codecheffriends
codeforces
codeforcesfriends
codeforcesuser
collectstatic
colspan
combobox
concat
config
Consolas
constexpr
contenttypes
coreapi
coredocs
cors
corsheaders
cpp
CRA
cred
crontab
csh
csrf
csrftoken
css
ctz
curated
curleft
curtop
cva
cxx
dabapps
dadce
dafb
darkmode
dartdoc
datetime
datetimeshortcuts
davegandy
dbaeumer
dblclick
dce
ddd
decltype
dedent
deletelink
deno
deps
describedby
dest
dfd
dirname
DIRS
discription
discussionpost
disscussion
django
djangoproject
Dmitriy
dnd
dnt
dockerfile
doctype
dotenv
downcode
Downcoder
draggable
drf
dribbble
DRILLDOWN
Droid
dropbox
dropdown
dropfriend
droppable
eaed
ececf
edecd
eee
efb
efcajlnqvdqjeoud
ele
elems
elif
elsif
enctype
endif
entrypoint
enum
EOL
eot
errexit
errorlist
errornote
esac
esbenp
eslint
eur
facebook
favicon
fbfbfc
FCalcutta
fdd
Fefer
fetchall
ffc
ffefef
fff
fieldset
fieldsetcollapser
filteredusers
findpos
Fira
flatpage
flickr
fontawesome
fontawesomeregular
foreach
formset
FOSSOVERFLOW
fromtimestamp
frontend
func
gamepad
gbp
getccfriends
getcffriends
getenv
getghfriends
getltfriends
gettext
ghshowfriends
github
githubfriends
githubusercontent
gittip
globals
glyphicons
gmail
gohri
google
GOOGLEDATA
gotop
graphql
grayscale
GSo
gtcvau
halflingsregular
hdd
heatmap
hexcolor
hiddenfields
hljs
Holovaty
hookform
horiz
howto
href
hsl
htm
html
http
Hyperlinked
ical
icnt
ico
iefix
ifdef
ifndef
iframe
img
inbox
INITDB
inlinechangelink
inlines
inlineviewlink
inp
inr
insertapi
Insitute
instagram
instanceof
INTV
isoformat
isready
Jannis
javadoc
javascript
javascriptreact
jpg
jpy
jsguide
json
jsx
jti
jumbotron
jumotron
JWK
jwt
keydown
keyframes
keyup
krw
kwargs
kwd
kwv
lbh
lccal
Lconf
leaderboard
leaderboardpro
leetcode
leetcodecontestrankings
leetcodefriends
leetcoderanking
leetcoderankingsccps
Leetocde
Leidel
len
Lexer
lify
lightgrey
linecap
linejoin
linenums
linkedin
linting
linux
linuxhint
localhost
lockfile
lodash
loglevel
logresponse
lsaquo
lstrip
LTshowfriends
lucide
madueke
majodev
makemigrations
maxcdn
maxlength
medkit
meh
Memon
messagelist
metadata
Microsoft
middleware
mixin
mjs
mongodb
moz
mozilla
mql
multiline
mxml
namearr
namespace
navbar
ndx
Neue
ngettext
nginx
nocode
nodejs
nodesource
nonday
noopener
noreferrer
normarr
noscript
nowrap
npm
npx
nullptr
nums
offcanvas
ofhiuvw
OFL
oklch
onrender
openlake
opensource
opentype
opn
orderby
osx
outdent
pagelines
paginator
params
pathlib
perl
pgettext
Phalip
php
phpdoc
pinterest
pln
plugin
png
pnpm
Polovnyov
Polyfill
popup
postgre
postgresql
Powershell
PPK
pragma
prepopulate
prepopulated
prettyprint
progid
pyguide
pylint
pymongo
pypi
PYTHONPATH
qrcode
queryset
Quicklink
quirksmode
qyu
rabbitmq
radiolist
reactjs
readonly
redis
redislabs
regex
regexp
regresponse
reinit
renren
replypost
resizable
retweet
rgba
rmb
rmq
Roboto
robotstxt
rohit
rpdttenqphkdyvpuoeky
rsaquo
rsc
rss
rstrip
rtl
runserver
sbyte
scrollbars
scss
sdk
searchbar
searchfield
Segoe
selectfilter
selectfilterstacked
serializer
setattr
setcontestoptions
setdefault
setis
shadcn
showall
simplejwt
sitemap
sizeof
skype
solvedc
solvedl
sortoptions
sortpriority
sortremove
spsiphnqk
sqlite
src
stackalloc
stan
standalone
startproject
startswith
staticfiles
stderr
stdout
strftime
strictfp
strikethrough
stringify
strptime
stswe
styleguide
subdir
substr
sudo
Sumagna
sumagnadas
supabase
svg
svgr
svh
Swicegood
sys
tabbable
tabstyle
tailwindcss
tanstack
tbody
textarea
textfield
tfoot
thead
timedelta
timelist
timezone
timezonewarning
todisplayusers
TODO
toolbar
tooltag
tooltip
toplinks
trello
tripathi
truetype
tsx
ttext
ttf
TTFB
ttg
tumblr
typedef
typeid
typename
typeof
uage
ubuntu
uid
uint
ulk
ulong
uname
undef
unicode
unmounts
unsubscribe
upvotes
uri
url
URLCONF
urlencode
urlencoded
urlify
urllib
urlpatterns
usd
username
userphoto
userpic
usertasks
ushort
usr
utc
utf
utils
UUID
UXux
validator
venv
vercel
verdana
vhdl
VHOST
viewlink
viewsets
viewsitelink
vimeo
visualise
vitejs
vitest
vmin
vnd
vscode
vue
wantarray
webfont
webkit
webpack
website
weibo
whiteants
whitenoise
wiki
winutils
woff
WORKDIR
wsgi
www
xae
xaxis
xcode
XFrame
xfull
xhr
XHT
xhtml
XIcon
xing
xlink
xml
xmlns
xmp
XReg
xsl
xss
yaml
yapf
yaxis
youmightnotneedjquery
youtube
yuaoh
yzo
Some files were automatically ignored 🙈

These sample patterns would exclude them:

(?:^|/)__init__\.py$
(?:^|/)codechef\.svg$
(?:^|/)github\.svg$
(?:^|/)leetcode\.svg$
(?:^|/)pnpm-lock\.yaml$
[^/]\.eot$
[^/]\.ttf$
[^/]\.woff$
^\Q.cspell.json\E$
^\Qapi/staticfiles_build/static/rest_framework/docs/js/highlight.pack.js\E$
^\Qapi/staticfiles_build/static/rest_framework/js/coreapi-0.1.1.js\E$
^api/leaderboard/contest_data\.json$
^api/requirements\.txt$
^api/staticfiles_build/static/admin/img/gis/
^api/staticfiles_build/static/rest_framework/fonts/glyphicons-halflings-regular\.woff2$
^app/dump\.rdb$
^app/src/logo\.svg$

You should consider excluding directory paths (e.g. (?:^|/)vendor/), filenames (e.g. (?:^|/)yarn\.lock$), or file extensions (e.g. \.gz$)

You should consider adding them to:

.github/actions/spelling/excludes.txt

File matching is via Perl regular expressions.

To check these files, more of their words need to be in the dictionary than not. You can use patterns.txt to exclude portions, add items to the dictionary (e.g. by adding them to allow.txt), or fix typos.

To accept these unrecognized words as correct and update file exclusions, you could run the following commands

... in a clone of the git@github.com:VarshiniGunti/Leaderboard-Pro.git repository
on the feat/openlake-pr-key-filter branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/main/apply.pl' |
perl - 'https://github.com/OpenLake/Leaderboard-Pro/actions/runs/22404973202/attempts/1' &&
git commit -m 'Update check-spelling metadata'
Available 📚 dictionaries could cover words not in the 📘 dictionary
Dictionary Entries Covers Uniquely
cspell:django/dict/django.txt 393 63 18
cspell:software-terms/dict/softwareTerms.txt 1288 106 15
cspell:python/src/common/extra.txt 741 20 13
cspell:npm/dict/npm.txt 302 46 10
cspell:html/dict/html.txt 2060 46 7

Consider adding them (in .github/workflows/spelling.yml) in jobs:/spelling::

      with:
        extra_dictionaries: |
          cspell:django/dict/django.txt
          cspell:software-terms/dict/softwareTerms.txt
          cspell:python/src/common/extra.txt
          cspell:npm/dict/npm.txt
          cspell:html/dict/html.txt

To stop checking additional dictionaries, add (in .github/workflows/spelling.yml):

check_extra_dictionaries: ""
Warnings ⚠️ (4)

See the 📂 files view, the 📜action log, or 📝 job summary for details.

⚠️ Warnings Count
⚠️ binary-file 15
⚠️ minified-file 1
⚠️ noisy-file 5
⚠️ single-line-file 10

See ⚠️ Event descriptions for more information.

If you see a bunch of garbage

If it relates to a ...

well-formed pattern

See if there's a pattern that would match it.

If not, try writing one and adding it to the patterns.txt file.

Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

Note that patterns can't match multiline strings.

binary-ish string

Please add a file path to the excludes.txt file instead of just accepting the garbage.

File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FOSSOVERFLOW-26] feat: add a key based filter in OpenLake Leaderboard

1 participant