Add incident column for when an incident occurred at (#2212)
Add incident column for when an incident occurred at. Closes #2208 [ci skip] [skip ci]
This commit is contained in:
@@ -76,11 +76,11 @@ final class ReportIncidentCommand
|
||||
public $stickied;
|
||||
|
||||
/**
|
||||
* The date at which the incident occurred.
|
||||
* The date at which the incident occurred at.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $incident_date;
|
||||
public $occurred_at;
|
||||
|
||||
/**
|
||||
* A given incident template.
|
||||
@@ -110,7 +110,7 @@ final class ReportIncidentCommand
|
||||
'component_status' => 'nullable|required_with:component_id|int|min:0|max:4',
|
||||
'notify' => 'nullable|bool',
|
||||
'stickied' => 'required|bool',
|
||||
'incident_date' => 'nullable|string',
|
||||
'occurred_at' => 'nullable|string',
|
||||
'template' => 'nullable|string',
|
||||
];
|
||||
|
||||
@@ -125,13 +125,13 @@ final class ReportIncidentCommand
|
||||
* @param int $component_status
|
||||
* @param bool $notify
|
||||
* @param bool $stickied
|
||||
* @param string|null $incident_date
|
||||
* @param string|null $occurred_at
|
||||
* @param string|null $template
|
||||
* @param array $template_vars
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $incident_date, $template, array $template_vars = [])
|
||||
public function __construct($name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $occurred_at, $template, array $template_vars = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->status = $status;
|
||||
@@ -141,7 +141,7 @@ final class ReportIncidentCommand
|
||||
$this->component_status = $component_status;
|
||||
$this->notify = $notify;
|
||||
$this->stickied = $stickied;
|
||||
$this->incident_date = $incident_date;
|
||||
$this->occurred_at = $occurred_at;
|
||||
$this->template = $template;
|
||||
$this->template_vars = $template_vars;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,13 @@ namespace CachetHQ\Cachet\Bus\Commands\Incident;
|
||||
|
||||
use CachetHQ\Cachet\Models\Incident;
|
||||
|
||||
/**
|
||||
* This is the update incident command.
|
||||
*
|
||||
* @author James Brooks <james@alt-three.com>
|
||||
* @author Joseph Cohem <joe@alt-three.com>
|
||||
* @author Graham Campbell <graham@alt-three.com>
|
||||
*/
|
||||
final class UpdateIncidentCommand
|
||||
{
|
||||
/**
|
||||
@@ -79,11 +86,11 @@ final class UpdateIncidentCommand
|
||||
public $stickied;
|
||||
|
||||
/**
|
||||
* The date that the incident occurred on.
|
||||
* The timestamp that the incident occurred at.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
public $incident_date;
|
||||
public $occurred_at;
|
||||
|
||||
/**
|
||||
* A given incident template.
|
||||
@@ -113,6 +120,7 @@ final class UpdateIncidentCommand
|
||||
'component_status' => 'nullable|int|min:0|max:4|required_with:component_id',
|
||||
'notify' => 'nullable|bool',
|
||||
'stickied' => 'nullable|bool',
|
||||
'occurred_at' => 'nullable|string',
|
||||
'template' => 'nullable|string',
|
||||
];
|
||||
|
||||
@@ -128,13 +136,13 @@ final class UpdateIncidentCommand
|
||||
* @param int $component_status
|
||||
* @param bool $notify
|
||||
* @param bool $stickied
|
||||
* @param string|null $incident_date
|
||||
* @param string|null $occurred_at
|
||||
* @param string|null $template
|
||||
* @param array $template_vars
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Incident $incident, $name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $incident_date, $template, array $template_vars = [])
|
||||
public function __construct(Incident $incident, $name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $occurred_at, $template, array $template_vars = [])
|
||||
{
|
||||
$this->incident = $incident;
|
||||
$this->name = $name;
|
||||
@@ -145,7 +153,7 @@ final class UpdateIncidentCommand
|
||||
$this->component_status = $component_status;
|
||||
$this->notify = $notify;
|
||||
$this->stickied = $stickied;
|
||||
$this->incident_date = $incident_date;
|
||||
$this->occurred_at = $occurred_at;
|
||||
$this->template = $template;
|
||||
$this->template_vars = $template_vars;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Cachet.
|
||||
*
|
||||
* (c) Alt Three Services Limited
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace CachetHQ\Cachet\Bus\Exceptions\Incident;
|
||||
|
||||
use CachetHQ\Cachet\Bus\Exceptions\ExceptionInterface;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* This is the invalid incident timestamp exception.
|
||||
*
|
||||
* @author James Brooks <james@alt-three.com>
|
||||
*/
|
||||
class InvalidIncidentTimestampException extends Exception implements ExceptionInterface
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Incident;
|
||||
use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand;
|
||||
use CachetHQ\Cachet\Bus\Commands\Incident\ReportIncidentCommand;
|
||||
use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent;
|
||||
use CachetHQ\Cachet\Bus\Exceptions\Incident\InvalidIncidentTimestampException;
|
||||
use CachetHQ\Cachet\Dates\DateFactory;
|
||||
use CachetHQ\Cachet\Models\Component;
|
||||
use CachetHQ\Cachet\Models\Incident;
|
||||
@@ -75,11 +76,12 @@ class ReportIncidentCommandHandler
|
||||
}
|
||||
|
||||
// The incident occurred at a different time.
|
||||
if ($command->incident_date) {
|
||||
$incidentDate = $this->dates->create('d/m/Y H:i', $command->incident_date);
|
||||
|
||||
$data['created_at'] = $incidentDate;
|
||||
$data['updated_at'] = $incidentDate;
|
||||
if ($occurredAt = $command->occurredAt) {
|
||||
if ($date = $this->dates->create('Y-m-d H:i', $occurredAt)) {
|
||||
$incident->fill(['occurred_at' => $date]);
|
||||
} else {
|
||||
throw new InvalidIncidentTimestampException("Unable to pass timestamp {$occurredAt}");
|
||||
}
|
||||
}
|
||||
|
||||
// Create the incident
|
||||
@@ -127,7 +129,7 @@ class ReportIncidentCommandHandler
|
||||
'visible' => $command->visible,
|
||||
'notify' => $command->notify,
|
||||
'stickied' => $command->stickied,
|
||||
'incident_date' => $command->incident_date,
|
||||
'occurredAt' => $command->occurredAt,
|
||||
'component' => Component::find($command->component_id) ?: null,
|
||||
'component_status' => $command->component_status,
|
||||
],
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Incident;
|
||||
use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand;
|
||||
use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand;
|
||||
use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent;
|
||||
use CachetHQ\Cachet\Bus\Exceptions\Incident\InvalidIncidentTimestampException;
|
||||
use CachetHQ\Cachet\Dates\DateFactory;
|
||||
use CachetHQ\Cachet\Models\Component;
|
||||
use CachetHQ\Cachet\Models\Incident;
|
||||
@@ -61,18 +62,20 @@ class UpdateIncidentCommandHandler
|
||||
}
|
||||
|
||||
$incident = $command->incident;
|
||||
$incident->update($this->filter($command));
|
||||
$incident->fill($this->filter($command));
|
||||
|
||||
// The incident occurred at a different time.
|
||||
if ($command->incident_date) {
|
||||
$incidentDate = $this->dates->create('d/m/Y H:i', $command->incident_date);
|
||||
|
||||
$incident->update([
|
||||
'created_at' => $incidentDate,
|
||||
'updated_at' => $incidentDate,
|
||||
]);
|
||||
if ($occurredAt = $command->occurredAt) {
|
||||
if ($date = $this->dates->create('Y-m-d H:i', $occurredAt)) {
|
||||
$incident->fill(['occurred_at' => $date]);
|
||||
} else {
|
||||
throw new InvalidIncidentTimestampException("Unable to pass timestamp {$occurredAt}");
|
||||
}
|
||||
}
|
||||
|
||||
// Rather than making lots of updates, just fill and save.
|
||||
$incident->save();
|
||||
|
||||
// Update the component.
|
||||
if ($component = Component::find($command->component_id)) {
|
||||
dispatch(new UpdateComponentCommand(
|
||||
@@ -138,7 +141,7 @@ class UpdateIncidentCommandHandler
|
||||
'visible' => $command->visible,
|
||||
'notify' => $command->notify,
|
||||
'stickied' => $command->stickied,
|
||||
'incident_date' => $command->incident_date,
|
||||
'occurredAt' => $command->occurredAt,
|
||||
'component' => Component::find($command->component_id) ?: null,
|
||||
'component_status' => $command->component_status,
|
||||
],
|
||||
|
||||
@@ -114,7 +114,7 @@ class SendIncidentEmailNotificationHandler
|
||||
'has_component' => ($event->incident->component) ? true : false,
|
||||
'component_name' => $component ? $component->name : null,
|
||||
'name' => $incident->name,
|
||||
'timestamp' => $incident->created_at_formatted,
|
||||
'timestamp' => $incident->occurred_at_formatted,
|
||||
'status' => $incident->human_status,
|
||||
'html_content' => $incident->formattedMessage,
|
||||
'text_content' => $incident->message,
|
||||
|
||||
@@ -33,8 +33,8 @@ class StickiedComposer
|
||||
*/
|
||||
public function compose(View $view)
|
||||
{
|
||||
$stickiedIncidents = Incident::stickied()->orderBy('scheduled_at', 'desc')->orderBy('created_at', 'desc')->get()->groupBy(function (Incident $incident) {
|
||||
return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->created_at)->toDateString();
|
||||
$stickiedIncidents = Incident::stickied()->orderBy('scheduled_at', 'desc')->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {
|
||||
return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->occurred_at)->toDateString();
|
||||
});
|
||||
$view->withStickiedIncidents($stickiedIncidents);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ use CachetHQ\Cachet\Models\MetricPoint;
|
||||
use CachetHQ\Cachet\Models\Subscriber;
|
||||
use CachetHQ\Cachet\Models\User;
|
||||
use CachetHQ\Cachet\Settings\Repository;
|
||||
use Carbon\Carbon;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -209,6 +210,7 @@ EINCIDENT;
|
||||
'scheduled_at' => null,
|
||||
'visible' => 1,
|
||||
'stickied' => false,
|
||||
'occurred_at' => Carbon::now(),
|
||||
],
|
||||
[
|
||||
'name' => 'This is an unresolved incident',
|
||||
@@ -218,6 +220,7 @@ EINCIDENT;
|
||||
'scheduled_at' => null,
|
||||
'visible' => 1,
|
||||
'stickied' => false,
|
||||
'occurred_at' => Carbon::now(),
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class IncidentController extends AbstractApiController
|
||||
Binput::get('component_status'),
|
||||
Binput::get('notify', true),
|
||||
Binput::get('stickied', false),
|
||||
Binput::get('created_at'),
|
||||
Binput::get('occurred_at'),
|
||||
Binput::get('template'),
|
||||
Binput::get('vars', [])
|
||||
));
|
||||
@@ -107,7 +107,7 @@ class IncidentController extends AbstractApiController
|
||||
Binput::get('component_status'),
|
||||
Binput::get('notify', true),
|
||||
Binput::get('stickied', false),
|
||||
Binput::get('created_at'),
|
||||
Binput::get('occurred_at'),
|
||||
Binput::get('template'),
|
||||
Binput::get('vars', [])
|
||||
));
|
||||
|
||||
@@ -127,11 +127,11 @@ class DashboardController extends Controller
|
||||
*/
|
||||
protected function getIncidents()
|
||||
{
|
||||
$allIncidents = Incident::notScheduled()->whereBetween('created_at', [
|
||||
$allIncidents = Incident::notScheduled()->whereBetween('occurred_at', [
|
||||
$this->startDate->copy()->subDays(30)->format('Y-m-d').' 00:00:00',
|
||||
$this->startDate->format('Y-m-d').' 23:59:59',
|
||||
])->orderBy('created_at', 'desc')->get()->groupBy(function (Incident $incident) {
|
||||
return (new Date($incident->created_at))
|
||||
])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {
|
||||
return (new Date($incident->occurred_at))
|
||||
->setTimezone($this->dateTimeZone)->toDateString();
|
||||
});
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ class IncidentController extends Controller
|
||||
Binput::get('component_status'),
|
||||
Binput::get('notify', false),
|
||||
Binput::get('stickied', false),
|
||||
Binput::get('created_at'),
|
||||
Binput::get('occurred_at'),
|
||||
null,
|
||||
[]
|
||||
));
|
||||
@@ -259,7 +259,7 @@ class IncidentController extends Controller
|
||||
Binput::get('component_status'),
|
||||
Binput::get('notify', true),
|
||||
Binput::get('stickied', false),
|
||||
Binput::get('created_at'),
|
||||
Binput::get('occurred_at'),
|
||||
null,
|
||||
[]
|
||||
));
|
||||
|
||||
@@ -18,6 +18,11 @@ use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* This is the feed controller.
|
||||
*
|
||||
* @author James Brooks <james@alt-three.com>
|
||||
*/
|
||||
class FeedController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -80,12 +85,12 @@ class FeedController extends Controller
|
||||
{
|
||||
if ($group->exists) {
|
||||
$group->components->map(function ($component) use ($isRss) {
|
||||
$component->incidents()->visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($isRss) {
|
||||
$component->incidents()->visible()->orderBy('occurred_at', 'desc')->get()->map(function ($incident) use ($isRss) {
|
||||
$this->feedAddItem($incident, $isRss);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
Incident::visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($isRss) {
|
||||
Incident::visible()->orderBy('occurred_at', 'desc')->get()->map(function ($incident) use ($isRss) {
|
||||
$this->feedAddItem($incident, $isRss);
|
||||
});
|
||||
}
|
||||
@@ -105,7 +110,7 @@ class FeedController extends Controller
|
||||
$incident->name,
|
||||
Config::get('setting.app_name'),
|
||||
Str::canonicalize(cachet_route('incident', [$incident->id])),
|
||||
$isRss ? $incident->created_at->toRssString() : $incident->created_at->toAtomString(),
|
||||
$isRss ? $incident->occurred_at->toRssString() : $incident->occurred_at->toAtomString(),
|
||||
$isRss ? $incident->message : Markdown::convertToHtml($incident->message)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -82,11 +82,11 @@ class StatusPageController extends AbstractApiController
|
||||
|
||||
$incidentVisibility = Auth::check() ? 0 : 1;
|
||||
|
||||
$allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisibility)->whereBetween('created_at', [
|
||||
$allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisibility)->whereBetween('occurred_at', [
|
||||
$startDate->copy()->subDays($daysToShow)->format('Y-m-d').' 00:00:00',
|
||||
$startDate->format('Y-m-d').' 23:59:59',
|
||||
])->orderBy('scheduled_at', 'desc')->orderBy('created_at', 'desc')->get()->load('updates')->groupBy(function (Incident $incident) {
|
||||
return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->created_at)->toDateString();
|
||||
])->orderBy('scheduled_at', 'desc')->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) {
|
||||
return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->occurred_at)->toDateString();
|
||||
});
|
||||
|
||||
// Add in days that have no incidents
|
||||
@@ -109,7 +109,7 @@ class StatusPageController extends AbstractApiController
|
||||
->withDaysToShow($daysToShow)
|
||||
->withAllIncidents($allIncidents)
|
||||
->withCanPageForward((bool) $today->gt($startDate))
|
||||
->withCanPageBackward(Incident::notScheduled()->where('created_at', '<', $startDate->format('Y-m-d'))->count() > 0)
|
||||
->withCanPageBackward(Incident::notScheduled()->where('occurred_at', '<', $startDate->format('Y-m-d'))->count() > 0)
|
||||
->withPreviousDate($startDate->copy()->subDays($daysToShow)->toDateString())
|
||||
->withNextDate($startDate->copy()->addDays($daysToShow)->toDateString());
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class System implements SystemContract
|
||||
];
|
||||
} elseif ($enabledScope->notStatus(1)->count() === 0) {
|
||||
// If all our components are ok, do we have any non-fixed incidents?
|
||||
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) {
|
||||
$incidents = Incident::notScheduled()->orderBy('occurred_at', 'desc')->get()->filter(function ($incident) {
|
||||
return $incident->status > 0;
|
||||
});
|
||||
$incidentCount = $incidents->count();
|
||||
|
||||
@@ -21,6 +21,13 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use McCool\LaravelAutoPresenter\HasPresenter;
|
||||
|
||||
/**
|
||||
* This is the incident model.
|
||||
*
|
||||
* @author James Brooks <james@alt-three.com>
|
||||
* @author Joseph Cohen <joseph@alt-three.com>
|
||||
* @author Graham Campbell <graham@alt-three.com>
|
||||
*/
|
||||
class Incident extends Model implements HasPresenter
|
||||
{
|
||||
use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait;
|
||||
@@ -71,6 +78,7 @@ class Incident extends Model implements HasPresenter
|
||||
'visible' => 'int',
|
||||
'stickied' => 'bool',
|
||||
'scheduled_at' => 'date',
|
||||
'occurred_at' => 'date',
|
||||
'deleted_at' => 'date',
|
||||
];
|
||||
|
||||
@@ -87,6 +95,7 @@ class Incident extends Model implements HasPresenter
|
||||
'stickied',
|
||||
'message',
|
||||
'scheduled_at',
|
||||
'occurred_at',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
];
|
||||
@@ -131,6 +140,7 @@ class Incident extends Model implements HasPresenter
|
||||
'visible',
|
||||
'stickied',
|
||||
'message',
|
||||
'occurred_at',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,16 +12,23 @@
|
||||
namespace CachetHQ\Cachet\Presenters;
|
||||
|
||||
use CachetHQ\Cachet\Dates\DateFactory;
|
||||
use CachetHQ\Cachet\Models\Incident;
|
||||
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
|
||||
use GrahamCampbell\Markdown\Facades\Markdown;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use McCool\LaravelAutoPresenter\BasePresenter;
|
||||
|
||||
class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
{
|
||||
use TimestampsTrait;
|
||||
|
||||
/**
|
||||
* The date factory instance.
|
||||
*
|
||||
* @var \CachetHQ\Cachet\Dates\DateFactory
|
||||
*/
|
||||
protected $dates;
|
||||
|
||||
/**
|
||||
* Inciden icon lookup.
|
||||
*
|
||||
@@ -35,6 +42,21 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
4 => 'icon ion-checkmark greens', // Fixed
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new presenter.
|
||||
*
|
||||
* @param \CachetHQ\Cachet\Dates\DateFactory $dates
|
||||
* @param \CachetHQ\Cachet\Models\Incident $resource
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(DateFactory $dates, Incident $resource)
|
||||
{
|
||||
$this->dates = $dates;
|
||||
|
||||
parent::__construct($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the message from Markdown into HTML.
|
||||
*
|
||||
@@ -55,6 +77,56 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
return strip_tags($this->formattedMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Present formatted occurred_at date time.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function occurred_at()
|
||||
{
|
||||
return $this->dates->make($this->wrappedObject->occurred_at)->toDateTimeString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Present diff for humans date time.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function occurred_at_diff()
|
||||
{
|
||||
return $this->dates->make($this->wrappedObject->occurred_at)->diffForHumans();
|
||||
}
|
||||
|
||||
/**
|
||||
* Present formatted date time.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function occurred_at_formatted()
|
||||
{
|
||||
return ucfirst($this->dates->make($this->wrappedObject->occurred_at)->format($this->incidentDateFormat()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the occurred_at time ready to be used by bootstrap-datetimepicker.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function occurred_at_datetimepicker()
|
||||
{
|
||||
return $this->dates->make($this->wrappedObject->occurred_at)->format('Y-m-d H:i');
|
||||
}
|
||||
|
||||
/**
|
||||
* Present formatted date time.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function occurred_at_iso()
|
||||
{
|
||||
return $this->dates->make($this->wrappedObject->occurred_at)->toISO8601String();
|
||||
}
|
||||
|
||||
/**
|
||||
* Present diff for humans date time.
|
||||
*
|
||||
@@ -62,7 +134,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function created_at_diff()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->created_at)->diffForHumans();
|
||||
return $this->dates->make($this->wrappedObject->created_at)->diffForHumans();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,17 +144,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function created_at_formatted()
|
||||
{
|
||||
return ucfirst(app(DateFactory::class)->make($this->wrappedObject->created_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the created_at time ready to be used by bootstrap-datetimepicker.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function created_at_datetimepicker()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->created_at)->format('d/m/Y H:i');
|
||||
return ucfirst($this->dates->make($this->wrappedObject->created_at)->format($this->incidentDateFormat()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +154,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function created_at_iso()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->created_at)->toISO8601String();
|
||||
return $this->dates->make($this->wrappedObject->created_at)->toISO8601String();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +164,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function scheduled_at()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->toDateTimeString();
|
||||
return $this->dates->make($this->wrappedObject->scheduled_at)->toDateTimeString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +174,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function scheduled_at_diff()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->diffForHumans();
|
||||
return $this->dates->make($this->wrappedObject->scheduled_at)->diffForHumans();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +184,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function scheduled_at_formatted()
|
||||
{
|
||||
return ucfirst(app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s')));
|
||||
return ucfirst($this->dates->make($this->wrappedObject->scheduled_at)->format($this->incidentDateFormat()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +194,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function scheduled_at_iso()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->toISO8601String();
|
||||
return $this->dates->make($this->wrappedObject->scheduled_at)->toISO8601String();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,7 +204,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
*/
|
||||
public function scheduled_at_datetimepicker()
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->format('d/m/Y H:i');
|
||||
return $this->dates->make($this->wrappedObject->scheduled_at)->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +218,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
return $this->scheduled_at_formatted;
|
||||
}
|
||||
|
||||
return $this->created_at_formatted;
|
||||
return $this->occurred_at_formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,7 +232,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
return $this->scheduled_at_iso;
|
||||
}
|
||||
|
||||
return $this->created_at_iso;
|
||||
return $this->occurred_at_iso;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +331,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
public function duration()
|
||||
{
|
||||
if ($update = $this->latest()) {
|
||||
return $this->wrappedObject->created_at->diffInSeconds($update->created_at);
|
||||
return $this->wrappedObject->created_at->diffInSeconds($update->occurred_at);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -291,6 +353,7 @@ class IncidentPresenter extends BasePresenter implements Arrayable
|
||||
'permalink' => $this->permalink(),
|
||||
'duration' => $this->duration(),
|
||||
'scheduled_at' => $this->scheduled_at(),
|
||||
'occurred_at' => $this->occurred_at(),
|
||||
'created_at' => $this->created_at(),
|
||||
'updated_at' => $this->updated_at(),
|
||||
]);
|
||||
|
||||
@@ -12,7 +12,15 @@
|
||||
namespace CachetHQ\Cachet\Presenters\Traits;
|
||||
|
||||
use CachetHQ\Cachet\Dates\DateFactory;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
/**
|
||||
* This is the timestamps trait.
|
||||
*
|
||||
* @author Joseph Cohen <joe@alt-three.com>
|
||||
* @author Graham Campbell <graham@alt-three.com>
|
||||
* @author James Brooks <james@alt-three.com>
|
||||
*/
|
||||
trait TimestampsTrait
|
||||
{
|
||||
/**
|
||||
@@ -44,4 +52,14 @@ trait TimestampsTrait
|
||||
{
|
||||
return app(DateFactory::class)->make($this->wrappedObject->deleted_at)->toDateTimeString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the incident date format setting, or fallback to a sane default.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function incidentDateFormat()
|
||||
{
|
||||
return Config::get('setting.incident_date_format', 'l jS F Y H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,3 +177,61 @@ if (!function_exists('cachet_redirect')) {
|
||||
return app('redirect')->to($url, $status, $headers);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('datetime_to_moment')) {
|
||||
/**
|
||||
* Convert PHP datetimes to moment.js formats.
|
||||
*
|
||||
* Thanks to http://stackoverflow.com/a/30192680/394013
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function datetime_to_moment($format)
|
||||
{
|
||||
$replacements = [
|
||||
'd' => 'DD',
|
||||
'D' => 'ddd',
|
||||
'j' => 'D',
|
||||
'l' => 'dddd',
|
||||
'N' => 'E',
|
||||
'S' => 'o',
|
||||
'w' => 'e',
|
||||
'z' => 'DDD',
|
||||
'W' => 'W',
|
||||
'F' => 'MMMM',
|
||||
'm' => 'MM',
|
||||
'M' => 'MMM',
|
||||
'n' => 'M',
|
||||
't' => '', // no equivalent
|
||||
'L' => '', // no equivalent
|
||||
'o' => 'YYYY',
|
||||
'Y' => 'YYYY',
|
||||
'y' => 'YY',
|
||||
'a' => 'a',
|
||||
'A' => 'A',
|
||||
'B' => '', // no equivalent
|
||||
'g' => 'h',
|
||||
'G' => 'H',
|
||||
'h' => 'hh',
|
||||
'H' => 'HH',
|
||||
'i' => 'mm',
|
||||
's' => 'ss',
|
||||
'u' => 'SSS',
|
||||
'e' => 'zz', // deprecated since version 1.6.0 of moment.js
|
||||
'I' => '', // no equivalent
|
||||
'O' => '', // no equivalent
|
||||
'P' => '', // no equivalent
|
||||
'T' => '', // no equivalent
|
||||
'Z' => '', // no equivalent
|
||||
'c' => '', // no equivalent
|
||||
'r' => '', // no equivalent
|
||||
'U' => 'X',
|
||||
];
|
||||
|
||||
$momentFormat = strtr($format, $replacements);
|
||||
|
||||
return $momentFormat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Cachet.
|
||||
*
|
||||
* (c) Alt Three Services Limited
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AlterTableIncidentsAddOccurredAtColumn extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('incidents', function (Blueprint $table) {
|
||||
$table->timestamp('occurred_at')->nullable()->after('scheduled_at');
|
||||
});
|
||||
|
||||
// We need a better way of handling data migrations...
|
||||
DB::update('UPDATE incidents SET `occurred_at` = `created_at`');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('incidents', function (Blueprint $table) {
|
||||
$table->dropColumn('occurred_at');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -161,6 +161,20 @@ $(function() {
|
||||
}
|
||||
});
|
||||
|
||||
$('input[rel=datepicker-custom]').datetimepicker({
|
||||
sideBySide: true,
|
||||
icons: {
|
||||
time: 'ion-clock',
|
||||
date: 'ion-android-calendar',
|
||||
up: 'ion-ios-arrow-up',
|
||||
down: 'ion-ios-arrow-down',
|
||||
previous: 'ion-ios-arrow-left',
|
||||
next: 'ion-ios-arrow-right',
|
||||
today: 'ion-android-home',
|
||||
clear: 'ion-trash-a',
|
||||
}
|
||||
});
|
||||
|
||||
// Sortable models.
|
||||
var orderableLists = document.querySelectorAll('[data-orderable-list]');
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ return [
|
||||
'message' => 'Message',
|
||||
'message-help' => 'You may also use Markdown.',
|
||||
'scheduled_at' => 'When to schedule the maintenance for?',
|
||||
'incident_time' => 'When did this incident occur?',
|
||||
'occurred_at' => 'When did this incident occur?',
|
||||
'notify_subscribers' => 'Notify subscribers?',
|
||||
'visibility' => 'Incident Visibility',
|
||||
'stick_status' => 'Stick Incident',
|
||||
|
||||
@@ -111,8 +111,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{ trans('forms.incidents.incident_time') }}</label> <small class="text-muted">{{ trans('forms.optional') }}</small>
|
||||
<input type="text" name="created_at" class="form-control" rel="datepicker-any" placeholder="{{ trans('forms.optional') }}">
|
||||
<label>{{ trans('forms.incidents.occurred_at') }}</label> <small class="text-muted">{{ trans('forms.optional') }}</small>
|
||||
<input type="text" name="occurred_at" class="form-control" rel="datepicker-custom" data-date-format="YYYY-MM-DD HH:mm" placeholder="{{ trans('forms.optional') }}">
|
||||
</div>
|
||||
<input type="hidden" name="notify" value="0">
|
||||
@if(subscribers_enabled())
|
||||
|
||||
@@ -84,13 +84,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{ trans('forms.incidents.incident_time') }}</label> <small class="text-muted">{{ trans('forms.optional') }}</small>
|
||||
<input type="text" name="created_at" class="form-control" rel="datepicker-any" value="{{ $incident->created_at_datetimepicker }}" placeholder="{{ trans('forms.optional') }}">
|
||||
<label>{{ trans('forms.incidents.occurred_at') }}</label> <small class="text-muted">{{ trans('forms.optional') }}</small>
|
||||
<input type="text" name="occurred_at" class="form-control" rel="datepicker-custom" data-date-format="YYYY-MM-DD HH:mm" value="{{ $incident->occurred_at_datetimepicker }}" placeholder="{{ trans('forms.optional') }}">
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<input type="hidden" name="id" value={{$incident->id}}>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="btn-group">
|
||||
<button type="submit" class="btn btn-success">{{ trans('forms.update') }}</button>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
<h1>{{ $incident->name }} <small>{{ formatted_date($incident->created_at) }}</small></h1>
|
||||
<h1>{{ $incident->name }} <small>{{ $incident->occurred_at_formatted }}</small></h1>
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class ReportIncidentCommandTest extends AbstractTestCase
|
||||
'component_status' => 1,
|
||||
'notify' => false,
|
||||
'stickied' => false,
|
||||
'incident_date' => null,
|
||||
'occurred_at' => null,
|
||||
'template' => null,
|
||||
'template_vars' => [],
|
||||
];
|
||||
@@ -51,7 +51,7 @@ class ReportIncidentCommandTest extends AbstractTestCase
|
||||
$params['component_status'],
|
||||
$params['notify'],
|
||||
$params['stickied'],
|
||||
$params['incident_date'],
|
||||
$params['occurred_at'],
|
||||
$params['template'],
|
||||
$params['template_vars']
|
||||
);
|
||||
|
||||
@@ -39,7 +39,7 @@ class UpdateIncidentCommandTest extends AbstractTestCase
|
||||
'component_status' => 1,
|
||||
'notify' => false,
|
||||
'stickied' => false,
|
||||
'incident_date' => null,
|
||||
'occurred_at' => null,
|
||||
'template' => null,
|
||||
'template_vars' => [],
|
||||
];
|
||||
@@ -54,7 +54,7 @@ class UpdateIncidentCommandTest extends AbstractTestCase
|
||||
$params['component_status'],
|
||||
$params['notify'],
|
||||
$params['stickied'],
|
||||
$params['incident_date'],
|
||||
$params['occurred_at'],
|
||||
$params['template'],
|
||||
$params['template_vars']
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user