Skip to content

Commit

Permalink
[5.x] Add ability to reset namespaced fieldsets (#9166)
Browse files Browse the repository at this point in the history
Co-authored-by: Duncan McClean <duncan@duncanmcclean.com>
Co-authored-by: Jason Varga <jason@pixelfear.com>
  • Loading branch information
3 people authored Aug 19, 2024
1 parent 7efe556 commit 0f04dfc
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 2 deletions.
102 changes: 102 additions & 0 deletions resources/js/components/fieldsets/FieldsetResetter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<template>
<confirmation-modal
v-if="resetting"
:title="modalTitle"
:bodyText="modalBody"
:buttonText="__('Reset')"
:danger="true"
@confirm="confirmed"
@cancel="cancel"
>
</confirmation-modal>
</template>

<script>
export default {
props: {
resource: {
type: Object
},
resourceTitle: {
type: String
},
route: {
type: String,
},
redirect: {
type: String
},
reload: {
type: Boolean
}
},
data() {
return {
resetting: false,
redirectFromServer: null,
}
},
computed: {
title() {
return data_get(this.resource, 'title', this.resourceTitle);
},
modalTitle() {
return __('Reset :resource', {resource: this.title});
},
modalBody() {
return __('Are you sure you want to reset this item?');
},
resetUrl() {
let url = data_get(this.resource, 'reset_url', this.route);
if (! url) console.error('FieldsetResetter cannot find reset url');
return url;
},
redirectUrl() {
return this.redirect || this.redirectFromServer;
},
},
methods: {
confirm() {
this.resetting = true;
},
confirmed() {
this.$axios.delete(this.resetUrl)
.then(response => {
this.redirectFromServer = data_get(response, 'data.redirect');
this.success();
})
.catch(() => {
this.$toast.error(__('Something went wrong'));
});
},
success() {
if (this.redirectUrl) {
location.href = this.redirectUrl;
return;
}
if (this.reload) {
location.reload();
return;
}
this.$toast.success(__('Reset'));
this.$emit('reset');
},
cancel() {
this.resetting = false;
}
}
}
</script>
19 changes: 18 additions & 1 deletion resources/js/components/fieldsets/Listing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
<template slot="actions" slot-scope="{ row: fieldset, index }">
<dropdown-list>
<dropdown-item :text="__('Edit')" :redirect="fieldset.edit_url" />
<dropdown-item
v-if="fieldset.is_resettable"
:text="__('Reset')"
class="warning"
@click="$refs[`resetter_${fieldset.id}`].confirm()"
>
<fieldset-resetter
:ref="`resetter_${fieldset.id}`"
:resource="fieldset"
:reload="true"
>
</fieldset-resetter>
</dropdown-item>
<dropdown-item
v-if="fieldset.is_deletable"
:text="__('Delete')"
Expand All @@ -35,12 +48,16 @@
<script>
import Listing from '../Listing.vue';
import FieldsetDeleter from './FieldsetDeleter.vue';
import FieldsetResetter from './FieldsetResetter.vue';
export default {
mixins: [Listing],
components: {FieldsetDeleter},
components: {
FieldsetDeleter,
FieldsetResetter
},
props: ['initialRows'],
Expand Down
1 change: 1 addition & 0 deletions routes/cp.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
Route::post('edit', [FieldsController::class, 'edit'])->name('fields.edit');
Route::post('update', [FieldsController::class, 'update'])->name('fields.update');
Route::get('field-meta', [MetaController::class, 'show']);
Route::delete('fieldsets/{fieldset}/reset', [FieldsetController::class, 'reset'])->name('fieldsets.reset');
Route::resource('fieldsets', FieldsetController::class)->except(['show']);
Route::get('blueprints', [BlueprintController::class, 'index'])->name('blueprints.index');
Route::get('blueprints/{namespace}/{handle}', [BlueprintController::class, 'edit'])->name('blueprints.edit');
Expand Down
1 change: 1 addition & 0 deletions src/Events/Concerns/ListensForContentEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ trait ListensForContentEvents
\Statamic\Events\EntryDeleted::class,
\Statamic\Events\EntrySaved::class,
\Statamic\Events\FieldsetDeleted::class,
\Statamic\Events\FieldsetReset::class,
\Statamic\Events\FieldsetSaved::class,
\Statamic\Events\FormDeleted::class,
\Statamic\Events\FormSaved::class,
Expand Down
20 changes: 20 additions & 0 deletions src/Events/FieldsetReset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Statamic\Events;

use Statamic\Contracts\Git\ProvidesCommitMessage;

class FieldsetReset extends Event implements ProvidesCommitMessage
{
public $fieldset;

public function __construct($fieldset)
{
$this->fieldset = $fieldset;
}

public function commitMessage()
{
return __('Fieldset reset', [], config('statamic.git.locale'));
}
}
22 changes: 22 additions & 0 deletions src/Fields/Fieldset.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
use Statamic\Events\FieldsetCreating;
use Statamic\Events\FieldsetDeleted;
use Statamic\Events\FieldsetDeleting;
use Statamic\Events\FieldsetReset;
use Statamic\Events\FieldsetSaved;
use Statamic\Events\FieldsetSaving;
use Statamic\Exceptions\FieldsetRecursionException;
use Statamic\Facades;
use Statamic\Facades\AssetContainer;
use Statamic\Facades\Collection;
use Statamic\Facades\Fieldset as FieldsetRepository;
use Statamic\Facades\File;
use Statamic\Facades\GlobalSet;
use Statamic\Facades\Path;
use Statamic\Facades\Taxonomy;
Expand Down Expand Up @@ -126,6 +128,11 @@ public function deleteUrl()
return cp_route('fieldsets.destroy', $this->handle());
}

public function resetUrl()
{
return cp_route('fieldsets.reset', $this->handle());
}

public function importedBy(): array
{
$blueprints = collect([
Expand Down Expand Up @@ -193,6 +200,12 @@ public function isDeletable()
return ! $this->isNamespaced();
}

public function isResettable()
{
return $this->isNamespaced()
&& File::exists(FieldsetRepository::overriddenNamespacedFieldsetPath($this->handle));
}

public function afterSave($callback)
{
$this->afterSaveCallbacks[] = $callback;
Expand Down Expand Up @@ -269,6 +282,15 @@ public function delete()
return true;
}

public function reset()
{
FieldsetRepository::reset($this);

FieldsetReset::dispatch($this);

return true;
}

public static function __callStatic($method, $parameters)
{
return Facades\Fieldset::{$method}(...$parameters);
Expand Down
11 changes: 10 additions & 1 deletion src/Fields/FieldsetRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private function namespacedFieldsetPath(string $handle)
return "{$this->hints[$namespace]}/{$path}.yaml";
}

private function overriddenNamespacedFieldsetPath(string $handle)
public function overriddenNamespacedFieldsetPath(string $handle)
{
[$namespace, $handle] = explode('::', $handle);
$handle = str_replace('/', '.', $handle);
Expand Down Expand Up @@ -183,6 +183,15 @@ public function delete(Fieldset $fieldset)
File::delete("{$this->directory}/{$fieldset->handle()}.yaml");
}

public function reset(Fieldset $fieldset)
{
if (! $fieldset->isNamespaced()) {
throw new \Exception('Non-namespaced fieldsets cannot be reset');
}

File::delete($this->overriddenNamespacedFieldsetPath($fieldset->handle()));
}

public function addNamespace(string $namespace, string $directory): void
{
$this->hints[$namespace] = $directory;
Expand Down
13 changes: 13 additions & 0 deletions src/Http/Controllers/CP/Fields/FieldsetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ public function index(Request $request)
'id' => $fieldset->handle(),
'delete_url' => $fieldset->deleteUrl(),
'edit_url' => $fieldset->editUrl(),
'reset_url' => $fieldset->resetUrl(),
'fields' => $fieldset->fields()->all()->count(),
'imported_by' => collect($fieldset->importedBy())->flatten(1)->mapToGroups(function ($item) {
return [$this->group($item) => ['handle' => $item->handle(), 'title' => $item->title()]];
}),
'is_deletable' => $fieldset->isDeletable(),
'is_resettable' => $fieldset->isResettable(),
'title' => $fieldset->title(),
],
];
Expand Down Expand Up @@ -158,6 +160,17 @@ public function destroy($fieldset)
return response('');
}

public function reset($fieldset)
{
$fieldset = Facades\Fieldset::find($fieldset);

$this->authorize('delete', $fieldset);

$fieldset->reset();

return response('');
}

private function groupKey(Fieldset $fieldset): string
{
return $fieldset->isNamespaced() ? Str::of($fieldset->namespace())->replace('_', ' ')->title() : __('My Fieldsets');
Expand Down
16 changes: 16 additions & 0 deletions tests/Feature/Fieldsets/ViewFieldsetListingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ public function it_shows_a_list_of_fieldsets()
'baz::baz' => $this->createFieldset('baz::baz'),
]));

Facades\Fieldset::shouldReceive('overriddenNamespacedFieldsetPath')
->with('baz::foo')
->andReturn('/fieldsets/vendor/baz/foo.yaml');

Facades\Fieldset::shouldReceive('overriddenNamespacedFieldsetPath')
->with('baz::bar')
->andReturn('/fieldsets/vendor/baz/bar.yaml');

// Custom policy to allow fieldsets to demonstrate how certain fieldset can be restricted
app()->bind(\Statamic\Policies\FieldsetPolicy::class, function () {
return new class extends \Statamic\Policies\FieldsetPolicy
Expand Down Expand Up @@ -54,7 +62,9 @@ public function before($user, $ability, $fieldset)
'fields' => 0,
'edit_url' => 'http://localhost/cp/fields/fieldsets/foo/edit',
'delete_url' => 'http://localhost/cp/fields/fieldsets/foo',
'reset_url' => 'http://localhost/cp/fields/fieldsets/foo/reset',
'is_deletable' => true,
'is_resettable' => false,
'imported_by' => collect(),
],
[
Expand All @@ -64,7 +74,9 @@ public function before($user, $ability, $fieldset)
'fields' => 0,
'edit_url' => 'http://localhost/cp/fields/fieldsets/bar/edit',
'delete_url' => 'http://localhost/cp/fields/fieldsets/bar',
'reset_url' => 'http://localhost/cp/fields/fieldsets/bar/reset',
'is_deletable' => true,
'is_resettable' => false,
'imported_by' => collect(),
],
]),
Expand All @@ -76,7 +88,9 @@ public function before($user, $ability, $fieldset)
'fields' => 0,
'edit_url' => 'http://localhost/cp/fields/fieldsets/baz::foo/edit',
'delete_url' => 'http://localhost/cp/fields/fieldsets/baz::foo',
'reset_url' => 'http://localhost/cp/fields/fieldsets/baz::foo/reset',
'is_deletable' => false,
'is_resettable' => false,
'imported_by' => collect(),
],
[
Expand All @@ -86,7 +100,9 @@ public function before($user, $ability, $fieldset)
'fields' => 0,
'edit_url' => 'http://localhost/cp/fields/fieldsets/baz::bar/edit',
'delete_url' => 'http://localhost/cp/fields/fieldsets/baz::bar',
'reset_url' => 'http://localhost/cp/fields/fieldsets/baz::bar/reset',
'is_deletable' => false,
'is_resettable' => false,
'imported_by' => collect(),
],
]),
Expand Down
10 changes: 10 additions & 0 deletions tests/Fields/FieldsetRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@ public function it_doesnt_delete_namespaced_fieldsets()
$this->repo->delete($fieldset);
}

#[Test]
public function it_resets_a_namespaced_fieldset()
{
File::shouldReceive('delete')->once();

$fieldset = (new Fieldset)->setHandle('foo::test');

$this->repo->reset($fieldset);
}

#[Test]
public function it_gets_a_namespaced_fieldset()
{
Expand Down

0 comments on commit 0f04dfc

Please sign in to comment.