Skip to content

Commit 39116d0

Browse files
committed
feat: add title and description for feature flags
1 parent c42a5c5 commit 39116d0

4 files changed

Lines changed: 50 additions & 27 deletions

File tree

config/toggle.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,23 @@
7575

7676
'flags' => [
7777
'mcp' => env('TOGGLE_MCP', false),
78+
],
79+
80+
/*
81+
|--------------------------------------------------------------------------
82+
| Lab Experiments
83+
|--------------------------------------------------------------------------
84+
|
85+
| Display metadata for experimental feature toggles shown on the Lab page.
86+
| Flag values must remain booleans in "flags" above for the toggle package.
87+
|
88+
*/
7889

90+
'experiments' => [
91+
'mcp' => [
92+
'title' => 'MCP Server',
93+
'description' => 'Expose a Model Context Protocol server so AI tools can list, create, update, and render your recipes. Requires an MCP API token.',
94+
],
7995
],
8096

8197
/*

resources/views/pages/settings/lab.blade.php

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@
66
new class extends Component
77
{
88
/**
9-
* @return array<string, bool>
9+
* @return array{toggles: Illuminate\Support\Collection<int, array{name: string, title: string, description: string|null, active: bool}>|null}
1010
*/
1111
public function with(): array
1212
{
1313
return [
14-
'toggles' => auth()->user()->id === 1 ? Toggle::all() : null,
14+
'toggles' => auth()->user()->id === 1
15+
? collect(Toggle::all())->map(function (bool $active, string $name): array {
16+
$experiment = config("toggle.experiments.{$name}", []);
17+
18+
return [
19+
'name' => $name,
20+
'title' => $experiment['title'] ?? $name,
21+
'description' => $experiment['description'] ?? null,
22+
'active' => $active,
23+
];
24+
})->values()
25+
: null,
1526
];
1627
}
1728
@@ -52,12 +63,15 @@ public function toggle(string $name, bool $active): void
5263
<flux:separator />
5364

5465
<div class="space-y-4">
55-
@forelse ($toggles as $name => $active)
56-
<flux:field variant="inline">
57-
<flux:label class="flex-1">{{ $name }}</flux:label>
66+
@forelse ($toggles as $toggle)
67+
<flux:field variant="inline" wire:key="{{ $toggle['name'] }}">
68+
<flux:label class="flex-1">{{ $toggle['title'] }}</flux:label>
69+
@if ($toggle['description'])
70+
<flux:description>{{ $toggle['description'] }}</flux:description>
71+
@endif
5872
<flux:switch
59-
:checked="$active"
60-
wire:change="toggle('{{ $name }}', $event.target.checked)"
73+
:checked="$toggle['active']"
74+
wire:change="toggle('{{ $toggle['name'] }}', $event.target.checked)"
6175
/>
6276
</flux:field>
6377
@empty

resources/views/pages/settings/layout.blade.php

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,18 @@
11
<div class="flex items-start max-md:flex-col">
22
<div class="me-10 w-full pb-4 md:w-[220px]">
33
<flux:navlist aria-label="{{ __('Settings') }}">
4-
<flux:navlist.item
5-
:href="route('settings.preferences')"
6-
wire:navigate
7-
>
4+
<flux:navlist.item :href="route('settings.preferences')" wire:navigate>
85
{{ __('Preferences') }}</flux:navlist.item>
96
<flux:navlist.item :href="route('appearance.edit')" wire:navigate>{{ __('Appearance') }}</flux:navlist.item>
107
<flux:navlist.item :href="route('profile.edit')" wire:navigate>{{ __('Profile') }}</flux:navlist.item>
118
@if (auth()?->user()?->oidc_sub === null)
12-
<flux:navlist.item
13-
:href="route('security.edit')"
14-
wire:navigate
15-
>
9+
<flux:navlist.item :href="route('security.edit')" wire:navigate>
1610
{{ __('Password & 2FA') }}</flux:navlist.item>
1711
@endif
18-
<flux:navlist.item
19-
:href="route('settings.api-tokens')"
20-
wire:navigate
21-
>
12+
<flux:navlist.item :href="route('settings.api-tokens')" wire:navigate>
2213
{{ __('API Tokens') }}</flux:navlist.item>
2314
@if (config('app.version'))
24-
<flux:navlist.item
25-
:href="route('settings.update')"
26-
wire:navigate
27-
>
15+
<flux:navlist.item :href="route('settings.update')" wire:navigate>
2816
{{ __('Updates') }}</flux:navlist.item>
2917
@endif
3018

@@ -33,10 +21,7 @@
3321
</flux:navlist.group>
3422

3523
<flux:navlist.group :heading="__('Support')" class="mt-2">
36-
<flux:navlist.item
37-
:href="route('settings.support')"
38-
wire:navigate
39-
>
24+
<flux:navlist.item :href="route('settings.support')" wire:navigate>
4025
{{ __('Support & Referral') }}</flux:navlist.item>
4126
</flux:navlist.group>
4227
</flux:navlist>

tests/Feature/Settings/LabTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,11 @@
3737

3838
expect(Toggle::active('test-feature'))->toBeFalse();
3939
});
40+
41+
test('lab settings page shows mcp title and description from config', function (): void {
42+
Toggle::enable('mcp');
43+
44+
Livewire::test('pages::settings.lab')
45+
->assertSee('MCP')
46+
->assertSee('Expose a Model Context Protocol server so AI tools can list, create, update, and render your recipes. Requires an MCP API token.');
47+
});

0 commit comments

Comments
 (0)