authorize('view', $project); $query = $project->issues(); if ($status = $request->query('status')) { $query->where('status', $status); } else { $query->where('status', 'unresolved'); } if ($level = $request->query('level')) { $query->where('level', $level); } if ($search = $request->query('search')) { $query->where(function ($q) use ($search) { $q->where('title', 'like', "%{$search}%") ->orWhere('culprit', 'like', "%{$search}%"); }); } if ($environment = $request->query('environment')) { $query->whereHas('events', function ($q) use ($environment) { $q->where('environment', $environment); }); } $sortField = $request->query('sort', 'last_seen_at'); $sortDir = $request->query('dir', 'desc'); $allowedSorts = ['last_seen_at', 'first_seen_at', 'times_seen', 'level']; if (in_array($sortField, $allowedSorts)) { $query->orderBy($sortField, $sortDir === 'asc' ? 'asc' : 'desc'); } $issues = $query->cursorPaginate(25)->withQueryString(); // Get distinct environments from events for this project $environments = $project->events() ->whereNotNull('environment') ->distinct() ->pluck('environment') ->sort() ->values(); return view('issues.index', [ 'project' => $project, 'issues' => $issues, 'currentStatus' => $status ?: 'unresolved', 'currentLevel' => $level, 'currentEnvironment' => $environment, 'search' => $search, 'environments' => $environments, ]); } public function show(Request $request, Project $project, Issue $issue): View { $this->authorize('view', $project); abort_unless($issue->project_id === $project->id, 404); $environment = $request->query('environment'); $eventsQuery = $issue->events(); if ($environment) { $eventsQuery->where('environment', $environment); } $latestEvent = (clone $eventsQuery)->latest('timestamp')->first(); $events = $eventsQuery ->latest('timestamp') ->cursorPaginate(10) ->withQueryString(); // Get distinct environments for this issue $environments = $issue->events() ->whereNotNull('environment') ->distinct() ->pluck('environment') ->sort() ->values(); return view('issues.show', [ 'project' => $project, 'issue' => $issue, 'latestEvent' => $latestEvent, 'events' => $events, 'environments' => $environments, 'currentEnvironment' => $environment, ]); } public function updateStatus(Request $request, Project $project, Issue $issue): RedirectResponse { $this->authorize('view', $project); abort_unless($issue->project_id === $project->id, 404); $action = $request->input('action'); match ($action) { 'resolve' => $issue->resolve(), 'unresolve' => $issue->unresolve(), 'ignore' => $issue->ignore(), 'mute' => $issue->mute(), default => null, }; return back()->with('status', 'Issue ' . $action . 'd.'); } public function bulkAction(Request $request, Project $project): RedirectResponse { $this->authorize('view', $project); $validated = $request->validate([ 'action' => 'required|in:resolve,ignore,mute,delete', 'issues' => 'required|array', 'issues.*' => 'string', ]); $query = Issue::where('project_id', $project->id) ->whereIn('id', $validated['issues']); match ($validated['action']) { 'resolve' => $query->update(['status' => 'resolved', 'is_regression' => false]), 'ignore' => $query->update(['status' => 'ignored']), 'mute' => $query->update(['status' => 'muted']), 'delete' => $query->delete(), }; $count = count($validated['issues']); return back()->with('status', "{$count} issue(s) {$validated['action']}d."); } }