Update code to match master

This commit is contained in:
Joseph Cohen
2015-03-26 15:07:16 -06:00
parent eb22ac6d8a
commit 37e20bf2bf
15 changed files with 192 additions and 105 deletions

View File

@@ -77,6 +77,10 @@ Now go to `http://<ipdockerisboundto>/setup` and have fun!
Note: When running in production you should ensure that you enable SSL. Note: When running in production you should ensure that you enable SSL.
This is commonly achieved by running Nginx with your certificates on your Docker host, service or load balancers in-front of the running container, or by adding your custom SSL certificates and configuration to the supplied Nginx configuration. This is commonly achieved by running Nginx with your certificates on your Docker host, service or load balancers in-front of the running container, or by adding your custom SSL certificates and configuration to the supplied Nginx configuration.
## Addons
- [cachet-monitor](https://github.com/castawaylabs/cachet-monitor) - For url monitoring. Automatic incident updates
## Read more about Cachet ## Read more about Cachet
For more information on why I started developing Cachet, check out my [Cachet articles on my blog](https://james-brooks.uk/tag/cachet/?utm_source=github&utm_medium=readme&utm_campaign=github-cachet). For more information on why I started developing Cachet, check out my [Cachet articles on my blog](https://james-brooks.uk/tag/cachet/?utm_source=github&utm_medium=readme&utm_campaign=github-cachet).

View File

@@ -4,6 +4,7 @@ namespace CachetHQ\Cachet\Http\Controllers\Admin;
use CachetHQ\Cachet\Http\Controllers\AbstractController; use CachetHQ\Cachet\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate; use CachetHQ\Cachet\Models\IncidentTemplate;
use GrahamCampbell\Binput\Facades\Binput; use GrahamCampbell\Binput\Facades\Binput;
@@ -68,10 +69,14 @@ class IncidentController extends AbstractController
*/ */
public function showAddIncident() public function showAddIncident()
{ {
$componentsInGroups = ComponentGroup::with('components')->get();
$componentsOutGroups = Component::where('group_id', 0)->get();
return View::make('dashboard.incidents.add')->with([ return View::make('dashboard.incidents.add')->with([
'pageTitle' => trans('dashboard.incidents.add.title').' - '.trans('dashboard.dashboard'), 'pageTitle' => trans('dashboard.incidents.add.title').' - '.trans('dashboard.dashboard'),
'components' => Component::all(), 'componentsInGroups' => $componentsInGroups,
'incidentTemplates' => IncidentTemplate::all(), 'componentsOutGroups' => $componentsOutGroups,
'incidentTemplates' => IncidentTemplate::all(),
]); ]);
} }
@@ -248,10 +253,14 @@ class IncidentController extends AbstractController
*/ */
public function showEditIncidentAction(Incident $incident) public function showEditIncidentAction(Incident $incident)
{ {
$componentsInGroups = ComponentGroup::with('components')->get();
$componentsOutGroups = Component::where('group_id', 0)->get();
return View::make('dashboard.incidents.edit')->with([ return View::make('dashboard.incidents.edit')->with([
'pageTitle' => trans('dashboard.incidents.edit.title').' - '.trans('dashboard.dashboard'), 'pageTitle' => trans('dashboard.incidents.edit.title').' - '.trans('dashboard.dashboard'),
'incident' => $incident, 'incident' => $incident,
'components' => Component::all(), 'componentsInGroups' => $componentsInGroups,
'componentsOutGroups' => $componentsOutGroups,
]); ]);
} }

View File

@@ -12,9 +12,11 @@ class AtomController extends AbstractController
/** /**
* Generates an Atom feed of all incidents. * Generates an Atom feed of all incidents.
* *
* @param \CachetHQ\Cachet\Models\ComponentGroup|null $group
*
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function feedAction() public function feedAction(ComponentGroup $group = null)
{ {
$feed = Feed::make(); $feed = Feed::make();
$feed->title = Setting::get('app_name'); $feed->title = Setting::get('app_name');
@@ -23,23 +25,37 @@ class AtomController extends AbstractController
$feed->setDateFormat('datetime'); $feed->setDateFormat('datetime');
Incident::all()->map(function ($incident) use ($feed) { if ($group) {
if ($incident->component) { $group->components->map(function ($component) use ($feed) {
$componentName = $incident->component->name; $component->incidents->orderBy('created_at', 'desc')->map(function ($incident) use ($feed) {
} else { $this->feedAddItem($feed, $incident);
$componentName = null; });
} });
} else {
$feed->add( Incident::orderBy('created_at', 'desc')->get()->map(function ($incident) use ($feed) {
$incident->name, $this->feedAddItem($feed, $incident);
Setting::get('app_name'), });
Setting::get('app_domain'), }
$incident->created_at,
($componentName === null ? $incident->humanStatus : $componentName.' '.$incident->humanStatus),
$incident->message
);
});
return $feed->render('atom'); return $feed->render('atom');
} }
/**
* Adds an item to the feed.
*
* @param \Thujohn\Rss\Rss $feed
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return void
*/
private function feedAddItem(& $feed, $incident)
{
$feed->add(
$incident->name,
Setting::get('app_name'),
Setting::get('app_domain'),
$incident->created_at->toAtomString(),
$incident->message
);
}
} }

View File

@@ -10,11 +10,13 @@ use Roumen\Feed\Facades\Feed;
class RssController extends AbstractController class RssController extends AbstractController
{ {
/** /**
* Generates an RSS feed of all incidents. * Generates an Atom feed of all incidents.
*
* @param \CachetHQ\Cachet\Models\ComponentGroup|null $group
* *
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function feedAction() public function feedAction(ComponentGroup $group = null)
{ {
$feed = Feed::make(); $feed = Feed::make();
$feed->title = Setting::get('app_name'); $feed->title = Setting::get('app_name');
@@ -23,23 +25,37 @@ class RssController extends AbstractController
$feed->setDateFormat('datetime'); $feed->setDateFormat('datetime');
Incident::all()->map(function ($incident) use ($feed) { if ($group) {
if ($incident->component) { $group->components->map(function ($component) use ($feed) {
$componentName = $incident->component->name; $component->incidents->orderBy('created_at', 'desc')->map(function ($incident) use ($feed) {
} else { $this->feedAddItem($feed, $incident);
$componentName = null; });
} });
} else {
$feed->add( Incident::orderBy('created_at', 'desc')->get()->map(function ($incident) use ($feed) {
$incident->name, $this->feedAddItem($feed, $incident);
Setting::get('app_name'), });
Setting::get('app_domain'), }
$incident->created_at,
($componentName === null ? $incident->humanStatus : $componentName.' '.$incident->humanStatus),
$incident->message
);
});
return $feed->render('rss'); return $feed->render('rss');
} }
/**
* Adds an item to the feed.
*
* @param \Thujohn\Rss\Rss $feed
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return void
*/
private function feedAddItem(& $feed, $incident)
{
$feed->add(
$incident->name,
Setting::get('app_name'),
Setting::get('app_domain'),
$incident->created_at->toAtomString(),
$incident->message
);
}
} }

View File

@@ -21,8 +21,8 @@ class StatusPageRoutes
'as' => 'status-page', 'as' => 'status-page',
'uses' => 'HomeController@showIndex', 'uses' => 'HomeController@showIndex',
]); ]);
$router->get('/atom', 'AtomController@feedAction'); $router->get('/atom/{component_group?}', 'AtomController@feedAction');
$router->get('/rss', 'RssController@feedAction'); $router->get('/rss/{component_group?}', 'RssController@feedAction');
}); });
} }
} }

View File

@@ -3,7 +3,6 @@
namespace CachetHQ\Cachet\Models; namespace CachetHQ\Cachet\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
@@ -15,7 +14,7 @@ use Watson\Validating\ValidatingTrait;
*/ */
class ComponentGroup extends Model class ComponentGroup extends Model
{ {
use SoftDeletes, ValidatingTrait; use ValidatingTrait;
/** /**
* The validation rules. * The validation rules.
@@ -33,13 +32,6 @@ class ComponentGroup extends Model
*/ */
protected $fillable = ['name']; protected $fillable = ['name'];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['deleted_at'];
/** /**
* A group can have many components. * A group can have many components.
* *

View File

@@ -14,6 +14,8 @@ use Watson\Validating\ValidatingTrait;
* @property string $name * @property string $name
* @property string $suffix * @property string $suffix
* @property string $description * @property string $description
* @property float $default_value
* @property int $calc_type
* @property int $display_chart * @property int $display_chart
* @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property \Carbon\Carbon $updated_at
@@ -90,6 +92,8 @@ class Metric extends Model
$queryType = "sum(metric_points.value)"; $queryType = "sum(metric_points.value)";
} elseif ($this->calc_type === self::CALC_AVG) { } elseif ($this->calc_type === self::CALC_AVG) {
$queryType = "avg(metric_points.value)"; $queryType = "avg(metric_points.value)";
} else {
$queryType = "sum(metric_points.value)";
} }
$query = DB::select("select {$queryType} as aggregate FROM metrics JOIN metric_points ON metric_points.metric_id = metrics.id WHERE to_char(metric_points.created_at, 'YYYYMMDDHH') = :timestamp AND to_char(metric_points.created_at, 'H') = to_char(now() - interval '{$hour} hour', 'H') GROUP BY to_char(metric_points.created_at, 'H')", [ $query = DB::select("select {$queryType} as aggregate FROM metrics JOIN metric_points ON metric_points.metric_id = metrics.id WHERE to_char(metric_points.created_at, 'YYYYMMDDHH') = :timestamp AND to_char(metric_points.created_at, 'H') = to_char(now() - interval '{$hour} hour', 'H') GROUP BY to_char(metric_points.created_at, 'H')", [

View File

@@ -17,7 +17,6 @@ class CreateComponentGroupsTable extends Migration
$table->increments('id'); $table->increments('id');
$table->string('name'); $table->string('name');
$table->timestamps(); $table->timestamps();
$table->softDeletes();
}); });
} }

View File

@@ -19,6 +19,7 @@ return [
'next_week' => 'nächste Woche', 'next_week' => 'nächste Woche',
'none' => 'keine Vorfälle', 'none' => 'keine Vorfälle',
'status' => [ 'status' => [
0 => '',
1 => 'Untersuchung läuft', 1 => 'Untersuchung läuft',
2 => 'Problem identifiziert', 2 => 'Problem identifiziert',
3 => 'Problem unter Beobachtung', 3 => 'Problem unter Beobachtung',

View File

@@ -19,6 +19,7 @@ return [
'next_week' => 'Siguiente semana', 'next_week' => 'Siguiente semana',
'none' => 'No hay ninguna incidencia reportada.', 'none' => 'No hay ninguna incidencia reportada.',
'status' => [ 'status' => [
0 => '',
1 => 'Investigando', 1 => 'Investigando',
2 => 'Identificado', 2 => 'Identificado',
3 => 'Observando', 3 => 'Observando',

View File

@@ -18,10 +18,13 @@ return [
'previous_week' => 'Semaine précédente', 'previous_week' => 'Semaine précédente',
'next_week' => 'Semaine suivante', 'next_week' => 'Semaine suivante',
'none' => 'Rien à reporter', 'none' => 'Rien à reporter',
'scheduled' => 'Maintenance planifiée',
'scheduled_at' => ', prévue à :timestamp',
'status' => [ 'status' => [
0 => '',
1 => 'Enquête en cours', 1 => 'Enquête en cours',
2 => 'Identifié', 2 => 'Identifié',
3 => 'Analyse en cours', 3 => 'Sous surveillance',
4 => 'Corrigé', 4 => 'Corrigé',
], ],
], ],
@@ -37,6 +40,15 @@ return [
'revoke' => 'Révoquer cette clé d\'API', 'revoke' => 'Révoquer cette clé d\'API',
], ],
// Metrics
'metrics' => [
'filter' => [
'hourly' => 'Par heure',
'daily' => 'Par jour',
'monthly' => 'Par mois',
],
],
// Other // Other
'powered_by' => ':app Status Page est propulsé par <a href="https://cachethq.github.io">Cachet</a>.', 'powered_by' => ':app Status Page est propulsé par <a href="https://cachethq.github.io">Cachet</a>.',
'about_this_site' => 'À propos de ce site', 'about_this_site' => 'À propos de ce site',

View File

@@ -13,12 +13,12 @@ return [
'add' => [ 'add' => [
'title' => 'Ajouter un incident', 'title' => 'Ajouter un incident',
'success' => 'Incident ajouté.', 'success' => 'Incident ajouté.',
'failure' => 'Il s\'est passé quelque chose avec cet incident.', 'failure' => 'Une erreur s\'est produite lors de l\'ajout de cet incident.',
], ],
'edit' => [ 'edit' => [
'title' => 'Éditer un incident', 'title' => 'Éditer un incident',
'success' => 'Incident mis-à-jour.', 'success' => 'Incident mis-à-jour.',
'failure' => 'Il s\'est passé quelque chose avec cet incident.', 'failure' => 'Une erreur s\'est produite lors de la mise à jour de cet incident.',
], ],
// Incident templates // Incident templates
@@ -26,7 +26,7 @@ return [
'add' => [ 'add' => [
'title' => 'Créer un modèle d\'incident', 'title' => 'Créer un modèle d\'incident',
'success' => 'Modèle créé.', 'success' => 'Modèle créé.',
'failure' => 'Il s\'est passé quelque chose avec ce modèle d\'incident.', 'failure' => 'Une erreur s\'est produite lors de l\'ajout de ce modèle d\'incident.',
], ],
'edit' => [ 'edit' => [
'title' => 'Modifier un modèle', 'title' => 'Modifier un modèle',
@@ -36,34 +36,54 @@ return [
], ],
], ],
// Components // Incident Maintenance
'components' => [ 'schedule' => [
'components' => 'Composant|Composants', 'schedule' => 'Maintenance planifiée',
'component_statuses' => 'Statut des composants', 'scheduled_at' => 'Prévue à :timestamp',
'add' => [ 'add' => [
'title' => 'Créer un composant', 'title' => 'Ajouter une maintenance planifiée',
'message' => 'Commencez par ajouter un composant.', 'success' => 'Maintenance ajoutée.',
'success' => 'Composant créé.', 'failure' => 'Une erreur s\'est produite lors de l\'ajout de la maintenance.',
'failure' => 'Il s\'est passé quelque chose avec ce composant.',
], ],
'edit' => [ 'edit' => [
'title' => 'Éditer un composant', 'title' => 'Éditer la maintenance',
'success' => 'Maintenance mise à jour!',
'failure' => 'Une erreur s\'est produite lors de la modification de la maintenance.',
],
'delete' => [
'success' => 'La maintenance a été effacée et ne s\'affihera plus..',
'failure' => 'La maintenance n\'a pu être effacée. Veuillez essayez de nouveau.',
],
],
// Components
'components' => [
'components' => 'Composantes',
'component_statuses' => 'Statut des composantes',
'add' => [
'title' => 'Créer une composante',
'message' => 'Commencez par ajouter une composante.',
'success' => 'Composante créée.',
'failure' => 'Une erreur s\'est produite lors de l\'ajout de cette composante.',
],
'edit' => [
'title' => 'Éditer une composante',
'success' => 'Composant mis-à-jour.', 'success' => 'Composant mis-à-jour.',
'failure' => 'Il s\'est passé quelque chose avec ce composant.', 'failure' => 'Une erreur s\'est produite lors de la mise à jour de cette composante.',
], ],
// Component groups // Component groups
'groups' => [ 'groups' => [
'groups' => 'Groupe de composants|Groupes de composants', 'groups' => 'Groupe de composantes',
'add' => [ 'add' => [
'title' => 'Ajouter un group de composants', 'title' => 'Ajouter un group de composantes',
'success' => 'Groupe de composants ajouté.', 'success' => 'Groupe de composantes ajouté.',
'failure' => 'Il s\'est passé quelque chose avec ce composantgroupe de composants.', 'failure' => 'Une erreur s\'est produite lors de l\'ajout de ce groupe de composantes.',
], ],
'edit' => [ 'edit' => [
'title' => 'Edit a component group', 'title' => 'Éditer un groupe de composantes',
'success' => 'Component group updated.', 'success' => 'Groupe de composantes mis-à-jour.',
'failure' => 'Something went wrong with the component group.', 'failure' => 'Une erreur s\'est produite lors de la mise à jour de ce groupe de composantes.',
], ],
], ],
], ],
@@ -77,9 +97,9 @@ return [
'failure' => 'Il s\'est passé quelque chose avec ce point de mesure.', 'failure' => 'Il s\'est passé quelque chose avec ce point de mesure.',
], ],
'edit' => [ 'edit' => [
'title' => 'Edit a metric', 'title' => 'Éditer un point de mesure',
'success' => 'Metric updated.', 'success' => 'Point de mesure mis-à-jour.',
'failure' => 'Something went wrong with the metric.', 'failure' => 'Il s\'est passé quelque chose avec ce point de mesure.',
], ],
], ],
@@ -88,16 +108,16 @@ return [
'team' => 'Équipe', 'team' => 'Équipe',
'member' => 'Membre', 'member' => 'Membre',
'profile' => 'Profil', 'profile' => 'Profil',
'description' => 'Les membres de l\'équipe pourrons ajouter, modifier &amp; éditer les composants et incidents.', 'description' => 'Les membres de l\'équipe pourrons ajouter, modifier &amp; éditer les composantes et incidents.',
'add' => [ 'add' => [
'title' => 'Ajouter un membre à l\'équipe', 'title' => 'Ajouter un membre à l\'équipe',
'success' => 'Membre ajouté.', 'success' => 'Membre ajouté.',
'failure' => 'Il s\'est passé quelque chose avec ce membre.', 'failure' => 'Une erreur s\'est produite lors de l\'ajout de ce membre.',
], ],
'edit' => [ 'edit' => [
'title' => 'Mettre à jour le profil', 'title' => 'Mettre à jour le profil',
'success' => 'Profil mis-à-jour.', 'success' => 'Profil mis-à-jour.',
'failure' => 'Il s\'est passé quelque chose en mettant à jour le profil.', 'failure' => 'Une erreur s\'est produite lors de la mise à jour du le profil.',
], ],
], ],
@@ -129,7 +149,7 @@ return [
'login' => 'Connexion', 'login' => 'Connexion',
'logged_in' => "Vous êtes connecté.", 'logged_in' => "Vous êtes connecté.",
'welcome' => 'Re-bonjour !', 'welcome' => 'Re-bonjour !',
'two-factor' => 'Please enter your token.', 'two-factor' => 'Entrez votre jeton d\'identification.',
], ],
// Sidebar footer // Sidebar footer
@@ -140,22 +160,22 @@ return [
// Notifications // Notifications
'notifications' => [ 'notifications' => [
'notifications' => 'Notifications', 'notifications' => 'Notifications',
'awesome' => 'Cool.', 'awesome' => 'Super.',
'whoops' => 'Oups.', 'whoops' => 'Oups.',
], ],
// Welcome modal // Welcome modal
'welcome' => [ 'welcome' => [
'welcome' => 'Welcome to Cachet', 'welcome' => 'Bienvenue dans Cachet',
'message' => 'Your status page is almost ready! You might want to configure these extra settings', 'message' => 'Votre page d\'état est presque prête! Vous voudrez probablement configurer ces réglages supplémentaires',
'close' => 'Just go straight to my dashboard', 'close' => 'Aller directement au tableau de bord',
'steps' => [ 'steps' => [
'component' => 'Create components', 'component' => 'Créer une composante',
'incident' => 'Create incidents', 'incident' => 'Créer un incident',
'customize' => 'Customize your Cachet Status Page.', 'customize' => 'Configurer votre Cachet.',
'team' => 'Add users to your team.', 'team' => 'Ajouter des utilisateurs à votre équipe.',
'api' => 'Generate API token.', 'api' => 'Générer un jeton d\'identification API.',
'two-factor' => 'Enable Two Factor Authetication.', 'two-factor' => 'Activer l\'identification à deux étapes.',
], ],
], ],

View File

@@ -55,12 +55,19 @@
{{ trans('cachet.incidents.status')[4] }} {{ trans('cachet.incidents.status')[4] }}
</label> </label>
</div> </div>
@if($components->count() > 0) @if(!$componentsInGroups->isEmpty() || !$componentsOutGroups->isEmpty())
<div class="form-group"> <div class="form-group">
<label>{{ trans('forms.incidents.component') }}</label> <label>{{ trans('forms.incidents.component') }}</label>
<select name='incident[component_id]' class='form-control'> <select name='incident[component_id]' class='form-control'>
<option value='0' selected></option> <option value='0' selected></option>
@foreach($components as $component) @foreach($componentsInGroups as $group)
<optgroup label="{{ $group->name }}">
@foreach($group->components as $component)
<option value='{{ $component->id }}'>{{ $component->name }}</option>
@endforeach
</optgroup>
@endforeach
@foreach($componentsOutGroups as $component)
<option value='{{ $component->id }}'>{{ $component->name }}</option> <option value='{{ $component->id }}'>{{ $component->name }}</option>
@endforeach @endforeach
</select> </select>

View File

@@ -44,16 +44,23 @@
{{ trans('cachet.incidents.status')[4] }} {{ trans('cachet.incidents.status')[4] }}
</label> </label>
</div> </div>
@if($components->count() > 0) @if(!$componentsInGroups->isEmpty() || !$componentsOutGroups->isEmpty())
<div class='form-group'> <div class="form-group">
<label>{{ trans('forms.incidents.component') }}</label> <label>{{ trans('forms.incidents.component') }}</label>
<select name='incident[component_id]' class='form-control'> <select name='incident[component_id]' class='form-control'>
<option value='0' {{ $incident->id === 0 ? "selected" : null }}></option> <option value='0' selected></option>
@foreach($components as $component) @foreach($componentsInGroups as $group)
<option value='{{ $component->id }}' {{ $incident->component_id === $component->id ? "selected" : null }}>{{ $component->name }}</option> <optgroup label="{{ $group->name }}">
@endforeach @foreach($group->components as $component)
</select> <option value='{{ $component->id }}'>{{ $component->name }}</option>
<span class='help-block'>{{ trans('forms.optional') }}</span> @endforeach
</optgroup>
@endforeach
@foreach($componentsOutGroups as $component)
<option value='{{ $component->id }}'>{{ $component->name }}</option>
@endforeach
</select>
<span class='help-block'>{{ trans('forms.optional') }}</span>
</div> </div>
<div class="form-group {{ $incident->component_id === 0 ? 'hidden' : null }}" id='component-status'> <div class="form-group {{ $incident->component_id === 0 ? 'hidden' : null }}" id='component-status'>
<div class="well"> <div class="well">

View File

@@ -20,7 +20,6 @@
<div class="row striped-list-item"> <div class="row striped-list-item">
<div class="col-xs-6"> <div class="col-xs-6">
<strong>{{ $template->name }}</strong> <strong>{{ $template->name }}</strong>
<p><small>{{ $template->template }}</small></p>
</div> </div>
<div class="col-xs-6 text-right"> <div class="col-xs-6 text-right">
<a href="/dashboard/templates/{{ $template->id }}/edit" class="btn btn-default">{{ trans('forms.edit') }}</a> <a href="/dashboard/templates/{{ $template->id }}/edit" class="btn btn-default">{{ trans('forms.edit') }}</a>