Skip to content

Commit

Permalink
Pagination 🥵🥵🥵
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseleite committed Oct 4, 2024
1 parent 5b828db commit 4a1eeac
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 44 deletions.
169 changes: 133 additions & 36 deletions resources/js/components/reporting/Report.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,34 +59,55 @@
<div v-if="loading" class="card loading">
<loading-graphic />
</div>
<data-list v-else ref="dataList" :columns="report.columns" :rows="sortablePages">
<div class="card overflow-hidden p-0" slot-scope="{ filteredRows: rows }">
<data-list-table :rows="sortablePages">
<template slot="cell-status" slot-scope="{ row: page }">
<status-icon :status="page.status_raw" class="inline-block w-5" />
{{ __('seo-pro::messages.rules.'+page.status_raw) }}
</template>
<template slot="cell-page" slot-scope="{ row: page }">
<a @click.prevent="selected = page.id" class="hover:text-black" v-text="page.url" />
</template>
<template slot="cell-actionable" slot-scope="{ row: page }">
<page-details v-if="selected === page.id" :item="page" @closed="selected = null" />
<a @click.prevent="selected = page.id" class="flex" style="gap: 0.25rem;">
<span
v-for="pill in actionablePageResults(page)"
:key="page.id+'_actionable_pill_'+pill"
class="inline-block text-xs bg-gray-300 hover:bg-gray-800 text-gray-800 shrink rounded-full px-2 py-0.5 text-center justify-center"
style="padding-top: 2px; padding-bottom: 2px;"
>{{ pill }}</span>
</a>
</template>
<td slot="actions" slot-scope="{ row: page }" class="text-right text-xs p-0 whitespace-no-wrap">
<a v-if="page.url" :href="page.url" target="_blank" class="font-normal text-gray-700 hover:text-blue" v-text="__('Visit')" />
<a v-if="page.edit_url" :href="page.edit_url" target="_blank" class="font-normal text-gray-700 hover:text-blue ml-4" v-text="__('Edit')" />
</td>
</data-list-table>
<data-list
v-else
ref="dataList"
:columns="report.columns"
:rows="sortablePages"
:sort="false"
:sort-column="sortColumn"
:sort-direction="sortDirection"
>
<div slot-scope="{ filteredRows: rows }">
<div class="card overflow-hidden p-0" >
<data-list-table :rows="sortablePages" @sorted="sorted">
<template slot="cell-status" slot-scope="{ row: page }">
<status-icon :status="page.status" class="inline-block w-5" />
{{ __('seo-pro::messages.rules.'+page.status) }}
</template>
<template slot="cell-page" slot-scope="{ row: page }">
<a @click.prevent="selectedId = page.id" class="hover:text-black" v-text="page.url" />
</template>
<template slot="cell-actionable" slot-scope="{ row: page }">
<page-details v-if="selectedId === page.id" :item="page" @closed="selected = null" />
<a @click.prevent="selectedId = page.id" class="flex" style="gap: 0.25rem;">
<span
v-for="pill in actionablePageResults(page)"
:key="page.id+'_actionable_pill_'+pill"
class="inline-block text-xs bg-gray-300 hover:bg-gray-800 text-gray-800 shrink rounded-full px-2 py-0.5 text-center justify-center"
style="padding-top: 2px; padding-bottom: 2px;"
>{{ pill }}</span>
</a>
</template>
<td slot="actions" slot-scope="{ row: page }" class="text-right text-xs p-0 whitespace-no-wrap">
<a v-if="page.url" :href="page.url" target="_blank" class="font-normal text-gray-700 hover:text-blue" v-text="__('Visit')" />
<a v-if="page.edit_url" :href="page.edit_url" target="_blank" class="font-normal text-gray-700 hover:text-blue ml-4" v-text="__('Edit')" />
</td>
</data-list-table>
</div>

<data-list-pagination
class="mt-6"
:resource-meta="paginationMeta"
:per-page="perPage"
:scroll-to-top="false"
:show-totals="true"
@per-page-changed="selectPaginationPerPage"
@page-selected="selectPaginationPage"
/>
</div>
</data-list>

</div>

</div>
Expand All @@ -108,13 +129,22 @@ export default {
StatusIcon,
},
props: ['initialReport'],
props: [
'initialReport',
'initialPage',
'initialPerPage',
],
data() {
return {
loading: true,
report: this.initialReport,
selected: null
selectedId: null,
sortColumn: 'status',
sortDirection: 'asc',
page: this.initialPage,
perPage: this.initialPerPage,
paginationMeta: {},
}
},
Expand All @@ -136,17 +166,43 @@ export default {
},
sortablePages() {
return this.report.pages.map(page => {
page.status_raw = page.status;
if (this.loading) {
return [];
}
if (page.status === 'fail') page.status = '1fail';
if (page.status === 'warning') page.status = '2warning';
if (page.status === 'pass') page.status = '3pass';
return this.report.pages.data;
},
return page;
});
parameters() {
return {
sortColumn: this.sortColumn,
sortDirection: this.sortDirection,
page: this.page,
perPage: this.perPage,
};
},
},
watch: {
parameters: {
deep: true,
handler(after, before) {
if (JSON.stringify(before) === JSON.stringify(after)) return;
this.load();
this.pushState();
},
},
},
mounted() {
window.history.replaceState({ parameters: this.parameters }, '');
window.addEventListener('popstate', this.popState);
},
beforeDestroy() {
window.removeEventListener('popstate', this.popState);
},
created() {
Expand All @@ -156,13 +212,20 @@ export default {
methods: {
load() {
Statamic.$request.get(cp_url(`seo-pro/reports/${this.id}`)).then(response => {
this.$axios.get(cp_url(`seo-pro/reports/${this.id}`), { params: this.parameters }).then(response => {
if (response.data.status === 'pending' || response.data.status === 'generating') {
setTimeout(() => this.load(), 1000);
return;
}
this.report = response.data;
this.sortColumn = response.data.sortColumn;
this.sortDirection = response.data.sortDirection;
this.page = response.data.pages.current_page;
this.perPage = response.data.pages.per_page;
this.paginationMeta = response.data.pages;
this.loading = false;
});
},
Expand All @@ -175,6 +238,40 @@ export default {
.value();
},
selectPaginationPage(page) {
this.page = parseInt(page);
},
selectPaginationPerPage(perPage) {
this.perPage = parseInt(perPage);
},
sorted(column, direction) {
this.sortColumn = column;
this.sortDirection = direction;
},
popState(event) {
if (! event.state) {
return;
}
this.popping = true;
this.page = event.state.parameters.page;
this.perPage = event.state.parameters.perPage;
this.$nextTick(() => {
this.popping = false;
});
},
pushState() {
if (this.popping) {
return;
}
const parameters = this.parameters;
const searchParams = new URLSearchParams(parameters);
window.history.pushState({ parameters }, '', '?' + searchParams.toString());
},
}
}
Expand Down
6 changes: 5 additions & 1 deletion resources/views/reports/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
'title' => __('seo-pro::messages.reports'),
])

<seo-pro-report :initial-report="{{ $report->toJson() }}"></seo-pro-report>
<seo-pro-report
:initial-report="{{ $report->toJson() }}"
:initial-page="{{ request()->input('page', 1) }}"
:initial-per-page="25"
></seo-pro-report>

@include('statamic::partials.docs-callout', [
'topic' => 'SEO Pro',
Expand Down
56 changes: 55 additions & 1 deletion src/Http/Controllers/ReportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Statamic\SeoPro\Http\Controllers;

use Illuminate\Http\Request;
use Statamic\CP\Column;
use Statamic\Extensions\Pagination\LengthAwarePaginator;
use Statamic\Facades\User;
use Statamic\Http\Controllers\CP\CpController;
use Statamic\SeoPro\Reporting\Report;
Expand Down Expand Up @@ -36,7 +38,7 @@ public function show(Request $request, $id)
$report = Report::find($id);

if ($request->ajax()) {
return $report->data();
return $this->reportData($report);
}

return view('seo-pro::reports.show', ['report' => $report]);
Expand All @@ -48,4 +50,56 @@ public function destroy($id)

return Report::find($id)->delete();
}

public function reportData($report)
{
$data = $report->data();

$data['columns'] = [
Column::make('status')->label(__('Status')),
Column::make('url')->label(__('URL')),
Column::make('actionable')->label(__('Actionable'))->sortable(false),
];

$data['sortColumn'] = request()->input('sortColumn', 'status');
$data['sortDirection'] = request()->input('sortDirection', 'asc');

$pages = $data['pages']->sortBy(
callback: fn ($value) => $this->sortablePageValue($value, $data['sortColumn']),
descending: $data['sortDirection'] === 'desc',
)->values();

ray($pages);

$currentPage = request()->input('page', 1);
$perPage = request()->input('perPage', config('statamic.cp.pagination_size')); // TODO: default to config

$data['pages'] = new LengthAwarePaginator(
$pages->forPage($currentPage, $perPage)->values(),
$pages->count(),
$perPage,
$currentPage,
);

return $data;
}

private function sortablePageValue($value, $column)
{
$value = $value[$column];

if ($column !== 'status') {
return $value;
}

if ($value === 'fail') {
return '1fail';
} elseif ($value === 'warning') {
return '2warning';
} elseif ($value === 'pass') {
return '3pass';
}

return $value;
}
}
16 changes: 10 additions & 6 deletions src/Reporting/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Statamic\CP\Column;
use Statamic\Facades\Entry;
use Statamic\Facades\File;
use Statamic\Facades\Folder;
Expand Down Expand Up @@ -227,11 +226,6 @@ public function toArray()

if ($this->isGenerated() && $this->pages() && $this->pages()->isNotEmpty()) {
$array['pages'] = $this->pagesToArray();
$array['columns'] = [
Column::make('status')->label(__('Status')),
Column::make('page')->label(__('URL')),
Column::make('actionable')->label(__('Actionable'))->sortable(false),
];

Cache::put($this->cacheKey(static::TO_ARRAY_CACHE_KEY_SUFFIX), $array);
}
Expand Down Expand Up @@ -271,6 +265,16 @@ protected function pagesToArray()
->map(fn ($page) => $this->pageToArray($page));
}

// protected function paginationMeta($pages)
// {
// return new LengthAwarePaginator(
// $pages,
// $pages->count(),
// 25,
// 1,
// );
// }

protected function pageToArray($page)
{
return [
Expand Down

0 comments on commit 4a1eeac

Please sign in to comment.