feat: overhaul project workspace navigation
linter / quality (pull_request) Successful in 1m28s
tests / ci (8.4) (pull_request) Successful in 1m47s

This commit is contained in:
2026-07-18 17:52:25 +02:00
parent a46695c2eb
commit ff796aa10a
45 changed files with 1790 additions and 995 deletions
@@ -55,37 +55,41 @@ class ProjectNotificationSettingsControllerTest extends TestCase
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->get(route('projects.settings.notifications', $project))
->get(route('projects.settings.index', [
'project' => $project,
'section' => 'notifications',
]))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('projects/settings/Notifications')
->component('projects/Settings')
->where('activeSection', 'notifications')
->where('project.id', $project->id)
->where('notificationActions.0.name', 'Discord alerts')
->where('notificationActions.0.channel', NotificationChannel::Discord->value)
->where('notificationActions.0.channel_configuration.allowed_mentions.0', 'users')
->where('notificationActions.0.channel_configuration.allowed_mentions.1', 'roles')
->where('notificationActions.0.event_type', NotificationEventType::TicketStatusChanged->value)
->where('notificationActions.0.enabled', true)
->where('notificationActions.0.has_delivery_url', true)
->where('notificationActions.0.filters.0.attribute', 'status.to.label')
->where('notificationActions.0.filters.0.operator', 'equals')
->where('notificationActions.0.filters.0.value', 'Doing')
->where('notificationActions.0.updated_at', $notificationAction->updated_at?->toISOString())
->where('channelOptions.0.value', NotificationChannel::Discord->value)
->where('eventTypeOptions.0.value', NotificationEventType::TicketStatusChanged->value)
->where('eventTypeOptions.1.value', NotificationEventType::TicketCreate->value)
->where('eventTypeOptions.2.value', NotificationEventType::TicketAssigneeChanged->value)
->where('discordAllowedMentionOptions.0.value', 'everyone')
->where('discordAllowedMentionOptions.2.value', 'users')
->where('filterAttributeOptions.0.value', 'project.id')
->where('filterOperatorOptions.0.value', 'equals')
->where('templateVariables.0.value', '$url')
->where('templateVariables.6.value', '$actor_name')
->where('templateVariables.7.value', '$assignee_from')
->where('templateVariables.8.value', '$assignee_to')
->where('templateState.templateName', 'Alert Template')
->where('templateState.inheritedAreas.0.value', DuplicateProjectConfiguration::COPY_NOTIFICATION_ACTIONS)
->missing('notificationActions.0.delivery_url'),
->where('sectionData.notificationActions.0.name', 'Discord alerts')
->where('sectionData.notificationActions.0.channel', NotificationChannel::Discord->value)
->where('sectionData.notificationActions.0.channel_configuration.allowed_mentions.0', 'users')
->where('sectionData.notificationActions.0.channel_configuration.allowed_mentions.1', 'roles')
->where('sectionData.notificationActions.0.event_type', NotificationEventType::TicketStatusChanged->value)
->where('sectionData.notificationActions.0.enabled', true)
->where('sectionData.notificationActions.0.has_delivery_url', true)
->where('sectionData.notificationActions.0.filters.0.attribute', 'status.to.label')
->where('sectionData.notificationActions.0.filters.0.operator', 'equals')
->where('sectionData.notificationActions.0.filters.0.value', 'Doing')
->where('sectionData.notificationActions.0.updated_at', $notificationAction->updated_at?->toISOString())
->where('sectionData.channelOptions.0.value', NotificationChannel::Discord->value)
->where('sectionData.eventTypeOptions.0.value', NotificationEventType::TicketStatusChanged->value)
->where('sectionData.eventTypeOptions.1.value', NotificationEventType::TicketCreate->value)
->where('sectionData.eventTypeOptions.2.value', NotificationEventType::TicketAssigneeChanged->value)
->where('sectionData.discordAllowedMentionOptions.0.value', 'everyone')
->where('sectionData.discordAllowedMentionOptions.2.value', 'users')
->where('sectionData.filterAttributeOptions.0.value', 'project.id')
->where('sectionData.filterOperatorOptions.0.value', 'equals')
->where('sectionData.templateVariables.0.value', '$url')
->where('sectionData.templateVariables.6.value', '$actor_name')
->where('sectionData.templateVariables.7.value', '$assignee_from')
->where('sectionData.templateVariables.8.value', '$assignee_to')
->where('sectionData.templateState.templateName', 'Alert Template')
->where('sectionData.templateState.inheritedAreas.0.value', DuplicateProjectConfiguration::COPY_NOTIFICATION_ACTIONS)
->missing('sectionData.notificationActions.0.delivery_url'),
);
}
@@ -133,7 +137,7 @@ class ProjectNotificationSettingsControllerTest extends TestCase
], JSON_THROW_ON_ERROR),
'message_template' => '$ticket_key moved from $status_from to $status_to by $actor_name: $url',
])
->assertRedirect(route('projects.settings.notifications', $project))
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'notifications']))
->assertSessionHas('status', 'Discord alerts notification was added.');
$notificationAction = NotificationAction::query()->firstOrFail();
@@ -195,7 +199,7 @@ class ProjectNotificationSettingsControllerTest extends TestCase
], JSON_THROW_ON_ERROR),
'message_template' => '$ticket_key moved to $status_to: $url',
])
->assertRedirect(route('projects.settings.notifications', $project))
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'notifications']))
->assertSessionHas('status', 'Ops escalation alerts notification was updated.');
$notificationAction->refresh();
@@ -250,7 +254,7 @@ class ProjectNotificationSettingsControllerTest extends TestCase
'delivery_url' => '',
'message_template' => '',
])
->assertRedirect(route('projects.settings.notifications', $project));
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'notifications']));
$this->assertFalse($notificationAction->fresh()->enabled);
@@ -263,7 +267,7 @@ class ProjectNotificationSettingsControllerTest extends TestCase
'delivery_url' => '',
'message_template' => '',
])
->assertRedirect(route('projects.settings.notifications', $project));
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'notifications']));
$this->assertTrue($notificationAction->fresh()->enabled);
}
@@ -293,7 +297,7 @@ class ProjectNotificationSettingsControllerTest extends TestCase
'delivery_url' => 'https://hooks.example.test/kanbangit/replaced-secret',
'message_template' => '',
])
->assertRedirect(route('projects.settings.notifications', $project));
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'notifications']));
$this->assertSame(
'https://hooks.example.test/kanbangit/replaced-secret',
@@ -318,7 +322,7 @@ class ProjectNotificationSettingsControllerTest extends TestCase
$this->actingAs($user)
->delete(route('projects.settings.notifications.destroy', [$project, $notificationAction]))
->assertRedirect(route('projects.settings.notifications', $project))
->assertRedirect(route('projects.settings.index', ['project' => $project, 'section' => 'notifications']))
->assertSessionHas('status', 'Webhook alerts notification was deleted.');
$this->assertModelMissing($notificationAction);
@@ -422,12 +426,15 @@ class ProjectNotificationSettingsControllerTest extends TestCase
$this->syncProjectPermissions($project, $user, ['edit']);
$this->actingAs($user)
->get(route('projects.settings.notifications', $project))
->get(route('projects.settings.index', [
'project' => $project,
'section' => 'notifications',
]))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('projects/settings/Notifications')
->where('notificationActions.0.has_delivery_url', true)
->missing('notificationActions.0.delivery_url'),
->component('projects/Settings')
->where('sectionData.notificationActions.0.has_delivery_url', true)
->missing('sectionData.notificationActions.0.delivery_url'),
);
}
}