Skip to content

Commit a9efba4

Browse files
jbrooksukclaude
andauthored
Add metadata support for incidents, schedules and components (#385)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 890b57d commit a9efba4

78 files changed

Lines changed: 1251 additions & 38 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

database/factories/ComponentFactory.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,8 @@ public function disabled(): self
6666
*/
6767
public function withMeta(): self
6868
{
69-
return $this->state([
70-
'meta' => [
71-
'foo' => 'bar',
72-
],
73-
]);
69+
return $this->afterCreating(function (Component $component) {
70+
$component->meta()->create(['key' => 'foo', 'value' => 'bar']);
71+
});
7472
}
7573
}

database/factories/ComponentGroupFactory.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,14 @@ public function orderedBy(ResourceOrderColumnEnum $column, ?ResourceOrderDirecti
4141
'order_direction' => $column === ResourceOrderColumnEnum::Manual ? null : $direction,
4242
]);
4343
}
44+
45+
/**
46+
* Provide the component group with additional meta.
47+
*/
48+
public function withMeta(): self
49+
{
50+
return $this->afterCreating(function (ComponentGroup $componentGroup) {
51+
$componentGroup->meta()->create(['key' => 'foo', 'value' => 'bar']);
52+
});
53+
}
4454
}

database/factories/IncidentFactory.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,14 @@ public function definition(): array
2727
'message' => fake()->paragraph,
2828
];
2929
}
30+
31+
/**
32+
* Provide the incident with additional meta.
33+
*/
34+
public function withMeta(): self
35+
{
36+
return $this->afterCreating(function (Incident $incident) {
37+
$incident->meta()->create(['key' => 'foo', 'value' => 'bar']);
38+
});
39+
}
3040
}

database/factories/ScheduleFactory.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,14 @@ public function inThePast(): self
5757
'completed_at' => now()->subDays(30),
5858
]);
5959
}
60+
61+
/**
62+
* Provide the schedule with additional meta.
63+
*/
64+
public function withMeta(): self
65+
{
66+
return $this->afterCreating(function (Schedule $schedule) {
67+
$schedule->meta()->create(['key' => 'foo', 'value' => 'bar']);
68+
});
69+
}
6070
}

database/factories/SubscriberFactory.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,14 @@ public function verified(): self
2525
'email_verified_at' => now(),
2626
]);
2727
}
28+
29+
/**
30+
* Provide the subscriber with additional meta.
31+
*/
32+
public function withMeta(): self
33+
{
34+
return $this->afterCreating(function (Subscriber $subscriber) {
35+
$subscriber->meta()->create(['key' => 'foo', 'value' => 'bar']);
36+
});
37+
}
2838
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\DB;
6+
use Illuminate\Support\Facades\Log;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
/**
12+
* The morph aliases written by the metadata feature this migration enables.
13+
*
14+
* Hardcoded rather than read from the runtime morph map so this migration
15+
* stays stable as application code evolves.
16+
*
17+
* @var list<string>
18+
*/
19+
private array $morphAliases = [
20+
'component',
21+
'component_group',
22+
'incident',
23+
'schedule',
24+
'subscriber',
25+
];
26+
27+
/**
28+
* Run the migrations.
29+
*/
30+
public function up(): void
31+
{
32+
Schema::table('meta', function (Blueprint $table) {
33+
$table->text('value')->nullable()->change();
34+
});
35+
36+
DB::table('components')
37+
->whereNotNull('meta')
38+
->orderBy('id')
39+
->each(function (object $component) {
40+
$meta = json_decode($component->meta, true);
41+
42+
if (! is_array($meta)) {
43+
Log::warning('Skipping component meta that is not a key/value object during migration.', [
44+
'component_id' => $component->id,
45+
'meta' => $component->meta,
46+
]);
47+
48+
return;
49+
}
50+
51+
$rows = collect($meta)->map(fn (mixed $value, int|string $key) => [
52+
'key' => (string) $key,
53+
'value' => json_encode($value),
54+
'meta_id' => $component->id,
55+
'meta_type' => 'component',
56+
'created_at' => now(),
57+
'updated_at' => now(),
58+
])->values()->all();
59+
60+
DB::table('meta')->insert($rows);
61+
});
62+
63+
Schema::table('components', function (Blueprint $table) {
64+
$table->dropColumn('meta');
65+
});
66+
}
67+
68+
/**
69+
* Reverse the migrations.
70+
*/
71+
public function down(): void
72+
{
73+
Schema::table('components', function (Blueprint $table) {
74+
$table->longText('meta')->nullable()->default(null)->after('enabled');
75+
});
76+
77+
DB::table('meta')
78+
->where('meta_type', 'component')
79+
->orderBy('meta_id')
80+
->get()
81+
->groupBy('meta_id')
82+
->each(function ($rows, $componentId) {
83+
$meta = $rows->mapWithKeys(fn (object $row) => [
84+
$row->key => json_decode($row->value, true),
85+
])->all();
86+
87+
DB::table('components')
88+
->where('id', $componentId)
89+
->update(['meta' => json_encode($meta)]);
90+
});
91+
92+
DB::table('meta')->whereIn('meta_type', $this->morphAliases)->delete();
93+
94+
Schema::table('meta', function (Blueprint $table) {
95+
$table->string('value')->nullable(false)->change();
96+
});
97+
}
98+
};

database/seeders/DatabaseSeeder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public function run(): void
3939
DB::table('component_checks')->truncate();
4040
DB::table('component_groups')->truncate();
4141
DB::table('schedules')->truncate();
42+
DB::table('meta')->truncate();
4243
DB::table('metrics')->truncate();
4344
DB::table('metric_points')->truncate();
4445
DB::table('updates')->truncate();

resources/lang/en/component_group.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
'collapsed_label' => 'Collapsed',
2929
'order_column_label' => 'Component group order',
3030
'order_direction' => 'Order direction',
31+
'meta_label' => 'Meta',
3132
],
3233
];

resources/lang/en/incident.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
'notify_subscribers_label' => 'Notify subscribers of this incident.',
5858
'pin_incident_label' => 'Pin the incident to the top of the status page.',
5959
'guid_label' => 'Incident UUID',
60+
'meta_label' => 'Meta',
6061
'add_component' => [
6162
'action_label' => 'Add component',
6263
'header' => 'Components',

resources/lang/en/schedule.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
'completed_at_helper' => 'When the maintenance window is expected to end.',
3131
'notify_subscribers_label' => 'Notify subscribers of this maintenance.',
3232
'notifications_helper' => 'Email subscribers about this scheduled maintenance and its updates.',
33+
'meta_label' => 'Meta',
3334
'add_component' => [
3435
'action_label' => 'Add component',
3536
'header' => 'Affected components',

0 commit comments

Comments
 (0)