22
33import io .github .silentdevelopment .headdb .database .DatabaseStats ;
44import io .github .silentdevelopment .headdb .database .DatabaseStatus ;
5+ import io .github .silentdevelopment .headdb .paper .HeadDBPlugin ;
56import io .github .silentdevelopment .headdb .paper .permission .Permissions ;
67import io .github .silentdevelopment .headdb .paper .runtime .RefreshState ;
7- import io .github .silentdevelopment .headdb .paper .runtime .PluginRuntime ;
88import net .kyori .adventure .text .Component ;
99import net .kyori .adventure .text .event .ClickEvent ;
1010import net .kyori .adventure .text .event .HoverEvent ;
1616import java .time .Instant ;
1717import java .time .ZoneId ;
1818import java .time .format .DateTimeFormatter ;
19+ import java .util .ArrayList ;
1920import java .util .List ;
2021import java .util .Objects ;
2122
@@ -26,77 +27,126 @@ public final class StatusFormatter {
2627 private StatusFormatter () {
2728 }
2829
29- public static @ NotNull List <Component > format (@ NotNull PluginRuntime runtime , @ NotNull CommandSender sender ) {
30- Objects .requireNonNull (runtime , "runtime " );
30+ public static @ NotNull List <Component > format (@ NotNull HeadDBPlugin plugin , @ NotNull CommandSender sender ) {
31+ Objects .requireNonNull (plugin , "plugin " );
3132 Objects .requireNonNull (sender , "sender" );
3233
33- DatabaseStatus status = runtime .database ().status ();
34- DatabaseStats stats = runtime .database ().stats ();
35- RefreshState refresh = runtime .refreshState ();
36-
37- return List .of (
38- Component .empty (),
39- Component .text ("> " , NamedTextColor .GRAY ).append (Component .text ("HeadDB Status" , NamedTextColor .RED )),
40- databaseStatusLine (status , sender ),
41- line ("Source" , status .source ()),
42- line ("Manifest ID" , value (status .manifestId ())),
43- line ("Catalog ID" , value (status .artifactId ())),
44- line ("Loaded at" , formatInstant (status .loadedAt ())),
45- Component .empty (),
46- line ("Heads" , stats .heads ()),
47- line ("Categories" , stats .categories ()),
48- line ("Tags" , stats .tags ()),
49- line ("Collections" , stats .collections ()),
50- line ("Revocations" , stats .revocations ()),
51- Component .empty (),
52- line ("Refresh running" , yesNo (refresh .running ())),
53- line ("Last failure" , formatFailure (refresh .lastFailureMessage ())),
54- Component .empty ()
55- );
34+ DatabaseStatus status = plugin .runtime ().database ().status ();
35+ DatabaseStats remoteStats = plugin .runtime ().database ().stats ();
36+ RefreshState refresh = plugin .runtime ().refreshState ();
37+
38+ int hiddenHeads = plugin .headRegistry ().hiddenHeads ().size ();
39+ int moreHeads = plugin .headRegistry ().customHeads ().list ().size ();
40+ int overrides = plugin .headRegistry ().overrides ().list ().size ();
41+ int playerHeads = plugin .headRegistry ().playerHeads ().knownPlayers ().size ();
42+ int moreCategories = plugin .customCategories ().list ().size ();
43+
44+ List <Component > lines = new ArrayList <>();
45+ lines .add (Component .empty ());
46+ lines .add (Component .text ("> " , NamedTextColor .DARK_GRAY ).append (Component .text ("Status" , NamedTextColor .RED )));
47+ lines .add (databaseLine (status ));
48+ lines .add (line ("Heads" , remoteStats .heads ()));
49+ lines .add (line ("Hidden Heads" , hiddenHeads ));
50+ lines .add (line ("More Heads" , moreHeads ));
51+ lines .add (line ("Player Heads" , playerHeads ));
52+ lines .add (line ("Categories" , remoteStats .categories ()));
53+ lines .add (line ("More Categories" , moreCategories ));
54+ lines .add (line ("Tags" , remoteStats .tags ()));
55+ lines .add (line ("Collections" , remoteStats .collections ()));
56+ lines .add (line ("Revocations" , remoteStats .revocations ()));
57+ lines .add (line ("Overrides" , overrides ));
58+ lines .add (refreshLine (refresh , sender ));
59+ lines .add (lastRefreshLine (refresh ));
60+
61+ String failure = firstPresent (status .lastError (), refresh .lastFailureMessage ());
62+ if (failure != null ) {
63+ lines .add (line ("Last error" , failure ));
64+ }
65+
66+ addSupportLine (lines , sender );
67+ lines .add (Component .empty ());
68+ return List .copyOf (lines );
5669 }
5770
58- private static @ NotNull Component databaseStatusLine (@ NotNull DatabaseStatus status , @ NotNull CommandSender sender ) {
59- Component line = Component .text ("Status: " , NamedTextColor .GRAY ).append (Component .text (String .valueOf (status .state ()), statusColor (status )));
71+ private static @ NotNull Component databaseLine (@ NotNull DatabaseStatus status ) {
72+ Component line = Component .text ("Database: " , NamedTextColor .GRAY ).append (Component .text (String .valueOf (status .state ()), statusColor (status )));
73+ String source = value (status .source ());
6074
61- if (isLoaded ( status )) {
62- return line ;
75+ if (! source . equals ( "none" )) {
76+ line = line . append ( Component . text ( " from " , NamedTextColor . GRAY )). append ( Component . text ( source , NamedTextColor . GOLD )) ;
6377 }
6478
65- if (!Permissions .has (sender , Permissions .REFRESH )) {
66- return line ;
79+ return line ;
80+ }
81+
82+ private static @ NotNull Component refreshLine (@ NotNull RefreshState refresh , @ NotNull CommandSender sender ) {
83+ String text = refresh .running () ? "running " + refresh .currentOperation () : "idle" ;
84+ Component line = line ("Refresh" , text );
85+
86+ if (!refresh .running () && Permissions .has (sender , Permissions .REFRESH )) {
87+ line = line .append (Component .text (" " )).append (refreshButton ());
6788 }
6889
69- return line . append ( Component . text ( " " )). append ( refreshButton ()) ;
90+ return line ;
7091 }
7192
72- private static boolean isLoaded (@ NotNull DatabaseStatus status ) {
73- return "LOADED" .equalsIgnoreCase (String .valueOf (status .state ()));
74- }
93+ private static @ NotNull Component lastRefreshLine (@ NotNull RefreshState refresh ) {
94+ if (refresh .lastOutcome () == RefreshState .RefreshOutcome .SUCCESS ) {
95+ return line ("Last Refresh" , refresh .lastOperation () + " completed at " + formatInstant (refresh .lastSuccessfulRefresh ()));
96+ }
7597
76- private static @ NotNull NamedTextColor statusColor (@ NotNull DatabaseStatus status ) {
77- if (isLoaded (status )) {
78- return NamedTextColor .GOLD ;
98+ if (refresh .lastOutcome () == RefreshState .RefreshOutcome .FAILURE ) {
99+ return line ("Last Refresh" , refresh .lastOperation () + " failed at " + formatInstant (refresh .lastFailedRefresh ()));
79100 }
80101
81- return NamedTextColor . RED ;
102+ return line ( "Last Refresh" , "never" ) ;
82103 }
83104
84105 private static @ NotNull Component refreshButton () {
85- return Component .text ("[ " , NamedTextColor .DARK_GRAY )
86- .append (Component .text ("REFRESH" , NamedTextColor .GOLD ).clickEvent (ClickEvent .runCommand ("/hdb refresh" )).hoverEvent (HoverEvent .showText (Component .text ("Click to refresh the HeadDB database." , NamedTextColor .GRAY ))))
87- .append (Component .text (" ]" , NamedTextColor .DARK_GRAY ));
106+ return Component .text ("[ " , NamedTextColor .DARK_GRAY ).append (Component .text ("REFRESH" , NamedTextColor .GOLD ).clickEvent (ClickEvent .runCommand ("/hdb refresh" )).hoverEvent (HoverEvent .showText (Component .text ("Click to refresh the database." , NamedTextColor .GRAY )))).append (Component .text (" ]" , NamedTextColor .DARK_GRAY ));
88107 }
89108
90- private static @ NotNull Component line (@ NotNull String key , @ Nullable Object value ) {
91- return Component .text (key + ": " , NamedTextColor .GRAY ).append (Component .text (String .valueOf (value ), NamedTextColor .GOLD ));
109+ private static void addSupportLine (@ NotNull List <Component > lines , @ NotNull CommandSender sender ) {
110+ boolean canDebug = Permissions .has (sender , Permissions .DEBUG );
111+ boolean canReport = Permissions .has (sender , Permissions .REPORT );
112+
113+ if (!canDebug && !canReport ) {
114+ return ;
115+ }
116+
117+ Component line = Component .text ("Support: " , NamedTextColor .GRAY );
118+
119+ if (canDebug ) {
120+ line = line .append (Component .text ("/hdb debug" , NamedTextColor .GOLD ));
121+ }
122+
123+ if (canDebug && canReport ) {
124+ line = line .append (Component .text (" | " , NamedTextColor .DARK_GRAY ));
125+ }
126+
127+ if (canReport ) {
128+ line = line .append (Component .text ("/hdb report" , NamedTextColor .GOLD ));
129+ }
130+
131+ lines .add (line );
92132 }
93133
94- private static @ NotNull String yesNo (boolean value ) {
95- if (value ) {
96- return "yes" ;
134+ private static @ NotNull NamedTextColor statusColor (@ NotNull DatabaseStatus status ) {
135+ String state = String .valueOf (status .state ());
136+
137+ if ("LOADED" .equalsIgnoreCase (state )) {
138+ return NamedTextColor .GOLD ;
139+ }
140+
141+ if ("LOADING" .equalsIgnoreCase (state )) {
142+ return NamedTextColor .YELLOW ;
97143 }
98144
99- return "no" ;
145+ return NamedTextColor .RED ;
146+ }
147+
148+ private static @ NotNull Component line (@ NotNull String key , @ Nullable Object value ) {
149+ return Component .text (key + ": " , NamedTextColor .GRAY ).append (Component .text (String .valueOf (value ), NamedTextColor .GOLD ));
100150 }
101151
102152 private static @ NotNull String formatInstant (@ Nullable Instant instant ) {
@@ -107,19 +157,35 @@ private static boolean isLoaded(@NotNull DatabaseStatus status) {
107157 return TIME_FORMAT .format (instant );
108158 }
109159
110- private static @ NotNull String formatFailure (@ Nullable String message ) {
111- if (message == null || message . isBlank () ) {
160+ private static @ NotNull String value (@ Nullable Object value ) {
161+ if (value == null ) {
112162 return "none" ;
113163 }
114164
115- return message ;
165+ String string = String .valueOf (value );
166+ if (string .isBlank ()) {
167+ return "none" ;
168+ }
169+
170+ return string ;
116171 }
117172
118- private static @ NotNull String value (@ Nullable Object value ) {
119- if (value == null ) {
120- return "none" ;
173+ private static @ Nullable String firstPresent (@ Nullable String first , @ Nullable String second ) {
174+ String normalizedFirst = normalize (first );
175+
176+ if (normalizedFirst != null ) {
177+ return normalizedFirst ;
121178 }
122179
123- return String . valueOf ( value );
180+ return normalize ( second );
124181 }
125- }
182+
183+ private static @ Nullable String normalize (@ Nullable String value ) {
184+ if (value == null || value .isBlank ()) {
185+ return null ;
186+ }
187+
188+ return value .trim ();
189+ }
190+
191+ }
0 commit comments