Ron
Ron
FFilament
Created by Ron on 7/23/2024 in #❓┊help
Testing call wizard next step fails
I am unable to get my Pest test function to actually call the form wizard next step.
CreateUserTest.php
use function Pest\Livewire\livewire;

it('can validate creating a user', function () {
livewire(UserResource\Pages\CreateUser::class)
->fillForm([])
->callFormComponentAction(component: 'create-user', name: 'next')
->assertHasFormErrors(['name' => 'The name field is required.']);
});
use function Pest\Livewire\livewire;

it('can validate creating a user', function () {
livewire(UserResource\Pages\CreateUser::class)
->fillForm([])
->callFormComponentAction(component: 'create-user', name: 'next')
->assertHasFormErrors(['name' => 'The name field is required.']);
});
This test fails with "Component has no errors" but the name field is required. Following the test source code and injecting "ray()" debug calls, it appears the next step action is not called. CreateUser.php
use CreateRecord\Concerns\HasWizard;
public function form(Form $form): Form
{
return parent::form($form)
->schema([
Wizard::make($this->getSteps())
->key('data.create-user')
...
]);
}
protected function getSteps(): array
{
return [
Step::make('Name')
->schema([
TextInput::make('name')->required(),
]),
Step::make('Email')
->schema([
TextInput::make('email')->email()->required(),
]),
];
}
use CreateRecord\Concerns\HasWizard;
public function form(Form $form): Form
{
return parent::form($form)
->schema([
Wizard::make($this->getSteps())
->key('data.create-user')
...
]);
}
protected function getSteps(): array
{
return [
Step::make('Name')
->schema([
TextInput::make('name')->required(),
]),
Step::make('Email')
->schema([
TextInput::make('email')->email()->required(),
]),
];
}
I referenced the following this link https://filamentphp.com/docs/3.x/panels/resources/creating-records#using-a-wizard in the docs. Does anyone know the correct way to test the next step action in a form wizard?
2 replies
FFilament
Created by Ron on 7/10/2024 in #❓┊help
reload a Livewire form component after updating the record
I am attempting to refresh a livewire form component after updating the record associated with the form section. I have a form section with a simple schema that just loads a livewire component. That livewire component uses a mount method to retrieve the record and passes this to an infolist. This all works great on initial load, but I have a section footer action that updates the record and I want the infolist to refresh after update.
Section::make('Applicant Recommendation)
->schema([
Livewire::make(ViewApplicantRecommendation::class)
->key('view-applicant-recommendation'),
])
->footerActions([
OverrideRecommendation::action(),
])->footerActionsAlignment(Alignment::End);
Section::make('Applicant Recommendation)
->schema([
Livewire::make(ViewApplicantRecommendation::class)
->key('view-applicant-recommendation'),
])
->footerActions([
OverrideRecommendation::action(),
])->footerActionsAlignment(Alignment::End);
The OverrideRecommendation action has a modal form and then updates the record in the action
->action(function (array $data, Order $record, Component $livewire) {
$record->recommendation->update([
'recommendation' => $data['override_recommendation'],
]);
->action(function (array $data, Order $record, Component $livewire) {
$record->recommendation->update([
'recommendation' => $data['override_recommendation'],
]);
ViewApplicationRecommendation uses an infolist and includes a mount method to get the record
public ?Order $record = null;
public function mount(?Order $record = null): void
{
$this->record = $record;
}
public function recommendationInfolist(Infolist $infolist): Infolist
{

return $infolist
->record($this->record)
->schema([
$this->getReasonsRepeatableEntry(),
]);
}
public ?Order $record = null;
public function mount(?Order $record = null): void
{
$this->record = $record;
}
public function recommendationInfolist(Infolist $infolist): Infolist
{

return $infolist
->record($this->record)
->schema([
$this->getReasonsRepeatableEntry(),
]);
}
In the OverrideRecommendation action I can redirect, which would be fine but it doesn't seem as Livewire assorts redirects to url fragments to position the page to the section.
8 replies
FFilament
Created by Ron on 7/6/2024 in #❓┊help
How to test Header/Footer Actions in a Section Form Component
callFormComponentAction fails with error "Call to a member function getKey() on null" when attempting to test calling a section header action. Can callFormComponentAction() be used to test Header/Footer actions on Form Sections. Test Code:
it('can toggle form edit', function () {
$order = $this->getOrders(1);

// Arrange
livewire(OrderRentalHistory::class, ['record' => $order->id])
->assertFormFieldIsDisabled('address')
->callFormComponentAction('rental-history', 'edit-form')
->assertFormFieldIsEnabled('address');

});
it('can toggle form edit', function () {
$order = $this->getOrders(1);

// Arrange
livewire(OrderRentalHistory::class, ['record' => $order->id])
->assertFormFieldIsDisabled('address')
->callFormComponentAction('rental-history', 'edit-form')
->assertFormFieldIsEnabled('address');

});
Form Code:
Section::make('Rental History')
->key('rental-history')
->headerActions([
Action::make('edit-form')
->label('Edit')
->button()
->icon('mdi-pencil')
->action(fn (Get $get, Set $set) => $set('form-editable', ! $get('form-editable'))),
])
->schema([
Hidden::make('form-editable')
->live(),
TextInput::make('address')
->prefixIcon('mdi-map-marker')
->disabled(fn (Get $get) => ! $get('form-editable')),

]),
Section::make('Rental History')
->key('rental-history')
->headerActions([
Action::make('edit-form')
->label('Edit')
->button()
->icon('mdi-pencil')
->action(fn (Get $get, Set $set) => $set('form-editable', ! $get('form-editable'))),
])
->schema([
Hidden::make('form-editable')
->live(),
TextInput::make('address')
->prefixIcon('mdi-map-marker')
->disabled(fn (Get $get) => ! $get('form-editable')),

]),
2 replies
FFilament
Created by Ron on 5/5/2024 in #❓┊help
How to close an ActionGroup dropdown with a custom function after the function completes
I see from a similar post how to close the drop down immediately on click, but is there a way to close the drop down within the custom function itself to preserve the progress spinner on the action? The code below shows an action w/in a group where the drop down is closed immediately (this code was from a similar post)
ActionGroup::make([
Action::make('process')
->action(function (Action $action) {
// ... run process function
// Is it possible to use the injected Action to close here, after processing
})
// Adding Extra Attributes will close the drop down immediately
->extraAttributes(['x-on:click' => 'close']),
])->button();
ActionGroup::make([
Action::make('process')
->action(function (Action $action) {
// ... run process function
// Is it possible to use the injected Action to close here, after processing
})
// Adding Extra Attributes will close the drop down immediately
->extraAttributes(['x-on:click' => 'close']),
])->button();
5 replies
FFilament
Created by Ron on 1/10/2024 in #❓┊help
Global navigation combined from multiple panels.
Is it possible to combine the navigation from multiple "sub" panels into a single app panel. I have an App panel with this code:
->navigation(function (NavigationBuilder $builder): NavigationBuilder {
return $builder->items(
items: PanelNavigation::items()
);
})
->navigation(function (NavigationBuilder $builder): NavigationBuilder {
return $builder->items(
items: PanelNavigation::items()
);
})
And PanelNavigation:items() calls module facades to pull the navigation items from respective panels
public static function items(): array
{
return [
NavigationItem::make('Dashboard')
->icon('mdi-view-dashboard')
->url(fn (): string => Dashboard::getUrl()),
...\Central::getNavigationItems(),
...\Logging::getNavigationItems(),
];

}
public static function items(): array
{
return [
NavigationItem::make('Dashboard')
->icon('mdi-view-dashboard')
->url(fn (): string => Dashboard::getUrl()),
...\Central::getNavigationItems(),
...\Logging::getNavigationItems(),
];

}
The getNavigationItems from a facade / module gets the resource navitems with the following
public function getNavigationItems(): array
{

return [
...CompanyResource::getNavigationItems(),
...CompanyThemeResource::getNavigationItems(),
...PropertyResource::getNavigationItems(),
];
}
public function getNavigationItems(): array
{

return [
...CompanyResource::getNavigationItems(),
...CompanyThemeResource::getNavigationItems(),
...PropertyResource::getNavigationItems(),
];
}
I use the same navigation builder in each panel and the code works only when running the /admin panel. When accessing the /app panel, the error is Route [filament.app.resources.companies.index] not defined. It appears that CompanyResource::getNavigationItems() is using the App panel to build the route Has anyone successfull built a global side nav with access to multiple panel resources?
3 replies