Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.x] Add helper arg for addons to easily remove child item in core nav #8883

Merged
merged 2 commits into from
Nov 1, 2023
Merged
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
49 changes: 45 additions & 4 deletions src/CP/Navigation/Nav.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,31 +45,49 @@ public function item($name)
}

/**
* Find or create nav item.
* Find nav item.
*
* @param string $section
* @param string $name
* @return NavItem|null
*/
public function findOrCreate($section, $name)
public function find($section, $name)
{
$item = collect($this->items)->first(function ($item) use ($section, $name) {
return $item->section() === $section
&& $item->display() === $name
&& ! $item->isChild();
});

return $item ?: $this->create($name)->section($section);
return $item;
}

/**
* Find or create nav item.
*
* @param string $section
* @param string $name
* @return NavItem
*/
public function findOrCreate($section, $name)
{
return $this->find($section, $name) ?: $this->create($name)->section($section);
}

/**
* Remove nav item.
*
* @param string $section
* @param string|null $name
* @param string|null $childName
* @return $this
*/
public function remove($section, $name = null)
public function remove($section, $name = null, $childName = null)
{
if ($childName) {
return $this->removeChildItem($section, $name, $childName);
}

$this->items = collect($this->items)
->reject(function ($item) use ($section, $name) {
return $name
Expand All @@ -81,6 +99,29 @@ public function remove($section, $name = null)
return $this;
}

/**
* Remove nav item.
*
* @param string $section
* @param string|null $name
* @param string|null $childName
* @return $this
*/
protected function removeChildItem($section, $name, $childName)
{
if (! $parent = $this->find($section, $name)) {
return $this;
}

if (! $children = $parent->resolveChildren()->children()) {
return $this;
}

$parent->children($children->reject(fn ($child) => $child->display() === $childName));

return $this;
}

/**
* Build navigation.
*
Expand Down
85 changes: 84 additions & 1 deletion tests/CP/Navigation/NavTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,35 @@ public function it_can_create_a_nav_item_with_a_custom_svg_icon()
}

/** @test */
public function it_can_get_and_modify_an_existing_item()
public function it_can_find_and_modify_an_existing_item()
{
$this->actingAs(tap(User::make()->makeSuper())->save());

Nav::droids('WAC-47')
->url('/pit-droid')
->icon('<svg>...</svg>');

Nav::find('Droids', 'WAC-47')
->url('/d-squad');

$item = $this->build()->get('Droids')->first();

$this->assertEquals('Droids', $item->section());
$this->assertEquals('WAC-47', $item->display());
$this->assertEquals('<svg>...</svg>', $item->icon());
$this->assertEquals('http://localhost/d-squad', $item->url());
}

/** @test */
public function it_can_find_and_modify_an_existing_item_using_magic_constructor()
{
$this->actingAs(tap(User::make()->makeSuper())->save());

Nav::droids('WAC-47')
->url('/pit-droid')
->icon('<svg>...</svg>');

// Callign the same constructor does a `findOrCreate()` under the hood...
Nav::droids('WAC-47')
->url('/d-squad');

Expand Down Expand Up @@ -344,6 +365,41 @@ public function it_can_remove_a_specific_nav_item()
$this->assertEquals('A-Wing', $ships->first()->display());
}

/** @test */
public function it_can_remove_a_specific_nav_child_item()
{
$this->actingAs(tap(User::make()->makeSuper())->save());

Nav::ships('Y-Wing')
->url('/y-wing')
->icon('y-wing')
->children(function () {
return [
Nav::item('Foo'),
Nav::item('Bar'),
];
});

Nav::ships('A-Wing')
->url('/a-wing')
->icon('a-wing')
->children(function () {
return [
Nav::item('Foo'),
Nav::item('Bar'),
];
});

$this->assertCount(2, $this->build()->get('Ships'));

Nav::remove('Ships', 'Y-Wing', 'Foo');

$this->assertCount(2, $ships = $this->build()->get('Ships'));

$this->assertEquals(['Bar'], $ships->first()->resolveChildren()->children()->map->display()->all());
$this->assertEquals(['Foo', 'Bar'], $ships->last()->resolveChildren()->children()->map->display()->all());
}

/** @test */
public function it_can_use_extend_to_defer_until_after_statamic_core_nav_items_are_built()
{
Expand Down Expand Up @@ -378,6 +434,33 @@ public function it_can_use_extend_to_remove_a_default_statamic_nav_item()
$this->assertNotContains('Collections', $this->build()->get('Content')->map->display());
}

/** @test */
public function it_can_use_extend_to_remove_a_default_statamic_child_nav_item()
{
Facades\Collection::make('articles')->save();
Facades\Collection::make('pages')->save();

$this->actingAs(tap(User::make()->makeSuper())->save());

$nav = Nav::build();

$collectionsChildren = function () {
return $this->build()
->get('Content')
->first(fn ($item) => $item->display() === 'Collections')
->resolveChildren()
->children();
};

$this->assertEquals(['Articles', 'Pages'], $collectionsChildren()->map->display()->all());

Nav::extend(function ($nav) {
$nav->remove('Content', 'Collections', 'Articles');
});

$this->assertEquals(['Pages'], $collectionsChildren()->map->display()->all());
}

/** @test */
public function it_checks_if_active()
{
Expand Down
Loading