public function indexAjax() { return BootstrapUI::tableRemoteResponse()->search(array('country'))->column('flag', function ($value, $row) { return '<img src="' . \Koldy\Url::link('img/flag/' . $row['tld'] . '.png') . '" />'; })->column('tld')->column('country')->column('total', function ($value, $row) { return "<div class=\"text-right\">{$value}</div>"; })->column('action', function ($value, $row) { return \Bootstrap::anchor(\Bootstrap::icon('search'), \Koldy\Url::href('reports', 'search', array('country_id' => $row['id'])))->title('Find reports from this country')->asButton()->size('xs')->color('red'); })->resultSet(Country::resultSet())->handle(); }
public function indexAction() { $calculationInProgress = Status::isCalculationInProgress(); $elements = array(); $user = Session::get('user'); // Check for currently ongoing calculation if ($calculationInProgress) { $alert = Bootstrap::alert('<img src="' . Url::link('img/alert.png') . '" /> Data calculation is in progress! Reports might be slower then usual! Status: ' . Status::getCalculationStatus())->color('warning')->dismissable(); $elements[] = $alert; } $title = Bootstrap::h(1, 'Welcome ' . ($this->getUser('first_name') === null ? $this->getUser('username') : $this->getUser('first_name')))->secondaryText('Your timezone is <a href="' . Url::href('profile') . '">' . $user['timezone'] . '</a>, ' . Timezone::date($user['timezone'], 'M dS, H:i:s')); $elements[] = Bootstrap::row()->add(12, $title); // last reports row $row = Bootstrap::row(); $minutes = 15; $panel = Bootstrap::panel("Reports per minute in last {$minutes} minutes", new Chart\RequestsPerSecond($minutes))->color('blue'); $row->add(4, $panel); $panel = Bootstrap::panel("Problematic apps in last {$minutes} minutes", new Chart\ProblematicApps($minutes))->color('blue'); $row->add(4, $panel); $panel = Bootstrap::panel("Problematic brands in last {$minutes} minutes", new Chart\ProblematicBrands($minutes))->color('blue'); $row->add(4, $panel); $elements[] = $row; // quick reports $row = Bootstrap::row(); // quick links $listGroup = Bootstrap::listGroup(); foreach (Menu::getReportLinks() as $url => $text) { $listGroup->addLink($url, $text); } $row->add(4, Bootstrap::panel('Quick links', $listGroup)); // countries $panel = Bootstrap::panel("Reports from countries in last {$minutes} minutes", new Chart\ProblematicCountries($minutes))->color('blue'); $row->add(4, $panel); // OS versions $panel = Bootstrap::panel("OS and version in last {$minutes} minutes", new Chart\ProblematicOsVersions($minutes))->color('blue'); $row->add(4, $panel); $elements[] = $row; $dashboardDaysCacheKey = "DashboardDays-last-10-days-offset-0min"; if (!$calculationInProgress || Cache::has($dashboardDaysCacheKey)) { // dahsboard last 10 days $row = Bootstrap::row(); $row->add(12, Bootstrap::panel('Number of crash reports in last 10 days', new Chart\DashboardDays(10))->color('blue')); $elements[] = $row; } return View::create('base')->with('title', 'Dashboard')->with('content', $elements); }
public function searchAjax() { $validator = Validator::create(array('package_id' => 'required|integer', 'package_version_id' => 'required|integer', 'brand_id' => 'required|integer', 'os_version_id' => 'required|integer', 'product_id' => 'required|integer', 'model_id' => 'required|integer', 'country_id' => 'required|integer', 'provider_id' => 'required|integer', 'date_from' => null, 'date_to' => null, 'stack_trace_id' => 'required|integer')); if ($validator->failed()) { Application::throwError(400, 'Bad request'); } else { $params = $validator->getParamsObj(); $prms = array(); $query = new ResultSet(); $count = new Select(); $count->from('crash_archive', 'a')->field('COUNT(*)', 'total'); $query->from('crash_archive', 'a')->field('a.id')->field('a.created_at')->leftJoin('package p', 'p.id', '=', 'a.package_id')->field('p.name', 'package_name')->leftJoin('package_version pv', 'pv.id', '=', 'a.package_version_id')->field('pv.value', 'package_version')->leftJoin('brand b', 'b.id', '=', 'a.brand_id')->field('b.name', 'brand_name')->leftJoin('stack_trace st', 'st.id', '=', 'a.stack_trace_id')->field('st.summary', 'stack_trace')->leftJoin('version v', 'v.id', '=', 'a.os_version_id')->field('v.os', 'os_name')->field('v.name', 'os_version_name')->leftJoin('country c', 'c.id', '=', 'a.country_id')->field('c.country', 'country_name')->field('c.tld', 'tld'); if ($params->date_from !== null) { $dateFrom = new DateTime($params->date_from); $query->where('a.created_at', '>=', Misc::utcFromUser('Y-m-d H:i:s', $dateFrom)); $count->where('a.created_at', '>=', Misc::utcFromUser('Y-m-d H:i:s', $dateFrom)); $prms['date_from'] = $params->date_from; } if ($params->date_to !== null) { $dateTo = new DateTime($params->date_to); $query->where('a.created_at', '<', Misc::utcFromUser('Y-m-d H:i:s', $dateTo)); $count->where('a.created_at', '<', Misc::utcFromUser('Y-m-d H:i:s', $dateTo)); $prms['date_to'] = $params->date_to; } if ($params->package_id > 0) { $query->where('a.package_id', $params->package_id); $count->where('a.package_id', $params->package_id); $prms['package_id'] = $params->package_id; } if ($params->package_version_id > 0) { $query->where('a.package_version_id', $params->package_version_id); $count->where('a.package_version_id', $params->package_version_id); $prms['package_version_id'] = $params->package_version_id; } if ($params->brand_id > 0) { $query->where('a.brand_id', $params->brand_id); $count->where('a.brand_id', $params->brand_id); $prms['brand_id'] = $params->brand_id; } if ($params->os_version_id > 0) { $query->where('a.os_version_id', $params->os_version_id); $count->where('a.os_version_id', $params->os_version_id); $prms['os_version_id'] = $params->os_version_id; } if ($params->product_id > 0) { $query->where('a.product_id', $params->product_id); $count->where('a.product_id', $params->product_id); $prms['product_id'] = $params->product_id; } if ($params->model_id > 0) { $query->where('a.model_id', $params->model_id); $count->where('a.model_id', $params->model_id); $prms['model_id'] = $params->model_id; } if ($params->country_id > 0) { $query->where('a.country_id', $params->country_id); $count->where('a.country_id', $params->country_id); $prms['country_id'] = $params->country_id; } if ($params->provider_id > 0) { $query->where('a.provider_id', $params->provider_id); $count->where('a.provider_id', $params->provider_id); $prms['provider_id'] = $params->provider_id; } if ($params->stack_trace_id > 0) { $query->where('a.stack_trace_id', $params->stack_trace_id); $count->where('a.stack_trace_id', $params->stack_trace_id); $prms['stack_trace_id'] = $params->stack_trace_id; } if (sizeof($prms) == 1) { // speed up count(*) ... because we have that precalculated if (isset($prms['stack_trace_id'])) { $count = new Select(); $count->from('stack_trace')->field('total')->where('id', $prms['stack_trace_id']); } else { if (isset($prms['brand_id'])) { $count = new Select(); $count->from('brand')->field('total')->where('id', $prms['brand_id']); } else { if (isset($prms['package_id'])) { $count = new Select(); $count->from('package')->field('total')->where('id', $prms['package_id']); } else { if (isset($prms['package_version_id'])) { $count = new Select(); $count->from('package_version')->field('total')->where('id', $prms['package_version_id']); } else { if (isset($prms['os_version_id'])) { $count = new Select(); $count->from('version')->field('total')->where('id', $prms['os_version_id']); } else { if (isset($prms['country_id'])) { $count = new Select(); $count->from('country')->field('total')->where('id', $prms['country_id']); } else { if (isset($prms['provider_id'])) { $count = new Select(); $count->from('provider')->field('total')->where('id', $prms['provider_id']); } else { if (isset($prms['model_id'])) { $count = new Select(); $count->from('phone_model')->field('total')->where('id', $prms['model_id']); } } } } } } } } } $query->setCountQuery($count); return BootstrapUI::tableRemoteResponse()->column('country_name', function ($value, $row) { if ($row['tld'] !== null) { $country = \Koldy\Html::quotes($row['country_name']); return '<img src="' . \Koldy\Url::link("img/flag/{$row['tld']}.png") . '" title="' . $country . '" />'; } else { return ''; } })->column('created_at', function ($value, $row) { $user = \Koldy\Session::get('user'); return \Koldy\Timezone::date($user['timezone'], 'd.m.Y', strtotime($value)) . '<br/>' . \Koldy\Timezone::date($user['timezone'], 'H:i:s', strtotime($value)); })->column('package_name', function ($value, $row) { $html = $value; $html .= "<details><summary>View stack trace summary</summary><pre class=\"text-danger\">{$row['stack_trace']}</pre></details>"; return $html; })->column('package_version')->column('brand_name')->column('os_version_name', function ($value, $row) { return "{$row['os_name']} {$row['os_version_name']}"; })->column('country')->column('action', function ($value, $row) { return \Bootstrap::anchor(\Bootstrap::icon('eye-open'), \Koldy\Url::href('report', $row['id']))->title('View report')->size('xs'); })->resultSet($query)->handle(); } }
public function viewAction() { $id = Url::getVar(1); // todo: ubaciti ovo u cache i odatle cupat van $cacheKey = "report-{$id}"; $crash = CrashArchive::fetchOne($id); if ($crash === false) { Application::throwError(404, 'Can not find crash report ' . $id); } $title = "Crash Report #{$id}"; $content = array(); $panel = Bootstrap::panel($title)->color('blue')->addHeaderElement(Bootstrap::button('Back')->setAttribute('onclick', 'window.history.back()')->color('red')->size('xs')); $table = Bootstrap::table(); $table->column('id', '')->column('value', ''); // time $table->row(array('id' => 'time', 'value' => Misc::userDate('Y-m-d H:i:s', $crash->created_at) . ' (' . $this->user['timezone'] . ')')); // package $e = $crash->getPackage(); $v = $crash->getPackageVersion(); $table->row(array('id' => 'package and version', 'value' => implode(' ', array($e !== null ? "{$this->getSearchLink('package_id', $e->id, $e->name)} {$this->getLabel($e->total)}" : 'unknown', $v !== null ? "{$this->getSearchLink('package_version_id', $v->id, $v->value)} {$this->getLabel($v->total)}" : 'unknown')))); // device $value = ''; $e = $crash->getBrand(); if ($e === null) { $value .= 'unknown brand<br/>'; } else { $value .= "{$this->getSearchLink('brand_id', $e->id, $e->name)} {$this->getLabel($e->total)}<br/>"; } $e = $crash->getPhoneModel(); if ($e === null) { $value .= 'unknown phone model<br/>'; } else { $value .= "{$this->getSearchLink('model_id', $e->id, $e->name)} {$this->getLabel($e->total)}<br/>"; } $table->row(array('id' => 'device', 'value' => substr($value, 0, -5))); // product $e = $crash->getProduct(); if ($e !== null) { $table->row(array('id' => 'product name', 'value' => "{$this->getSearchLink('product_id', $e->id, $e->name)} {$this->getLabel($e->total)}")); } // os $e = $crash->getOsVersion(); $table->row(array('id' => 'OS', 'value' => $e === null ? 'unknown' : "{$this->getSearchLink('os_version_id', $e->id, "{$e->os} {$e->name}")} {$this->getLabel($e->total)}")); // user comment if ($crash->user_comment !== null && trim($crash->user_comment) != '') { $table->row(array('id' => 'user comment', 'value' => $crash->user_comment)); } // user email if ($crash->user_email !== null && trim($crash->user_email) != '') { $table->row(array('id' => 'user email', 'value' => $crash->user_email)); } // app lifetime if ($crash->user_app_start_date !== null && $crash->user_crash_date !== null) { $table->row(array('id' => 'app lifetime', 'value' => "{$crash->user_app_start_date}<br/>{$crash->user_crash_date} (duration: {$this->duration($crash->user_app_start_date, $crash->user_crash_date)})")); } // memory usage $table->row(array('id' => 'available / total memory size', 'value' => Convert::bytesToString($crash->available_mem_size) . ' / ' . Convert::bytesToString($crash->total_mem_size))); // country if ($crash->country_id !== null) { $country = Country::fetchOne($crash->country_id); $table->row(array('id' => 'country', 'value' => "<img src=\"" . Url::link("img/flag/{$country->tld}.png") . "\" /> <a href=\"" . Url::href('reports', 'search', array('country_id' => $crash->country_id)) . "\">{$country->country} (" . strtoupper($country->tld) . ")</a> " . Bootstrap::label($country->total)->color('red'))); } // provider if ($crash->provider_id !== null) { $e = Provider::fetchOne($crash->provider_id); $table->row(array('id' => 'internet provider', 'value' => "{$this->getSearchLink('provider_id', $e->id, $e->name)} {$this->getLabel($e->total)}")); } $metas = $crash->getMetas(); $toTabs = array(); foreach ($metas as $key => $value) { if ($key != 'stack_trace') { if (strpos(trim($value), "\n") === false) { $table->row(array('id' => str_replace('_', ' ', $key), 'value' => trim($value) == '' ? '<em>empty</em>' : $value)); } else { $toTabs[] = $key; } } } $toTabsUnknown = array(); $unknownMetas = $crash->getUnknownMetas(); foreach ($unknownMetas as $key => $value) { if (strpos(trim($value), "\n") === false) { $table->row(array('id' => str_replace('_', ' ', $key), 'value' => (trim($value) == '' ? '<em>empty</em>' : $value) . ' ' . Bootstrap::label('unknown meta')->color('lightblue'))); } else { $toTabsUnknown[] = $key; } } if ($crash->stack_trace_id !== null) { $table->row(array('id' => 'find reports with this stack trace', 'value' => Bootstrap::anchor(\Bootstrap::icon('search'), Url::href('reports', 'search', array('stack_trace_id' => $crash->stack_trace_id)))->asButton()->color('red')->size('xs'))); } $panel->content($table); $content[] = Bootstrap::row()->add(12, $panel); $tabs = Bootstrap::nav(); if (isset($metas['stack_trace'])) { $tabs->addLink('stack trace', "<pre class=\"text-danger\">{$metas['stack_trace']}</pre>"); } else { if ($crash->stack_trace_id !== null) { $stackTrace = Stack\Trace::fetchOne($crash->stack_trace_id); $tabs->addLink('stack trace summary', "<pre class=\"text-danger\">{$stackTrace->summary}</pre>"); } } if (sizeof($toTabs) > 0) { foreach ($toTabs as $key) { $tabs->addLink(str_replace('_', ' ', $key), "<pre>{$metas[$key]}</pre>"); } } if (sizeof($toTabsUnknown) > 0) { foreach ($toTabsUnknown as $key) { $tabs->addLink(str_replace('_', ' ', $key) . ' ' . Bootstrap::label('?')->color('lightblue'), "<pre>{$unknownMetas[$key]}</pre>"); } } if ($tabs->count() > 0) { $content[] = Bootstrap::row()->add(12, $tabs); } if ($crash->stack_trace_id !== null) { $content[] = Bootstrap::row()->add(12, Bootstrap::panel('This error count per day', new Chart\StackTracesPerDay($crash->stack_trace_id, 30))->color('red')); } return View::create('base')->with('title', $title)->with('content', $content); }