Skip to content

Commit 7b43ef0

Browse files
committed
improve dashboard tagging
1 parent bff828d commit 7b43ef0

File tree

2 files changed

+136
-42
lines changed

2 files changed

+136
-42
lines changed

assets/styles.css

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,20 @@ a {
691691
border-color: rgba(0, 122, 255, 0.25);
692692
}
693693

694+
/* Incoming PRs blocked on viewing user - red border */
695+
#incomingPRs .pr-card[data-blocked-on-viewing="true"] {
696+
border-color: rgba(220, 38, 38, 0.4);
697+
border-left-width: 3px;
698+
border-left-color: #dc2626;
699+
}
700+
701+
/* Outgoing PRs blocked on viewing user - green border */
702+
#outgoingPRs .pr-card[data-blocked-on-viewing="true"] {
703+
border-color: rgba(34, 197, 94, 0.4);
704+
border-left-width: 3px;
705+
border-left-color: #22c55e;
706+
}
707+
694708
/* Draft PR cards */
695709
.pr-card[data-draft="true"] {
696710
opacity: 0.7;
@@ -772,6 +786,13 @@ a {
772786
color: #ffffff;
773787
}
774788

789+
.badge-blocked-on-you {
790+
background: #dc2626;
791+
color: #ffffff;
792+
font-weight: 700;
793+
text-transform: uppercase;
794+
}
795+
775796
.badge-ready {
776797
background: linear-gradient(135deg, #34c759 0%, #30d158 100%);
777798
color: #ffffff;
@@ -890,7 +911,7 @@ a {
890911
}
891912

892913
.badge-merge-conflict {
893-
background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%);
914+
background: #FA8072;
894915
color: #ffffff;
895916
font-weight: 700;
896917
}
@@ -903,9 +924,7 @@ a {
903924

904925
/* Waiting on section */
905926
.pr-waiting-on {
906-
display: inline-flex;
907-
align-items: center;
908-
gap: 0.25rem;
927+
display: inline;
909928
color: var(--color-text-secondary);
910929
font-size: 0.875rem;
911930
}
@@ -930,6 +949,11 @@ a {
930949
font-weight: 700;
931950
}
932951

952+
.pr-waiting-on-you-green {
953+
color: #166534;
954+
font-weight: 700;
955+
}
956+
933957
/* Replaced animated dots with static text for performance */
934958

935959
/* Removed funkyBounce animation for performance */

assets/user.js

Lines changed: 108 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -807,44 +807,46 @@ export const User = (() => {
807807
return filtered;
808808
};
809809

810+
const isBlockedOnUser = (pr, user) => {
811+
if (!pr.turnData?.pr_state?.unblock_action || !user) return false;
812+
return Object.keys(pr.turnData.pr_state.unblock_action).includes(user.login);
813+
};
814+
810815
const renderPRList = (container, prs, isDraft = false, section = "", state) => {
811816
if (!container) return;
812817

813818
const filteredPRs = applyFilters(prs, section);
819+
const currentUser = window.App?.state?.currentUser || null;
820+
const viewingUser = window.App?.state?.viewingUser || currentUser;
814821

815822
const sortedPRs = [...filteredPRs].sort((a, b) => {
816-
if (a.draft && !b.draft) return 1;
817-
if (!a.draft && b.draft) return -1;
818-
819-
if (a.draft === b.draft) {
820-
if (!a.draft && !b.draft) {
821-
if (
822-
a.status_tags?.includes("blocked on you") &&
823-
!b.status_tags?.includes("blocked on you")
824-
)
825-
return -1;
826-
if (
827-
!a.status_tags?.includes("blocked on you") &&
828-
b.status_tags?.includes("blocked on you")
829-
)
830-
return 1;
831-
832-
if (
833-
a.status_tags?.includes("ready-to-merge") &&
834-
!b.status_tags?.includes("ready-to-merge")
835-
)
836-
return -1;
837-
if (
838-
!a.status_tags?.includes("ready-to-merge") &&
839-
b.status_tags?.includes("ready-to-merge")
840-
)
841-
return 1;
842-
}
843-
844-
return new Date(b.updated_at) - new Date(a.updated_at);
823+
// Categorize PRs
824+
const aBlockedOnViewing = isBlockedOnUser(a, viewingUser);
825+
const bBlockedOnViewing = isBlockedOnUser(b, viewingUser);
826+
const aDraft = a.draft || false;
827+
const bDraft = b.draft || false;
828+
829+
// Priority 1: Blocked on viewing user
830+
// Priority 2: Normal (not blocked, not draft)
831+
// Priority 3: Draft
832+
833+
// Determine categories
834+
const getCategory = (pr) => {
835+
if (isBlockedOnUser(pr, viewingUser)) return 1; // Highest priority
836+
if (pr.draft) return 3; // Lowest priority
837+
return 2; // Normal
838+
};
839+
840+
const aCategory = getCategory(a);
841+
const bCategory = getCategory(b);
842+
843+
// Sort by category first
844+
if (aCategory !== bCategory) {
845+
return aCategory - bCategory;
845846
}
846-
847-
return 0;
847+
848+
// Within same category, sort by last modification time (most recent first - descending order)
849+
return new Date(b.updated_at) - new Date(a.updated_at);
848850
});
849851

850852
container.innerHTML = sortedPRs.map((pr) => createPRCard(pr)).join("");
@@ -854,12 +856,60 @@ export const User = (() => {
854856
}
855857
};
856858

859+
const buildWaitingOn = (pr, viewingUser, currentUser, isIncomingPR = false) => {
860+
if (!pr.turnData?.pr_state?.unblock_action) {
861+
return '';
862+
}
863+
864+
// unblock_action is a dictionary where keys are usernames and values have critical/reason
865+
const unblockAction = pr.turnData.pr_state.unblock_action;
866+
const usernames = Object.keys(unblockAction);
867+
868+
if (usernames.length === 0) {
869+
return '';
870+
}
871+
872+
const waitingList = usernames.map(username => {
873+
const action = unblockAction[username];
874+
const isViewingUser = viewingUser && username === viewingUser.login;
875+
const isCurrentUser = currentUser && username === currentUser.login;
876+
877+
let displayName = username;
878+
let className = 'pr-waiting-on-user';
879+
880+
// If viewing someone else's dashboard, highlight their name
881+
if (viewingUser && currentUser && viewingUser.login !== currentUser.login) {
882+
if (isViewingUser) {
883+
displayName = viewingUser.login;
884+
// Use red for incoming PRs, green for outgoing
885+
className = isIncomingPR ? 'pr-waiting-on-you' : 'pr-waiting-on-you-green';
886+
}
887+
} else {
888+
// Normal behavior when viewing your own dashboard
889+
if (isCurrentUser) {
890+
displayName = 'YOU';
891+
className = 'pr-waiting-on-you';
892+
}
893+
}
894+
895+
const title = action.reason || 'Waiting for action';
896+
897+
return `<span class="${className}" title="${escapeHtml(title)}">${escapeHtml(displayName)}</span>`;
898+
}).join(', ');
899+
900+
return ` <span class="pr-waiting-on"><span class="pr-waiting-on-label">(waiting on</span> ${waitingList}<span class="pr-waiting-on-label">)</span></span>`;
901+
};
902+
857903
const createPRCard = (pr) => {
858904
const state = getPRState(pr);
859-
const badges = buildBadges(pr);
905+
const currentUser = window.App?.state?.currentUser || null;
906+
const viewingUser = window.App?.state?.viewingUser || currentUser;
907+
const badges = buildBadges(pr, viewingUser, currentUser);
860908
const ageText = getAgeText(pr);
861909
const reviewers = buildReviewers(pr.requested_reviewers || []);
862910
const needsAction = pr.status_tags?.includes("blocked on you");
911+
// Determine if this is an incoming PR (PR author is not the viewing user)
912+
const isIncomingPR = pr.user.login !== (viewingUser?.login || currentUser?.login);
863913

864914
const getActivityIcon = (type) => {
865915
const icons = {
@@ -936,8 +986,10 @@ export const User = (() => {
936986
</div>
937987
`;
938988

989+
const blockedOnViewing = isBlockedOnUser(pr, viewingUser);
990+
939991
return `
940-
<div class="pr-card" data-state="${state}" data-pr-id="${pr.id}" ${needsAction ? 'data-needs-action="true"' : ""} ${pr.draft ? 'data-draft="true"' : ""}>
992+
<div class="pr-card" data-state="${state}" data-pr-id="${pr.id}" ${needsAction ? 'data-needs-action="true"' : ""} ${pr.draft ? 'data-draft="true"' : ""} ${blockedOnViewing ? 'data-blocked-on-viewing="true"' : ""}>
941993
<div class="pr-header">
942994
<a href="${pr.html_url}" class="pr-title" target="_blank" rel="noopener">
943995
${escapeHtml(pr.title)}
@@ -950,6 +1002,7 @@ export const User = (() => {
9501002
<span class="pr-repo">${pr.repository.full_name}</span>
9511003
<span class="pr-number">#${pr.number}</span>
9521004
<span class="pr-author">by ${pr.user.login}</span>
1005+
${buildWaitingOn(pr, viewingUser, currentUser, isIncomingPR)}
9531006
</div>
9541007
<div class="pr-meta-right">
9551008
<span class="pr-age">${ageText}</span>
@@ -968,6 +1021,17 @@ export const User = (() => {
9681021
const section = existingCard.closest("#incomingPRs")
9691022
? "incoming"
9701023
: "outgoing";
1024+
1025+
// Check if this PR's blocking status affects sorting
1026+
const viewingUser = state.viewingUser || state.currentUser;
1027+
const wasBlockedOnViewing = existingCard.hasAttribute('data-blocked-on-viewing');
1028+
const isNowBlockedOnViewing = isBlockedOnUser(pr, viewingUser);
1029+
1030+
// If blocking status changed, re-render the entire section to maintain sort order
1031+
if (wasBlockedOnViewing !== isNowBlockedOnViewing) {
1032+
updatePRSections(state);
1033+
return;
1034+
}
9711035

9721036
const hideStale = getCookie(`${section}FilterStale`) === "true";
9731037
const shouldHide = (hideStale && isStale(pr));
@@ -1029,7 +1093,7 @@ export const User = (() => {
10291093
return "xlarge";
10301094
};
10311095

1032-
const buildBadges = (pr) => {
1096+
const buildBadges = (pr, viewingUser, currentUser) => {
10331097
const badges = [];
10341098

10351099
// Add prominent badges first based on turnData
@@ -1050,15 +1114,21 @@ export const User = (() => {
10501114
badges.push('<span class="badge badge-draft">draft</span>');
10511115
}
10521116

1117+
// Check if PR is blocked on viewing user
1118+
if (isBlockedOnUser(pr, viewingUser)) {
1119+
if (viewingUser && currentUser && viewingUser.login === currentUser.login) {
1120+
badges.push('<span class="badge badge-blocked-on-you">blocked on you</span>');
1121+
} else if (viewingUser) {
1122+
badges.push(`<span class="badge badge-blocked-on-you">blocked on ${viewingUser.login}</span>`);
1123+
}
1124+
}
1125+
10531126
if (pr.status_tags?.includes("loading")) {
10541127
badges.push('<span class="badge badge-loading">Loading</span>');
10551128
} else if (pr.status_tags && pr.status_tags.length > 0) {
10561129
const needsBadges = pr.status_tags
1057-
.filter((tag) => tag.startsWith("needs-") || tag === "blocked on you")
1130+
.filter((tag) => tag.startsWith("needs-"))
10581131
.map((tag) => {
1059-
if (tag === "blocked on you") {
1060-
return '<span class="badge badge-blocked">blocked on you</span>';
1061-
}
10621132
const displayText = tag.replace("needs-", "").replace(/_/g, " ");
10631133
return `<span class="badge badge-needs">${displayText}</span>`;
10641134
});

0 commit comments

Comments
 (0)