feat: Site audit and Crawls screens with their MCP tools

- golem15.seo.issues (Site audit): current issues errors first, labels,
  summary and fix columns, filters, P7 issue_details, Check this address
  again, Ignore, Stop ignoring, bulk Ignore, ignored rows badged
- golem15.seo.crawls (Crawls): newest first, P6 crawl_summary with one
  status callout, staging and rendered-comparison lines, stats strip and
  per-kind table; Cancel; a running crawl refuses delete
- Start crawl toolbar action on both, refusing already_running and
  no_site_url; navigation Site audit (gauge) and Crawls (globe)
- routes and MCP tools start/cancel/list/get/delete crawls, list_issues
  with filters (open by default), recheck_url, ignore and unignore
- AdminOperations maps both controllers; toolbar actions get their own
  operation kind
- TestCrawlAdmin, TestCrawlTools, TestIssueKindLabels
This commit is contained in:
Jakub Zych
2026-11-04 15:34:22 +01:00
parent edc03cae4b
commit c4f0b4f94c
32 changed files with 2778 additions and 20 deletions

View File

@@ -0,0 +1,31 @@
{{- with .Data -}}
{{- if .HasCallout -}}
<div class="summer-callout{{ if .Tone }} summer-callout--{{ .Tone }}{{ end }}" role="status">
{{- if .Title -}}<p class="summer-callout__title">{{ .Title }}</p>{{- end -}}
<p class="summer-callout__text">{{ .Text }}</p>
</div>
{{- end -}}
{{- if .Staging -}}<p>{{ .Staging }}</p>{{- end -}}
{{- if .Render -}}<p>{{ .Render }}</p>{{- end -}}
{{- if .Stats -}}
<dl class="summer-stats">
{{- range .Stats -}}
<div class="summer-stat"><dt class="summer-stat__label">{{ .Label }}</dt><dd class="summer-stat__value">{{ .Value }}</dd></div>
{{- end -}}
</dl>
{{- end -}}
{{- if .Kinds -}}
<div class="summer-table-wrap">
<table class="summer-table">
<thead><tr><th>{{ trans "golem15.seo::lang.crawls.kinds_problem" }}</th><th>{{ trans "golem15.seo::lang.crawls.kinds_severity" }}</th><th class="summer-table__num">{{ trans "golem15.seo::lang.crawls.kinds_count" }}</th></tr></thead>
<tbody>
{{- range .Kinds -}}
<tr><td>{{ .Label }}</td><td>{{ .Severity }}</td><td class="summer-table__num"><a href="{{ .Link }}">{{ .Count }}</a></td></tr>
{{- end -}}
</tbody>
</table>
</div>
{{- else if .NoIssues -}}
<p>{{ trans "golem15.seo::lang.crawls.no_issues" }}</p>
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,11 @@
# Crawls filters (UI-SPEC C24): status and start date.
scopes:
status:
label: golem15.seo::lang.crawls.status
modelClass: Golem15\SEO\Models\Crawl
nameFrom: status
scope: FilterCrawlStatus
started_at:
label: golem15.seo::lang.crawls.started_at
type: daterange
column: started_at

View File

@@ -0,0 +1,14 @@
# Crawl preview (UI-SPEC C24): read-only, P6 above the fields and Cancel
# while the crawl is queued or running.
name: golem15.seo::lang.crawls.name
form: ~/plugins/golem15/seo/models/crawl/fields.yaml
modelClass: Golem15\SEO\Models\Crawl
defaultRedirect: golem15/seo/crawls
preview:
headerPartial: crawl_summary
recordActions: [cancel]
messages:
preview: golem15.seo::lang.crawls.preview_title

View File

@@ -0,0 +1,22 @@
# Crawls (UI-SPEC C24): newest first; the toolbar starts a crawl and
# deletes the selected ones (a running crawl refuses).
list: ~/plugins/golem15/seo/models/crawl/columns.yaml
modelClass: Golem15\SEO\Models\Crawl
title: golem15.seo::lang.crawls.list_title
recordUrl: golem15/seo/crawls/preview/:id
noRecordsMessage: golem15.seo::lang.crawls.list_empty
recordsPerPage: 20
showCheckboxes: true
showSetup: true
filter: config_filter.yaml
defaultSort:
column: started_at
direction: desc
toolbar:
buttons: [start_crawl, delete]
messages:
empty: golem15.seo::lang.crawls.list_empty
deleteConfirm: golem15.seo::lang.crawls.delete_selected_confirm