ditz 0.4 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog +15 -0
- data/INSTALL +20 -0
- data/LICENSE +674 -0
- data/Manifest.txt +42 -0
- data/PLUGINS.txt +99 -0
- data/README.txt +50 -35
- data/Rakefile +34 -2
- data/ReleaseNotes +6 -0
- data/bin/ditz +45 -68
- data/contrib/completion/ditz.bash +7 -7
- data/lib/blue-check.png +0 -0
- data/lib/component.rhtml +10 -4
- data/lib/ditz.rb +15 -3
- data/lib/file-storage.rb +54 -0
- data/lib/green-bar.png +0 -0
- data/lib/green-check.png +0 -0
- data/lib/hook.rb +1 -1
- data/lib/html.rb +39 -4
- data/lib/index.rhtml +80 -59
- data/lib/issue.rhtml +91 -79
- data/lib/issue_table.rhtml +24 -29
- data/lib/lowline.rb +5 -6
- data/lib/model-objects.rb +50 -17
- data/lib/model.rb +84 -26
- data/lib/operator.rb +151 -70
- data/lib/plugins/git-sync.rb +83 -0
- data/lib/plugins/git.rb +67 -15
- data/lib/plugins/issue-claiming.rb +174 -0
- data/lib/red-check.png +0 -0
- data/lib/release.rhtml +69 -38
- data/lib/style.css +138 -39
- data/lib/trollop.rb +614 -0
- data/lib/unassigned.rhtml +11 -15
- data/lib/util.rb +4 -0
- data/lib/views.rb +3 -1
- data/lib/yellow-bar.png +0 -0
- data/man/ditz.1 +38 -0
- data/setup.rb +1585 -0
- data/www/index.html +152 -0
- data/www/main.css +45 -0
- metadata +26 -7
@@ -6,16 +6,16 @@
|
|
6
6
|
|
7
7
|
_ditz()
|
8
8
|
{
|
9
|
-
cur=${COMP_WORDS[COMP_CWORD]}
|
9
|
+
local cur=${COMP_WORDS[COMP_CWORD]}
|
10
10
|
if [ $COMP_CWORD -eq 1 ]; then
|
11
|
-
COMPREPLY=( $( compgen -W "$(ditz --commands)" $cur ) )
|
11
|
+
COMPREPLY=( $( compgen -W "$(ditz --commands)" -- $cur ) )
|
12
12
|
elif [ $COMP_CWORD -eq 2 ]; then
|
13
|
-
cmd=${COMP_WORDS[1]}
|
14
|
-
COMPREPLY=( $( compgen -W "$(ditz "$cmd" '<options>' 2>/dev/null)" $cur ) )
|
13
|
+
local cmd=${COMP_WORDS[1]}
|
14
|
+
COMPREPLY=( $( compgen -W "$(ditz "$cmd" '<options>' 2>/dev/null)" -- $cur ) )
|
15
15
|
elif [ $COMP_CWORD -eq 3 ]; then
|
16
|
-
cmd=${COMP_WORDS[1]}
|
17
|
-
parm1=${COMP_WORDS[2]}
|
18
|
-
COMPREPLY=( $( compgen -W "$(ditz "$cmd" "$parm1" '<options>' 2>/dev/null)" $cur ) )
|
16
|
+
local cmd=${COMP_WORDS[1]}
|
17
|
+
local parm1=${COMP_WORDS[2]}
|
18
|
+
COMPREPLY=( $( compgen -W "$(ditz "$cmd" "$parm1" '<options>' 2>/dev/null)" -- $cur ) )
|
19
19
|
fi
|
20
20
|
}
|
21
21
|
|
data/lib/blue-check.png
ADDED
Binary file
|
data/lib/component.rhtml
CHANGED
@@ -1,18 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
1
5
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
2
6
|
<head>
|
3
7
|
<title>Component <%= component.name %></title>
|
4
|
-
<meta http-equiv="Content-Type" content="text/html; charset=
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
5
9
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
6
10
|
</head>
|
7
11
|
|
8
12
|
<body>
|
9
13
|
|
10
|
-
|
14
|
+
<div class="main">
|
11
15
|
|
12
16
|
<h1><%= project.name %> component: <%= component.name %></h1>
|
17
|
+
<div class="backptr"><%= link_to "index", "« #{project.name} project page" %></div>
|
13
18
|
|
19
|
+
<h2>All issues</h2>
|
14
20
|
<%= render "issue_table", :show_component => false, :show_release => true %>
|
15
|
-
|
16
|
-
<
|
21
|
+
</div>
|
22
|
+
<div class="footer">Generated by <a href="http://ditz.rubyforge.org/">ditz</a>.</div>
|
17
23
|
</body>
|
18
24
|
</html>
|
data/lib/ditz.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Ditz
|
2
2
|
|
3
|
-
VERSION = "0.
|
3
|
+
VERSION = "0.5"
|
4
4
|
|
5
5
|
def debug s
|
6
|
-
puts "# #{s}" if $
|
6
|
+
puts "# #{s}" if $verbose
|
7
7
|
end
|
8
8
|
module_function :debug
|
9
9
|
|
@@ -46,11 +46,23 @@ def find_ditz_file fn
|
|
46
46
|
File.expand_path File.join(dir, fn)
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
def load_plugins fn
|
50
|
+
Ditz::debug "loading plugins from #{fn}"
|
51
|
+
plugins = YAML::load_file $opts[:plugins_file]
|
52
|
+
plugins.each do |p|
|
53
|
+
fn = Ditz::find_ditz_file "plugins/#{p}.rb"
|
54
|
+
Ditz::debug "loading plugin #{p.inspect} from #{fn}"
|
55
|
+
require File.expand_path(fn)
|
56
|
+
end
|
57
|
+
plugins
|
58
|
+
end
|
59
|
+
|
60
|
+
module_function :home_dir, :find_dir_containing, :find_ditz_file, :load_plugins
|
50
61
|
end
|
51
62
|
|
52
63
|
require 'model-objects'
|
53
64
|
require 'operator'
|
54
65
|
require 'views'
|
55
66
|
require 'hook'
|
67
|
+
require 'file-storage'
|
56
68
|
|
data/lib/file-storage.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Ditz
|
2
|
+
|
3
|
+
## stores ditz database on disk
|
4
|
+
class FileStorage
|
5
|
+
PROJECT_FN = "project.yaml"
|
6
|
+
ISSUE_FN_GLOB = "issue-*.yaml"
|
7
|
+
|
8
|
+
def ISSUE_TO_FN i; "issue-#{i.id}.yaml" end
|
9
|
+
|
10
|
+
def initialize base_dir
|
11
|
+
@base_dir = base_dir
|
12
|
+
@project_fn = File.join @base_dir, PROJECT_FN
|
13
|
+
end
|
14
|
+
|
15
|
+
def load
|
16
|
+
Ditz::debug "loading project from #{@project_fn}"
|
17
|
+
project = Project.from @project_fn
|
18
|
+
|
19
|
+
fn = File.join @base_dir, ISSUE_FN_GLOB
|
20
|
+
Ditz::debug "loading issues from #{fn}"
|
21
|
+
project.issues = Dir[fn].map { |fn| Issue.from fn }
|
22
|
+
Ditz::debug "found #{project.issues.size} issues"
|
23
|
+
|
24
|
+
project.issues.each { |i| i.project = project }
|
25
|
+
project
|
26
|
+
end
|
27
|
+
|
28
|
+
def save project
|
29
|
+
dirty = false
|
30
|
+
dirty = project.each_modelobject { |o| break true if o.changed? }
|
31
|
+
if dirty
|
32
|
+
Ditz::debug "project is dirty, saving #{@project_fn}"
|
33
|
+
project.save! @project_fn
|
34
|
+
end
|
35
|
+
|
36
|
+
changed_issues = project.issues.select { |i| i.changed? }
|
37
|
+
changed_issues.each do |i|
|
38
|
+
fn = filename_for_issue i
|
39
|
+
Ditz::debug "issue #{i.name} is dirty, saving #{fn}"
|
40
|
+
i.save! fn
|
41
|
+
end
|
42
|
+
|
43
|
+
project.deleted_issues.each do |i|
|
44
|
+
fn = filename_for_issue i
|
45
|
+
Ditz::debug "issue #{i.name} has been deleted, deleting #{fn}"
|
46
|
+
FileUtils.rm fn
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def filename_for_issue i; File.join @base_dir, ISSUE_TO_FN(i) end
|
51
|
+
def filename_for_project; @project_fn end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/green-bar.png
ADDED
Binary file
|
data/lib/green-check.png
ADDED
Binary file
|
data/lib/hook.rb
CHANGED
data/lib/html.rb
CHANGED
@@ -48,16 +48,51 @@ class ErbHtml
|
|
48
48
|
raise ArgumentError, "no link for #{o.inspect}" unless dest
|
49
49
|
"<a href=\"#{dest}\">#{name}</a>"
|
50
50
|
end
|
51
|
-
|
52
|
-
|
51
|
+
|
52
|
+
def issue_status_img_for i, opts={}
|
53
|
+
fn, title = if i.closed?
|
54
|
+
case i.disposition
|
55
|
+
when :fixed; ["green-check.png", "fixed"]
|
56
|
+
when :wontfix; ["red-check.png", "won't fix"]
|
57
|
+
when :reorg; ["blue-check.png", "reorganized"]
|
58
|
+
end
|
59
|
+
elsif i.in_progress?
|
60
|
+
["green-bar.png", "in progress"]
|
61
|
+
elsif i.paused?
|
62
|
+
["yellow-bar.png", "paused"]
|
63
|
+
end
|
64
|
+
|
65
|
+
return "" unless fn
|
66
|
+
|
67
|
+
args = {:src => fn, :alt => title, :title => title}
|
68
|
+
args[:class] = opts[:class] if opts[:class]
|
69
|
+
|
70
|
+
"<img " + args.map { |k, v| "#{k}=#{v.inspect}" }.join(" ") + "/>"
|
53
71
|
end
|
54
72
|
|
55
|
-
def
|
73
|
+
def issue_link_for i, opts={}
|
74
|
+
link = link_to i, "#{i.title}"
|
75
|
+
link = "<span class=\"inline-issue-link\">" + link + "</span>" if opts[:inline]
|
76
|
+
link = link + " " + issue_status_img_for(i, :class => "inline-status-image") if opts[:status_image]
|
77
|
+
link
|
78
|
+
end
|
79
|
+
|
80
|
+
def link_issue_names project, s, opts={}
|
56
81
|
project.issues.inject(s) do |s, i|
|
57
|
-
s.gsub(/\b#{i.name}\b/,
|
82
|
+
s.gsub(/\b#{i.name}\b/, issue_link_for(i, {:inline => true, :status_image => true}.merge(opts)))
|
58
83
|
end
|
59
84
|
end
|
60
85
|
|
86
|
+
def progress_meter p, size=50
|
87
|
+
done = (p * size).to_i
|
88
|
+
undone = [size - done, 0].max
|
89
|
+
"<span class='progress-meter'><span class='progress-meter-done'>" +
|
90
|
+
(" " * done) +
|
91
|
+
"</span><span class='progress-meter-undone'>" +
|
92
|
+
(" " * undone) +
|
93
|
+
"</span></span>"
|
94
|
+
end
|
95
|
+
|
61
96
|
## render a nested ERB
|
62
97
|
alias :render :render_template
|
63
98
|
|
data/lib/index.rhtml
CHANGED
@@ -1,51 +1,65 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
1
5
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
2
6
|
<head>
|
3
7
|
<title><%= project.name %> Issue Tracker</title>
|
4
|
-
<meta http-equiv="Content-Type" content="text/html; charset=
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
5
9
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
6
10
|
</head>
|
7
11
|
<body>
|
8
12
|
|
13
|
+
<div class="main">
|
9
14
|
<h1><%= project.name %> Issue Tracker</h1>
|
10
15
|
|
11
16
|
<h2>Upcoming Releases</h2>
|
12
17
|
<% if upcoming_releases.empty? %>
|
13
18
|
<p>No upcoming releases.</p>
|
14
19
|
<% else %>
|
15
|
-
<
|
16
|
-
|
17
|
-
<%
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
<table>
|
21
|
+
<tbody>
|
22
|
+
<% upcoming_releases.each do |r| %>
|
23
|
+
<%
|
24
|
+
issues = project.issues_for_release r
|
25
|
+
num_done = issues.count_of { |i| i.closed? }
|
26
|
+
pct_done = issues.size == 0 ? 1.0 : (num_done.to_f / issues.size.to_f)
|
27
|
+
open_issues = issues.select { |i| i.open? }
|
28
|
+
%>
|
29
|
+
<tr><td>
|
30
|
+
<%= link_to r, "#{r.name}" %>
|
31
|
+
</td>
|
32
|
+
<td>
|
33
|
+
<% if issues.empty? %>
|
34
|
+
no issues
|
35
|
+
<% elsif open_issues.empty? %>
|
36
|
+
ready for release!
|
31
37
|
<% else %>
|
32
|
-
<%=
|
38
|
+
<%= progress_meter pct_done %>
|
39
|
+
<%= sprintf "%.0f%%", pct_done * 100.0 %> complete
|
40
|
+
</td>
|
41
|
+
</tr><tr><td></td><td>
|
42
|
+
<%= num_done %> / <%= issues.size %> issues.
|
43
|
+
<%= link_to r, "See issues »" %>
|
33
44
|
<% end %>
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
45
|
+
</td>
|
46
|
+
</tr>
|
47
|
+
<% end %>
|
48
|
+
</tbody>
|
49
|
+
</table>
|
38
50
|
<% end %>
|
39
51
|
|
40
52
|
<h2>Past Releases</h2>
|
41
53
|
<% if past_releases.empty? %>
|
42
54
|
<p>No past releases.</p>
|
43
55
|
<% else %>
|
44
|
-
<
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
56
|
+
<table>
|
57
|
+
<tbody>
|
58
|
+
<% past_releases.sort_by { |r| r.release_time }.reverse.each do |r| %>
|
59
|
+
<tr><td><%= link_to r, r.name %></td><td class="littledate">on <%= r.release_time.pretty_date %></td></tr>
|
60
|
+
<% end %>
|
61
|
+
</tbody>
|
62
|
+
</table>
|
49
63
|
<% end %>
|
50
64
|
|
51
65
|
<h2>Unassigned issues</h2>
|
@@ -57,53 +71,60 @@
|
|
57
71
|
<% if issues.empty? %>
|
58
72
|
No unassigned issues.
|
59
73
|
<% else %>
|
60
|
-
<%= link_to "unassigned", "unassigned issue".pluralize(issues.size).capitalize
|
74
|
+
<%= link_to "unassigned", "unassigned issue".pluralize(issues.size).capitalize %> (<%= open_issues.size.to_pretty_s %> open).
|
61
75
|
<% end %>
|
62
76
|
</p>
|
63
77
|
|
64
78
|
<% if components.size > 1 %>
|
65
79
|
<h2>Open Issues by component</h2>
|
66
|
-
<
|
67
|
-
|
68
|
-
<%
|
69
|
-
|
70
|
-
|
71
|
-
|
80
|
+
<table>
|
81
|
+
<tbody>
|
82
|
+
<% components.each do |c| %>
|
83
|
+
<%
|
84
|
+
issues = project.issues_for_component c
|
85
|
+
num_done = issues.count_of { |i| i.closed? }
|
86
|
+
pct_done = issues.size == 0 ? 1.0 : (num_done.to_f / issues.size.to_f)
|
87
|
+
open_issues = issues.select { |i| i.open? }
|
88
|
+
%>
|
72
89
|
<% if open_issues.empty? %>
|
73
|
-
<
|
74
|
-
<%= link_to c, c.name %>:
|
75
|
-
no open issues.
|
76
|
-
</span>
|
90
|
+
<tr class="dimmed">
|
77
91
|
<% else %>
|
78
|
-
|
79
|
-
<%= open_issues.map { |n,is| n.to_s.pluralize is.size }.join(' and ') %> open.
|
92
|
+
<tr>
|
80
93
|
<% end %>
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
<td>
|
95
|
+
<%= link_to c, c.name %>
|
96
|
+
</td><td>
|
97
|
+
<%= "open issue".pluralize(open_issues.size) %>
|
98
|
+
</td></tr>
|
99
|
+
<% end %>
|
100
|
+
</tbody>
|
101
|
+
</table>
|
84
102
|
<% end %>
|
85
103
|
|
86
104
|
<h2>Recent activity</h2>
|
87
105
|
|
88
|
-
<table>
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
<
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
106
|
+
<table class="log">
|
107
|
+
<tbody>
|
108
|
+
<% project.issues.map { |i| i.log_events.map { |e| [e, i] } }.
|
109
|
+
flatten_one_level.
|
110
|
+
sort_by { |e| e.first.first }.
|
111
|
+
reverse[0 ... 10].
|
112
|
+
each_with_index do |((date, who, what, comment), i), idx| %>
|
113
|
+
<tr class="<%= idx % 2 == 0 ? "even-row" : "odd-row" %>">
|
114
|
+
<td class="date"><%= date.pretty_date %></td>
|
115
|
+
<td class="issuename">
|
116
|
+
<%= issue_link_for i, :status_image => true %>
|
117
|
+
</td>
|
118
|
+
<td> <%= what %> </td>
|
119
|
+
</tr>
|
120
|
+
<tr><td></td></tr>
|
102
121
|
<% end %>
|
103
|
-
|
122
|
+
</tbody>
|
104
123
|
</table>
|
105
124
|
|
106
|
-
|
125
|
+
</div>
|
126
|
+
|
127
|
+
<div class="footer">Generated by <a href="http://ditz.rubyforge.org/">ditz</a>.</div>
|
107
128
|
|
108
129
|
</body>
|
109
130
|
</html>
|
data/lib/issue.rhtml
CHANGED
@@ -1,107 +1,119 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
|
1
5
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
2
6
|
<head>
|
3
7
|
<title><%= issue.title %></title>
|
4
|
-
<meta http-equiv="Content-Type" content="text/html; charset=
|
8
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
5
9
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
6
10
|
</head>
|
7
11
|
|
8
12
|
<body>
|
9
13
|
|
10
|
-
|
14
|
+
<div class="main">
|
11
15
|
|
12
16
|
<h1><%= link_issue_names project, issue.title %></h1>
|
17
|
+
<div class="backptr"><%= link_to "index", "« #{project.name} project page" %></div>
|
13
18
|
|
14
|
-
|
19
|
+
<% if issue.desc && !issue.desc.empty? %>
|
20
|
+
<div class="description">
|
21
|
+
<%= link_issue_names project, p(issue.desc) %>
|
22
|
+
</div>
|
23
|
+
<% end %>
|
15
24
|
|
25
|
+
<h2>Details</h2>
|
16
26
|
<table>
|
17
|
-
<
|
18
|
-
<
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
<
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
<
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
<
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
27
|
+
<tbody>
|
28
|
+
<tr>
|
29
|
+
<td class="attrname">Id:</td>
|
30
|
+
<td class="attrval"><span class="id"><%= issue.id %></span></td>
|
31
|
+
</tr>
|
32
|
+
|
33
|
+
<tr>
|
34
|
+
<td class="attrname">Type:</td>
|
35
|
+
<td class="attrval"><%= issue.type %></td>
|
36
|
+
</tr>
|
37
|
+
|
38
|
+
<tr>
|
39
|
+
<td class="attrname">Creation time:</td>
|
40
|
+
<td class="attrval"><%=t issue.creation_time %></td>
|
41
|
+
</tr>
|
42
|
+
|
43
|
+
<tr>
|
44
|
+
<td class="attrname">Creator:</td>
|
45
|
+
<td class="attrval"><span class="person"><%=obscured_email issue.reporter %></span></td>
|
46
|
+
</tr>
|
47
|
+
|
48
|
+
<% unless issue.references.empty? %>
|
49
|
+
<tr>
|
50
|
+
<td class="attrname">References:</td>
|
51
|
+
<td class="attrval">
|
52
|
+
<% issue.references.each_with_index do |r, i| %>
|
53
|
+
[<%= i + 1 %>] <%= link_to r, r %><br/>
|
54
|
+
<% end %>
|
55
|
+
</td>
|
56
|
+
</tr>
|
46
57
|
|
47
|
-
|
58
|
+
<% end %>
|
48
59
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
<tr>
|
61
|
+
<td class="attrname">Release:</td>
|
62
|
+
<td class="attrval">
|
63
|
+
<% if release %>
|
64
|
+
<%= link_to release, release.name %>
|
65
|
+
<% if release.released? %>
|
66
|
+
(released <%= release.release_time.pretty_date %>)
|
67
|
+
<% else %>
|
68
|
+
(unreleased)
|
69
|
+
<% end %>
|
56
70
|
<% else %>
|
57
|
-
|
71
|
+
<%= link_to "unassigned", "unassigned" %>
|
58
72
|
<% end %>
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
<
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
<%= extra_summary_html %>
|
78
|
-
|
73
|
+
</td>
|
74
|
+
</tr>
|
75
|
+
|
76
|
+
<tr>
|
77
|
+
<td class="attrname">Component:</td>
|
78
|
+
<td class="attrval"><%= link_to component, component.name %></td>
|
79
|
+
</tr>
|
80
|
+
|
81
|
+
<tr>
|
82
|
+
<td class="attrname">Status:</td>
|
83
|
+
<td class="attrval">
|
84
|
+
<%= issue.status_string %><% if issue.closed? %>: <%= issue.disposition_string %><% end %>
|
85
|
+
<%= issue_status_img_for issue, :class => "inline-status-image" %>
|
86
|
+
</td>
|
87
|
+
</tr>
|
88
|
+
|
89
|
+
<%= extra_summary_html %>
|
90
|
+
</tbody>
|
79
91
|
</table>
|
80
92
|
|
81
93
|
<%= extra_details_html %>
|
82
94
|
|
83
95
|
<h2>Issue log</h2>
|
84
96
|
|
85
|
-
<table>
|
86
|
-
|
87
|
-
<%
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
<% if comment.empty? %>
|
98
|
-
<% else %>
|
99
|
-
<%= link_issue_names project, p(comment) %>
|
97
|
+
<table class="log">
|
98
|
+
<tbody>
|
99
|
+
<% issue.log_events.reverse.each_with_index do |(time, who, what, comment), i| %>
|
100
|
+
<tr class="<%= i % 2 == 0 ? "even-row" : "odd-row" %>">
|
101
|
+
<td class="date"><%=t time %></td>
|
102
|
+
<td class="person"><%=obscured_email who %></td>
|
103
|
+
<td class="message"><%=h what %></td>
|
104
|
+
</tr>
|
105
|
+
<% unless comment.empty? %>
|
106
|
+
<tr><td colspan="3" class="logcomment">
|
107
|
+
<%= link_issue_names project, comment %>
|
108
|
+
</td></tr>
|
100
109
|
<% end %>
|
101
|
-
|
102
|
-
<% end %>
|
110
|
+
<tr><td></td></tr>
|
111
|
+
<% end %>
|
112
|
+
</tbody>
|
103
113
|
</table>
|
104
114
|
|
105
|
-
|
115
|
+
</div>
|
116
|
+
<div class="footer">Generated by <a href="http://ditz.rubyforge.org/">ditz</a>.</div>
|
117
|
+
|
106
118
|
</body>
|
107
119
|
</html>
|