1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Panels templates for `nitpg`.
20 import templates_events
23 # A panel can be displayed in a html page.
25 # This display a Bootstrap panel.
29 redef fun rendering
do
30 add
"""<div class="panel panel-default">
31 <div class="panel-heading">
32 <h3 class="panel-title">"""
36 <div class="panel-body">"""
42 # Render the panel title.
43 # Betweem `<h4>` tags.
44 fun render_title
do end
46 # Render the panel body.
47 fun render_body
do end
50 # A panel that contain only a table as body.
54 redef fun rendering
do
55 add
"""<div class="panel panel-default">
56 <div class="panel-heading">
57 <h3 class="panel-title">"""
67 # Display an error message within a panel.
71 redef fun rendering
do
73 <div class="panel panel-danger">
74 <div class="panel-heading">
75 <h3 class="panel-title">"""
80 <div class="panel-body">"""
88 # The error message to display as panel body.
91 redef fun render_title
do
92 add
"<span class=\"glyphicon glyphicon-warning-sign\
"></span> "
96 redef fun render_body
do
102 # A panel that display a markdown content rendered as HTML.
106 # Markdown text to display.
109 redef fun rendering
do
110 add
"""<div class="panel">
111 <div class="panel-body">{{{text.md_to_html}}}</div>
116 # Display a list of active game.
118 # Used for NitRPG homepage.
119 class GamesShortListPanel
122 # Root url used for links.
125 # List of NitRPG games to display.
126 var games
: Array[Game]
128 redef fun render_title
do
129 add
"<span class=\"glyphicon glyphicon-home\
"></span> "
130 add
"<a href=\"{root_url}/games\
">Active games</a>"
133 redef fun render_body
do
134 if games
.is_empty
then
135 add
"<em>No game yet...</em>"
138 var sorted
= games
.to_a
139 (new GamePlayersComparator).sort
(sorted
)
140 for game
in sorted
do
141 add
"{game.link} ({game.load_players.length} players)<br>"
146 # A panel that display a list of player in a repo.
148 super GamesShortListPanel
151 redef fun render_title
do
152 add
"<span class=\"glyphicon glyphicon-home\
"></span> "
153 add
"<a href=\"{root_url}/games\
">Active games</a>"
156 redef fun render_body
do
157 if games
.is_empty
then
158 add
"<div class=\"panel-body\
">"
159 add
"<em>No player yet...</em>"
163 var sorted
= games
.to_a
164 (new GamePlayersComparator).sort
(sorted
)
165 add
"""<table class="table table-striped table-hover">
169 <th>Achievements</th>
171 for game
in sorted
do
173 add
" <td>{game.link}</td>"
174 add
" <td>{game.load_players.length}</td>"
175 add
" <td>{game.load_achievements.length}</td>"
182 # A panel that display repo statistics.
183 class GameStatusPanel
189 redef fun render_title
do
190 add
"<span class=\"glyphicon glyphicon-home\
"></span> "
194 redef fun render_body
do
195 add
"<strong class=\"text-success\
">{game.load_players.length}</strong>"
196 add
" <a href=\"{game.url}/players\
">players</a><br>"
197 add
"<strong class=\"text-success\
">{game.stats["achievements"]}</strong>"
198 add
" <a href=\"{game.url}/achievements\
">achievements</a><br><br>"
199 add
"<strong class=\"text-success\
">{game.stats["pulls"]}</strong> pull requests"
200 add
" (<strong>{game.stats["pulls_open"]}</strong> open)<br>"
201 add
"<strong class=\"text-success\
">{game.stats["issues"]}</strong> issues"
202 add
" (<strong>{game.stats["issues_open"]}</strong> open)<br>"
203 add
"<strong class=\"text-success\
">{game.stats["commits"]}</strong> commits"
207 # Player status panel.
208 class PlayerStatusPanel
217 redef fun render_title
do
218 add
"<a href=\"{player.url}\
">"
219 add
" <img class=\"img-circle\
" style=\"width
: 30px\
""
220 add
" src=\"{player.user.avatar_url or else "#"}\
" alt=\"{player.name}\
">"
221 add
"</a> {player.link}"
224 redef fun render_body
do
225 var ranking
= game
.player_ranking
227 add
"<p class=\"lead\
">ranked "
228 add
" <span class=\"text-success\
"># {ranking[player.name]}</span></p>"
229 add
"<strong class=\"text-success\
">{player.nitcoins}</strong> nitcoins<br><br>"
230 add
"<strong class=\"text-success\
">{player.stats["achievements"]}</strong> achievements<br><br>"
231 add
"<strong>{player.stats["pulls"]}</strong> pull requests<br>"
232 add
"<strong>{player.stats["issues"]}</strong> issues<br>"
233 add
"<strong>{player.stats["commits"]}</strong> commits"
237 # A panel that display a list of player in a repo.
238 class ShortListPlayersPanel
244 redef fun render_title
do
245 add
"<span class=\"glyphicon glyphicon-user\
"></span> "
246 add
"<a href=\"{game.url}/players\
">Players</a>"
249 redef fun render_body
do
250 var players
= game
.load_players
.values
.to_a
251 if players
.is_empty
then
252 add
"<em>No player yet...</em>"
255 (new PlayerCoinComparator).sort
(players
)
256 for player
in players
do
257 add
"{player.nitcoins} - {player.link}<br>"
262 # A panel that display a list of player in a repo.
263 class ListPlayersPanel
269 redef fun render_title
do
270 add
"<span class=\"glyphicon glyphicon-user\
"></span> "
271 add
"<a href=\"{game.url}/players\
">Players</a>"
274 redef fun render_body
do
275 var players
= game
.load_players
.values
.to_a
276 (new PlayerCoinComparator).sort
(players
)
277 if players
.is_empty
then
278 add
"<div class=\"panel-body\
">"
279 add
"<em>No player yet...</em>"
283 add
"""<table class="table table-striped table-hover">
290 for player
in players
do
292 add
" <td>{rank}</td>"
293 add
" <td>{player.link}</td>"
294 add
" <td>{player.nitcoins}</td>"
302 # A panel that display the podium.
309 redef fun render_title
do
310 add
"<span class=\"glyphicon glyphicon-stats\
"></span> Hall of fame"
313 redef fun render_body
do
314 var players
= game
.load_players
.values
.to_a
315 (new PlayerCoinComparator).sort
(players
)
316 if players
.is_empty
then
317 add
"<em>No players yet...</em>"
321 <div class="container-fluid">
322 <div id="podium" class="row row-sm-height">"""
323 var max
= players
.first
.nitcoins
324 var orders
= [3, 1, 0, 2, 4]
325 for order
in orders
do
326 if order
>= players
.length
then continue
327 var player
= players
[order
]
329 if max
> 0 then size
= player
.nitcoins
* 300 / max
331 <div class="col-xs-2 col-xs-height col-xs-offset-{{{order}}} col-bottom"
332 style="text-align: center;">
334 <a href="{{{player.url}}}">
335 <img class="img-circle" style="width: 80px"
336 src="{{{player.user.avatar_url or else "#"}}}" alt="{{{player.name}}}">
339 <p>{{{player.link}}}</p>
340 <p>{{{player.nitcoins}}}</p>
341 <div class=" progress-bar-warning progress-bar-striped"
342 style="height: {{{size}}}px;"></div>
351 # A `Panel` that displays the list of PR to review for a `Player`.
352 class PlayerReviewsPanel
358 # Player to display customized list for.
361 redef fun render_title
do
362 add
"<span class=\"glyphicon glyphicon-check\
"></span> "
363 add
"Review pull requests and comment issues to gain nitcoins!"
366 redef fun render_body
do
367 var q
= "is:open label:need_review sort:updated-asc " +
368 "-involves:{player.name}"
370 var q2
= "is:open label:request_for_comments sort:updated-asc " +
371 "-involves:{player.name}"
373 var issues
= new ArraySet[Issue]
374 issues
.add_all game
.api
.search_repo_issues
(game
.repo
, q
)
375 issues
.add_all game
.api
.search_repo_issues
(game
.repo
, q2
)
376 if issues
.is_empty
then
377 add
"<em>No pull request or issue to review yet...</em>"
380 for issue
in issues
do
381 var user
= issue
.user
382 var uplay
= user
.player
(game
)
383 add
"""<div class="media">
384 <a class="media-left" href="{{{uplay.url}}}">
385 <img class=\"img-circle\" style="width:50px"
386 src="{{{user.avatar_url or else "#"}}}" alt="{{{uplay.name}}}">
388 <div class="media-body">
389 <h4 class="media-heading">
390 {{{issue.link}}} {{{issue.title}}}
392 <span class="text-muted">opened by </span>
400 # A `Panel` that displays the work assigned or tagged.
401 class PlayerWorkPanel
407 # Player to display customized list for.
410 redef fun render_title
do
411 add
"<span class=\"glyphicon glyphicon-check\
"></span> "
412 add
"Do your tasks to gain nitcoins!"
415 redef fun render_body
do
416 var q
= "is:open label:need_work sort:updated-asc author:{player.name}"
417 var q2
= "is:open sort:updated-asc assignee:{player.name}"
419 var issues
= new ArraySet[Issue]
420 issues
.add_all game
.api
.search_repo_issues
(game
.repo
, q
)
421 issues
.add_all game
.api
.search_repo_issues
(game
.repo
, q2
)
422 if issues
.is_empty
then
423 add
"<em>No work to do yet...</em>"
426 for issue
in issues
do
427 var user
= issue
.user
428 var uplay
= user
.player
(game
)
429 add
"""<div class="media">
430 <a class="media-left" href="{{{uplay.url}}}">
431 <img class=\"img-circle\" style="width:50px"
432 src="{{{user.avatar_url or else "#"}}}" alt="{{{uplay.name}}}">
434 <div class="media-body">
435 <h4 class="media-heading">
436 {{{issue.link}}} {{{issue.title}}}
438 <span class="text-muted">opened by </span>
446 # A `Panel` that displays a pagined list of events stored in the `entity`.
448 # This way the panel can be used to view events stored under `Game`, `Player`...
452 # Entity to load the events from.
453 var entity
: GameEntity
455 # Number of events to display.
458 # From where to start?
461 redef fun render_title
do
462 add
"<span class=\"glyphicon glyphicon-flash\
"></span> "
466 redef fun render_body
do
467 var events
= entity
.load_events
468 if events
.is_empty
then
469 add
"<em>No event yet...</em>"
473 if limit
< 0 then limit
= 10
474 if from
< 0 then from
= 0
476 for i
in [from
.. from
+ limit
] do
477 if i
>= events
.length
then break
478 add events
[i
].tpl_event
.media_item
481 if limit
> events
.length
then return
483 add
"""<div class="btn-group" role="group">"""
485 add
"""<a class="btn btn-default" role="button"
486 href="?pfrom={{{from - limit}}}&plimit={{{limit}}}">
487 <span class=\"glyphicon glyphicon-chevron-left\"></span></a>"""
489 if from
+ limit
< events
.length
then
491 <a class="btn btn-default" role="button"
492 href="?pfrom={{{from + limit}}}&plimit={{{limit}}}">
493 <span class=\"glyphicon glyphicon-chevron-right\"></span></a>"""
499 # Achievement unlocked list panel.
500 class AchievementsListPanel
503 # Entity to load the events from.
504 var entity
: GameEntity
506 redef fun render_title
do
507 add
"<span class=\"glyphicon glyphicon-list\
"></span> "
508 add
"Achievements unlocked"
511 redef fun render_body
do
512 var achs
= entity
.load_achievements
.values
.to_a
513 if achs
.is_empty
then
514 add
"<em>No achievement yet...</em>"
517 for ach
in achs
do add ach
.list_item
521 # Achievement detail panel.
522 class AchievementPanel
525 # Achievement to display.
526 var achievement
: Achievement
528 redef fun render_title
do
529 add
"<span class=\"glyphicon glyphicon-check\
"></span> "
530 add
"Achievement details"
533 redef fun render_body
do
534 add
"""<p class=\"lead\">
535 <span class="badge progress-bar-success"
536 style="vertical-align: middle">+{{{achievement.reward}}}</span>
537 {{{achievement.name}}}
539 <p><strong>{{{achievement.desc}}}</strong></p>"""
541 var events
= achievement
.load_events
543 if events
.is_empty
then
544 add
"<em>Never unlocked...</em>"
548 var event
= events
.last
549 var tpl
= event
.tpl_event
550 var player
= tpl
.player
552 add
"""<div class="media">
553 <a class="media-left" href="{{{player.url}}}">
554 <span class="badge progress-bar-warning" style="position: absolute">#1</span>
555 <img class=\"img-circle\" style="width:50px"
556 src="{{{player.user.avatar_url or else "#"}}}" alt="{{{player.name}}}">
558 <div class="media-body">
559 <h4 class="media-heading">Unlocked first by {{{player.link}}}</h4>
560 <span class="text-muted">at {{{event.time}}} </span>
564 if events
.length
> 1 then
565 add
"""<p><br>Also unlocked by <strong class="text-success">
566 {{{events.length}}} players</strong>.</p>"""