89d643157dbb3f627ca3aa7193b9a05374d224b5
[nit.git] / contrib / nitrpg / src / templates / panels.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Panels templates for `nitpg`.
18 module panels
19
20 import templates_events
21
22 # A panel can be displayed in a html page.
23 #
24 # This display a Bootstrap panel.
25 class Panel
26 super Template
27
28 redef fun rendering do
29 add """<div class="panel panel-default">
30 <div class="panel-heading">
31 <h3 class="panel-title">"""
32 render_title
33 add """ </h3>
34 </div>
35 <div class="panel-body">"""
36 render_body
37 add """</div>
38 </div>"""
39 end
40
41 # Render the panel title.
42 # Betweem `<h4>` tags.
43 fun render_title do end
44
45 # Render the panel body.
46 fun render_body do end
47 end
48
49 # A panel that contain only a table as body.
50 class TablePanel
51 super Panel
52
53 redef fun rendering do
54 add """<div class="panel panel-default">
55 <div class="panel-heading">
56 <h3 class="panel-title">"""
57 render_title
58 add """
59 </h3>
60 </div>"""
61 render_body
62 add """</div>"""
63 end
64 end
65
66 # Display an error message within a panel.
67 class ErrorPanel
68 super Panel
69
70 redef fun rendering do
71 add """
72 <div class="panel panel-danger">
73 <div class="panel-heading">
74 <h3 class="panel-title">"""
75 render_title
76 add """
77 </h3>
78 </div>
79 <div class="panel-body">"""
80 render_body
81 add """
82 </div>
83 </div>
84 """
85 end
86
87 # The error message to display as panel body.
88 var msg: String
89
90 redef fun render_title do
91 add "<span class=\"glyphicon glyphicon-warning-sign\"></span>&nbsp;&nbsp;"
92 add "Error"
93 end
94
95 redef fun render_body do
96 add msg.html_escape
97 end
98
99 end
100
101 # A panel that display repo statistics.
102 class GameStatusPanel
103 super Panel
104
105 # Repo to display.
106 var game: Game
107
108 redef fun render_title do
109 add "<span class=\"glyphicon glyphicon-home\"></span>&nbsp;&nbsp;"
110 add "{game.link}"
111 end
112
113 redef fun render_body do
114 add "<strong class=\"text-success\">{game.load_players.length}</strong>"
115 add " <a href=\"{game.url}/players\">players</a><br><br>"
116 add "<strong class=\"text-success\">{game.stats["pulls"]}</strong> pull requests"
117 add " (<strong>{game.stats["pulls_open"]}</strong> open)<br>"
118 add "<strong class=\"text-success\">{game.stats["issues"]}</strong> issues"
119 add " (<strong>{game.stats["issues_open"]}</strong> open)<br>"
120 add "<strong class=\"text-success\">{game.stats["commits"]}</strong> commits"
121 end
122 end
123
124 # Player status panel.
125 class PlayerStatusPanel
126 super Panel
127
128 # Game instance.
129 var game: Game
130
131 # Target player.
132 var player: Player
133
134 redef fun render_title do
135 add "<a href=\"{player.url}\">"
136 add " <img class=\"img-circle\" style=\"width: 30px\""
137 add " src=\"{player.user.avatar_url}\" alt=\"{player.name}\">"
138 add "</a>&nbsp;&nbsp;{player.link}"
139 end
140
141 redef fun render_body do
142 var ranking = game.player_ranking
143 # TODO player.rank
144 add "<p class=\"lead\">ranked "
145 add " <span class=\"text-success\"># {ranking[player.name]}</span></p>"
146 add "<strong class=\"text-success\">{player.nitcoins}</strong> nitcoins<br><br>"
147 add "<strong>{player.stats["pulls"]}</strong> pull requests<br>"
148 add "<strong>{player.stats["issues"]}</strong> issues<br>"
149 add "<strong>{player.stats["commits"]}</strong> commits"
150 end
151 end
152
153 # A panel that display a list of player in a repo.
154 class ShortListPlayersPanel
155 super Panel
156
157 # Game instance.
158 var game: Game
159
160 redef fun render_title do
161 add "<span class=\"glyphicon glyphicon-user\"></span>&nbsp;&nbsp;"
162 add "<a href=\"{game.url}/players\">Players</a>"
163 end
164
165 redef fun render_body do
166 var players = game.load_players.values.to_a
167 if players.is_empty then
168 add "<em>No player yet...</em>"
169 return
170 end
171 (new PlayerCoinComparator).sort(players)
172 for player in players do
173 add "{player.nitcoins} - {player.link}<br>"
174 end
175 end
176 end
177
178 # A panel that display a list of player in a repo.
179 class ListPlayersPanel
180 super TablePanel
181
182 # Game instance.
183 var game: Game
184
185 redef fun render_title do
186 add "<span class=\"glyphicon glyphicon-user\"></span>&nbsp;&nbsp;"
187 add "<a href=\"{game.url}/players\">Players</a>"
188 end
189
190 redef fun render_body do
191 var players = game.load_players.values.to_a
192 (new PlayerCoinComparator).sort(players)
193 if players.is_empty then
194 add "<div class=\"panel-body\">"
195 add "<em>No player yet...</em>"
196 add "</div>"
197 return
198 end
199 add """<table class="table table-striped table-hover">
200 <tr>
201 <th>#</th>
202 <th>Player</th>
203 <th>Nitcoins</th>
204 </tr>"""
205 var rank = 1
206 for player in players do
207 add "<tr>"
208 add " <td>{rank}</td>"
209 add " <td>{player.link}</td>"
210 add " <td>{player.nitcoins}</td>"
211 add "</tr>"
212 rank += 1
213 end
214 add "</table>"
215 end
216 end
217
218 # A panel that display the podium.
219 class PodiumPanel
220 super Panel
221
222 # Game instance.
223 var game: Game
224
225 redef fun render_title do
226 add "<span class=\"glyphicon glyphicon-stats\"></span>&nbsp;&nbsp;Hall of fame"
227 end
228
229 redef fun render_body do
230 var players = game.load_players.values.to_a
231 (new PlayerCoinComparator).sort(players)
232 if players.is_empty then
233 add "<em>No players yet...</em>"
234 return
235 end
236 add """
237 <div class="container-fluid">
238 <div id="podium" class="row row-sm-height">"""
239 var max = players.first.nitcoins
240 var orders = [3, 1, 0, 2, 4]
241 for order in orders do
242 if order >= players.length then continue
243 var player = players[order]
244 var size = 0
245 if max > 0 then size = player.nitcoins * 300 / max
246 add """
247 <div class="col-xs-2 col-xs-height col-xs-offset-{{{order}}} col-bottom"
248 style="text-align: center;">
249 <p>
250 <a href="{{{player.url}}}">
251 <img class="img-circle" style="width: 80px"
252 src="{{{player.user.avatar_url}}}" alt="{{{player.name}}}">
253 </a>
254 </p>
255 <p>{{{player.link}}}</p>
256 <p>{{{player.nitcoins}}}</p>
257 <div class=" progress-bar-warning progress-bar-striped"
258 style="height: {{{size}}}px;"></div>
259 </div>"""
260 end
261 add """
262 </div>
263 </div>"""
264 end
265 end
266
267 # A `Panel` that displays the list of PR to review for a `Player`.
268 class PlayerReviewsPanel
269 super Panel
270
271 # Repo to display.
272 var game: Game
273
274 # Player to display customized list for.
275 var player: Player
276
277 redef fun render_title do
278 add "<span class=\"glyphicon glyphicon-check\"></span>&nbsp;&nbsp;"
279 add "Review pull requests to gain nitcoins!"
280 end
281
282 redef fun render_body do
283 var q = "is:open label:need_review sort:updated-asc " +
284 "-involves:{player.name}"
285
286 var issues = game.repo.search_issues(q)
287 if issues.is_empty then
288 add "<em>No pull request to review yet...</em>"
289 return
290 end
291 for issue in issues do
292 var user = issue.user
293 var uplay = user.player(game)
294 add """<div class="media">
295 <a class="media-left" href="{{{uplay.url}}}">
296 <img class=\"img-circle\" style="width:50px"
297 src="{{{user.avatar_url}}}" alt="{{{uplay.name}}}">
298 </a>
299 <div class="media-body">
300 <h4 class="media-heading">
301 {{{issue.link}}} {{{issue.title}}}
302 </h4>
303 <span class="text-muted">opened by </span>
304 {{{uplay.link}}}
305 </div>
306 </div>"""
307 end
308 end
309 end
310
311 # A `Panel` that displays a pagined list of events stored in the `entity`.
312 #
313 # This way the panel can be used to view events stored under `Game`, `Player`...
314 class EventListPanel
315 super Panel
316
317 # Entity to load the events from.
318 var entity: GameEntity
319
320 # Number of events to display.
321 var limit: Int
322
323 # From where to start?
324 var from: Int
325
326 redef fun render_title do
327 add "<span class=\"glyphicon glyphicon-flash\"></span>&nbsp;&nbsp;"
328 add "Last events"
329 end
330
331 redef fun render_body do
332 var events = entity.load_events
333 if events.is_empty then
334 add "<em>No event yet...</em>"
335 return
336 end
337 # check input
338 if limit < 0 then limit = 10
339 if from < 0 then from = 0
340 # display events
341 for i in [from .. from + limit] do
342 if i >= events.length then break
343 add events[i].tpl_event.media_item
344 end
345 # pagination
346 if limit > events.length then return
347 add "<hr>"
348 add """<div class="btn-group" role="group">"""
349 if from > 0 then
350 add """<a class="btn btn-default" role="button"
351 href="?pfrom={{{from - limit}}}&plimit={{{limit}}}">
352 <span class=\"glyphicon glyphicon-chevron-left\"></span></a>"""
353 end
354 if from + limit < events.length then
355 add """
356 <a class="btn btn-default" role="button"
357 href="?pfrom={{{from + limit}}}&plimit={{{limit}}}">
358 <span class=\"glyphicon glyphicon-chevron-right\"></span></a>"""
359 end
360 add "</div>"
361 end
362 end