Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lang/en/messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
'form_configure_store_instructions' => 'Disable to stop storing submissions. Events and email notifications will still be sent.',
'form_configure_title_instructions' => 'Use a call to action, such as \'Contact Us\'.',
'form_create_description' => 'Get started by creating your first form.',
'form_export_filtered_description' => 'Exports submissions with current filters and visible columns.',
'form_export_filtered_description' => 'Exports submissions with current filters.',
'getting_started_widget_collections' => 'Collections hold the different content types that make up your site, helping you stay organized.',
'getting_started_widget_docs' => 'Discover everything Statamic can do, and learn how to use its powerful features the right way.',
'getting_started_widget_header' => 'Getting Started with Statamic',
Expand Down
18 changes: 9 additions & 9 deletions resources/js/pages/forms/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ const listingParameters = ref({});

const hasFilteredScope = computed(() => {
const params = listingParameters.value;
const hasSortOverride = (params.sort && params.sort !== 'datestamp') || (params.order && params.order !== 'desc');
return !!(params.search || params.filters || hasSortOverride);
return !!(params.search || params.filters);
});

function openExportModal() {
Expand All @@ -40,18 +39,19 @@ function exportSubmissions() {

let url = exporter.downloadUrl;

const params = listingParameters.value;
const query = new URLSearchParams();
if (params.sort) query.set('sort', params.sort);
if (params.order) query.set('order', params.order);

if (exportScope.value === 'filtered') {
const params = listingParameters.value;
const query = new URLSearchParams();
if (params.search) query.set('search', params.search);
if (params.sort) query.set('sort', params.sort);
if (params.order) query.set('order', params.order);
if (params.filters) query.set('filters', params.filters);

const separator = url.includes('?') ? '&' : '?';
url += separator + query.toString();
}

const separator = url.includes('?') ? '&' : '?';
url += separator + query.toString();

window.open(url, '_blank');
exportModalOpen.value = false;
}
Expand Down
94 changes: 94 additions & 0 deletions tests/Feature/Forms/ExportSubmissionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace Tests\Feature\Forms;

use PHPUnit\Framework\Attributes\Test;
use Statamic\Facades\Blueprint;
use Statamic\Facades\Form;
use Statamic\Facades\FormSubmission;
use Statamic\Facades\User;
use Tests\PreventSavingStacheItemsToDisk;
use Tests\TestCase;

class ExportSubmissionsTest extends TestCase
{
use PreventSavingStacheItemsToDisk;

protected function resolveApplicationConfiguration($app)
{
parent::resolveApplicationConfiguration($app);

$app['config']['statamic.forms.forms'] = $this->fakeStacheDirectory.'/forms';
}

#[Test]
public function it_exports_submissions_sorted_by_a_column()
{
$form = $this->createFormWithSubmissions();

$response = $this
->actingAs(tap(User::make()->makeSuper())->save())
->export($form, 'csv', ['sort' => 'name', 'order' => 'asc'])
->assertOk();

$this->assertEquals(['Alice', 'Bravo', 'Charlie'], $this->namesFromCsv($response->getContent()));
}

#[Test]
public function it_exports_submissions_sorted_in_the_requested_direction()
{
$form = $this->createFormWithSubmissions();

$response = $this
->actingAs(tap(User::make()->makeSuper())->save())
->export($form, 'csv', ['sort' => 'name', 'order' => 'desc'])
->assertOk();

$this->assertEquals(['Charlie', 'Bravo', 'Alice'], $this->namesFromCsv($response->getContent()));
}

#[Test]
public function it_exports_submissions_sorted_by_the_listings_default_date_column()
{
$form = $this->createFormWithSubmissions();

$response = $this
->actingAs(tap(User::make()->makeSuper())->save())
->export($form, 'csv', ['sort' => 'datestamp', 'order' => 'desc'])
->assertOk();

$this->assertEquals(['Bravo', 'Alice', 'Charlie'], $this->namesFromCsv($response->getContent()));
}

private function createFormWithSubmissions()
{
$blueprint = Blueprint::makeFromFields(['name' => ['type' => 'text']]);
Blueprint::partialMock()->shouldReceive('find')->with('forms.test')->andReturn($blueprint);

$form = tap(Form::make('test'))->save();

// A submission's date is derived from its ID, so the IDs are set explicitly
// to keep the dates distinct and the resulting sort order deterministic.
collect(['Charlie' => '1700000001', 'Alice' => '1700000002', 'Bravo' => '1700000003'])
->each(fn ($id, $name) => FormSubmission::make()->form($form)->id($id)->data(['name' => $name])->save());

return $form;
}

private function export($form, $type, $params = [])
{
return $this->get(cp_route('forms.export', array_merge([
'form' => $form->handle(),
'type' => $type,
], $params)));
}

private function namesFromCsv($csv)
{
return collect(explode("\n", trim($csv)))
->slice(1)
->map(fn ($line) => str_getcsv($line)[0])
->values()
->all();
}
}
Loading