1515
1616import java .util .Comparator ;
1717import java .util .List ;
18+ import java .util .Set ;
19+ import java .util .stream .Collectors ;
1820
1921@ ApplicationScoped
2022public class MembersTab {
@@ -65,13 +67,48 @@ public void render(JtContainer membersTab) {
6567
6668 if (Jt .button ("🔄 Sync Members from GitHub" ).use (columns .col (1 ))) {
6769 try {
68- firestoreServices .deleteAllMembers ();
70+ // Load current state from Firestore and GitHub
71+ List <ZenikaMember > existingMembers = firestoreServices .getAllMembers ();
6972 List <GitHubMember > gitHubMembers = gitHubServices .getZenikaOpenSourceMembers ();
70-
73+
74+ Set <String > currentGitHubLogins = gitHubMembers .stream ()
75+ .map (GitHubMember ::getLogin )
76+ .collect (Collectors .toSet ());
77+
78+ int added = 0 ;
79+ int updated = 0 ;
80+ int removed = 0 ;
81+
82+ // Upsert: add/update members based on GitHub organization
7183 for (GitHubMember gitHubMember : gitHubMembers ) {
72- firestoreServices .createMember (ZenikaMemberMapper .mapGitHubMemberToZenikaMember (gitHubMember ));
84+ ZenikaMember existing = existingMembers .stream ()
85+ .filter (m -> m .getGitHubAccount () != null
86+ && gitHubMember .getLogin ().equals (m .getGitHubAccount ().getLogin ()))
87+ .findFirst ()
88+ .orElse (null );
89+
90+ if (existing == null ) {
91+ firestoreServices .createMember (
92+ ZenikaMemberMapper .mapGitHubMemberToZenikaMember (gitHubMember ));
93+ added ++;
94+ } else {
95+ existing .setGitHubAccount (gitHubMember );
96+ firestoreServices .createMember (existing );
97+ updated ++;
98+ }
99+ }
100+
101+ // Remove members that are no longer in the GitHub organization
102+ for (ZenikaMember member : existingMembers ) {
103+ if (member .getGitHubAccount () != null
104+ && !currentGitHubLogins .contains (member .getGitHubAccount ().getLogin ())) {
105+ firestoreServices .deleteMember (member .getId ());
106+ removed ++;
107+ }
73108 }
74- Jt .success ("Successfully synced " + gitHubMembers .size () + " members!" ).use (membersTab );
109+
110+ Jt .success ("✅ Synchronization completed: " + added + " added, " + updated + " updated, " + removed
111+ + " removed." ).use (membersTab );
75112 } catch (DatabaseException e ) {
76113 Jt .error ("Error syncing members: " + e .getMessage ()).use (membersTab );
77114 }
@@ -102,8 +139,26 @@ public void render(JtContainer membersTab) {
102139 var row = Jt .columns (6 ).key ("member_row_" + m .getId ()).use (membersTab );
103140 Jt .text (m .getFirstname () != null ? m .getFirstname () : "" ).use (row .col (0 ));
104141 Jt .text (m .getName () != null ? m .getName () : "" ).use (row .col (1 ));
105- Jt .text (m .getGitHubAccount () != null ? m .getGitHubAccount ().getLogin () : "" ).use (row .col (2 ));
106- Jt .text (m .getGitlabAccount () != null ? m .getGitlabAccount ().getUsername () : "" ).use (row .col (3 ));
142+
143+ if (m .getGitHubAccount () != null && m .getGitHubAccount ().getLogin () != null ) {
144+ String githubLogin = m .getGitHubAccount ().getLogin ();
145+ String githubLinkMarkdown = "<a href=\" https://github.com/" + githubLogin
146+ + "\" target=\" _blank\" rel=\" noopener noreferrer\" >"
147+ + githubLogin + "</a>" ;
148+ Jt .markdown (githubLinkMarkdown ).use (row .col (2 ));
149+ } else {
150+ Jt .text ("" ).use (row .col (2 ));
151+ }
152+
153+ if (m .getGitlabAccount () != null && m .getGitlabAccount ().getUsername () != null ) {
154+ String gitlabUsername = m .getGitlabAccount ().getUsername ();
155+ String gitlabLinkMarkdown = "<a href=\" https://gitlab.com/" + gitlabUsername
156+ + "\" target=\" _blank\" rel=\" noopener noreferrer\" >"
157+ + gitlabUsername + "</a>" ;
158+ Jt .markdown (gitlabLinkMarkdown ).use (row .col (3 ));
159+ } else {
160+ Jt .text ("" ).use (row .col (3 ));
161+ }
107162 Jt .text (m .getCity () != null ? m .getCity () : "" ).use (row .col (4 ));
108163 if (Jt .button ("📝" ).key ("btn_edit_" + m .getId ()).use (row .col (5 ))) {
109164 selectedMemberId = m .getId ();
@@ -128,7 +183,7 @@ public void render(JtContainer membersTab) {
128183 m .setCity (newCity );
129184 firestoreServices .createMember (m );
130185 selectedMemberId = null ;
131- Jt .success ("Successfully updated ✅ " ).use (membersTab );
186+ Jt .success ("✅ Successfully updated" ).use (membersTab );
132187 Jt .markdown ("<style>#edit_row_" + m .getId () + " { display: none !important; }</style>" ).use (membersTab );
133188 }
134189 if (Jt .button ("Cancel" ).key ("btn_cancel_" + m .getId ()).use (editRow .col (5 ))) {
0 commit comments