WebKitPerfMonitor: There should be a way to add all metrics of a suite without also...
[WebKit-https.git] / Websites / perf.webkit.org / public / include / admin-header.php
1 <?php
2
3 require_once('db.php');
4 require_once('manifest.php');
5
6 ?><!DOCTYPE html>
7 <html>
8 <head>
9 <title>WebKit Perf Monitor</title>
10 <link rel="stylesheet" href="/common.css">
11 <link rel="stylesheet" href="/admin/admin.css">
12 </head>
13 <body>
14 <header id="title">
15 <h1><a href="/">WebKit Perf Monitor</a></h1>
16 <ul>
17     <li><a href="/admin/platforms">Platforms</a></li>
18     <li><a href="/admin/tests">Tests</a></li>
19     <li><a href="/admin/jobs">Jobs</a></li>
20     <li><a href="/admin/aggregators">Aggregators</a></li>
21     <li><a href="/admin/builders">Builders</a></li>
22     <li><a href="/admin/repositories">Repositories</a></li>
23     <li><a href="/admin/bug-trackers">Bug Trackers</a></li>
24 </ul>
25 </header>
26
27 <div id="mainContents">
28 <?php
29
30 function notice($message) {
31     echo "<p class='notice'>$message</p>";
32 }
33
34 $db = new Database;
35 if (!$db->connect()) {
36     notice('Failed to connect to the database');
37     $db = NULL;
38 } else
39     $action = array_key_exists('action', $_POST) ? $_POST['action'] : NULL;
40
41 function execute_query_and_expect_one_row_to_be_affected($query, $params, $success_message, $failure_message) {
42     global $db;
43
44     foreach ($params as &$param) {
45         if ($param == '')
46             $param = NULL;
47     }
48
49     $affected_rows = $db->query_and_get_affected_rows($query, $params);
50     if ($affected_rows) {
51         assert('$affected_rows == 1');
52         notice($success_message);
53         return true;
54     }
55
56     notice($failure_message);
57     return false;
58 }
59
60 function update_field($table, $prefix, $field_name) {
61     global $db;
62
63     if (!array_key_exists('id', $_POST) || (array_get($_POST, 'updated-column') != $field_name && !array_key_exists($field_name, $_POST)))
64         return FALSE;
65
66     $id = intval($_POST['id']);
67     $prefixed_field_name = $prefix . '_' . $field_name;
68     $id_field_name = $prefix . '_id';
69
70     execute_query_and_expect_one_row_to_be_affected("UPDATE $table SET $prefixed_field_name = \$2 WHERE $id_field_name = \$1",
71         array($id, array_get($_POST, $field_name)),
72         "Updated the $prefix $id",
73         "Could not update $prefix $id");
74
75     return TRUE;
76 }
77
78 function regenerate_manifest() {
79     global $db;
80
81     $generator = new ManifestGenerator($db);
82     if (!$generator->generate()) {
83         notice("Failed to generate the manifest (before trying to write into the filesystem).");
84         return FALSE;
85     }
86
87     if (!$generator->store()) {
88         notice("Failed to save the generated manifest into the filesystem");
89         return FALSE;
90     }
91
92     return TRUE;
93 }
94
95 function add_job($type, $payload = null) {
96     global $db;
97
98     if ($db->insert_row('jobs', 'job', array('type' => $type, 'payload' => $payload)))
99         notice("Added a job of type $type");
100     else
101         notice("Failed to add job of type $type");
102 }
103
104 class AdministrativePage {
105     private $table;
106     private $prefix;
107     private $column_to_be_ordered_by;
108     private $column_info;
109
110     function __construct($db, $table, $prefix, $column_info) {
111         $this->db = $db;
112         $this->table = $table;
113         $this->prefix = $prefix;
114         $this->column_info = $column_info;
115     }
116
117     private function name_to_titlecase($name) {
118         return ucwords(str_replace('_', ' ', $name));
119     }
120
121     private function column_label($name) {
122         return array_get($this->column_info[$name], 'label', $this->name_to_titlecase($name));
123     }
124
125     private function render_form_control_for_column($editing_mode, $name, $value = '', $show_update_button_if_needed = FALSE) {
126         $show_update_button = FALSE;
127         switch ($editing_mode) {
128         case 'text':
129             echo <<< END
130 <textarea name="$name" rows="7" cols="50">$value</textarea><br>
131 END;
132             $show_update_button = $show_update_button_if_needed;
133             break;
134         case 'boolean':
135             $checkedness = $this->db->is_true($value) ? ' checked' : '';
136             echo <<< END
137 <input type="checkbox" name="$name"$checkedness>
138 END;
139             $show_update_button = $show_update_button_if_needed;
140             break;
141         case 'url':
142             echo <<< END
143 <input type="text" name="$name" value="$value" size="70">
144 END;
145             break;
146         default:
147             assert($editing_mode == 'string');
148             echo <<< END
149 <input type="text" name="$name" value="$value">
150 END;
151         }
152
153         if ($show_update_button) {
154             echo <<< END
155
156 <button type="submit" name="action" value="update">Update</button>
157 END;
158         }
159     }
160
161     function render_table($column_to_be_ordered_by) {
162         $column_names = array_keys($this->column_info);
163         $column_to_subcolumn_names = array();
164         foreach ($column_names as $name) {
165             if (array_get($this->column_info[$name], 'pre_insertion'))
166                 continue;
167             $subcolumns = array_get($this->column_info[$name], 'subcolumns', array());
168             if (!$subcolumns || !array_get($this->column_info[$name], 'custom'))
169                 continue;
170             $column_to_subcolumn_names[$name] = $subcolumns;
171         }
172
173         $rowspan_if_needed = $column_to_subcolumn_names ? ' rowspan="2"' : '';
174
175         $headers = "<tr><td$rowspan_if_needed>ID</td>";
176         foreach ($column_names as $name) {
177             if (array_get($this->column_info[$name], 'pre_insertion'))
178                 continue;
179             $label = htmlspecialchars($this->column_label($name));
180             if (array_get($column_to_subcolumn_names, $name)) {
181                 $count = count($column_to_subcolumn_names[$name]);
182                 $headers .= "<td colspan=\"$count\">$label</td>";
183             } else
184                 $headers .= "<td$rowspan_if_needed>$label</td>";
185         }
186         $headers .= "</tr>\n";
187
188         if ($column_to_subcolumn_names) {
189             $headers .= '<tr>';
190             foreach ($column_names as $name) {
191                 $subcolumn_names = array_get($column_to_subcolumn_names, $name);
192                 if (!$subcolumn_names)
193                     continue;
194                 foreach ($subcolumn_names as $label)
195                     $headers .= '<td>' . htmlspecialchars($label) . '</td>';
196             }
197             $headers .= "</tr>\n";
198         }
199
200         echo <<< END
201 <table>
202 <thead>
203 $headers
204 </thead>
205 <tbody>
206
207 END;
208
209         assert(ctype_alnum_underscore($column_to_be_ordered_by));
210         $rows = $this->db->fetch_table($this->table, $this->prefix . '_' . $column_to_be_ordered_by);
211         if ($rows) {
212             foreach ($rows as $row) {
213                 $id = intval($row[$this->prefix . '_id']);
214
215                 $custom_cells_list = array();
216                 $maximum_rows = 1;
217                 foreach ($column_names as $name) {
218                     if (array_get($this->column_info[$name], 'pre_insertion'))
219                         continue;
220
221                     if ($custom = array_get($this->column_info[$name], 'custom')) {
222                         $custom_cells_list[$name] = $custom($row);
223                         $maximum_rows = max($maximum_rows, count($custom_cells_list[$name]));
224                     }
225                 }
226
227                 $rowspan_if_needed = $maximum_rows > 1 ? ' rowspan="' . $maximum_rows . '"' : '';
228
229                 echo "<tr>\n<td$rowspan_if_needed>$id</td>\n";
230                 foreach ($column_names as $name) {
231                     if (array_get($this->column_info[$name], 'pre_insertion'))
232                         continue;
233
234                     if (array_key_exists($name, $custom_cells_list)) {
235                         $this->render_custom_cells(array_get($column_to_subcolumn_names, $name), $custom_cells_list[$name], 0);
236                         continue;
237                     }
238
239                     $value = htmlspecialchars($row[$this->prefix . '_' . $name], ENT_QUOTES);
240                     $editing_mode = array_get($this->column_info[$name], 'editing_mode');
241                     if (!$editing_mode) {
242                         echo "<td$rowspan_if_needed>$value</td>\n";
243                         continue;
244                     }
245
246                     echo <<< END
247 <td$rowspan_if_needed>
248 <form method="POST">
249 <input type="hidden" name="id" value="$id">
250 <input type="hidden" name="action" value="update">
251 <input type="hidden" name="updated-column" value="$name">
252
253 END;
254                     $this->render_form_control_for_column($editing_mode, $name, $value, TRUE);
255                     echo "</form></td>\n";
256
257                 }
258                 echo "</tr>\n";
259
260                 for ($row = 1; $row < $maximum_rows; $row++) {
261                     echo "<tr>\n";
262                     foreach ($column_names as $name) {
263                         if (array_key_exists($name, $custom_cells_list))
264                             $this->render_custom_cells(array_get($column_to_subcolumn_names, $name), $custom_cells_list[$name], $row);
265                     }
266                     echo "</tr>\n";
267                 }
268             }
269         }
270         echo <<< END
271 </tbody>
272 </table>
273 END;
274     }
275
276     function render_custom_cells($subcolum_names, $rows, $row_index) {
277         $cells = array_get($rows, $row_index, array());
278         if (!is_array($cells))
279             $cells = array($cells);
280
281         if ($subcolum_names && count($cells) <= 1) {
282             $colspan = count($subcolum_names);
283             $content = $cells ? $cells[0] : '';
284             echo "<td colspan=\"$colspan\">$content</td>\n";
285             return;
286         }
287
288         for ($i = 0; $i < ($subcolum_names ? count($subcolum_names) : 1); $i++)
289             echo '<td>' . array_get($cells, $i, '') . '</td>';
290         echo "\n";
291     }
292
293     function render_form_to_add($title = NULL) {
294
295         if (!$title) # Can't use the table name since it needs to be singular.
296             $title = 'New ' . $this->name_to_titlecase($this->prefix);
297
298 echo <<< END
299 <section class="action-field">
300 <h2>$title</h2>
301 <form method="POST">
302
303 END;
304         foreach (array_keys($this->column_info) as $name) {
305             $editing_mode = array_get($this->column_info[$name], 'editing_mode');
306             if (array_get($this->column_info[$name], 'custom') || !$editing_mode)
307                 continue;
308
309             $label = htmlspecialchars($this->column_label($name));
310             echo "<label>$label<br>\n";
311             $this->render_form_control_for_column($editing_mode, $name);
312             echo "</label><br>\n";
313         }
314
315 echo <<< END
316
317 <button type="submit" name="action" value="add">Add</button>
318 </form>
319 </section>
320 END;
321
322     }
323
324 }
325
326 ?>