Skip to content
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
5 changes: 5 additions & 0 deletions demo/app/Models/Category.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Translatable\HasTranslations;

class Category extends Model
{
use HasFactory;
use HasTranslations;

protected $guarded = [];
public array $translatable = [
'description',
];

public function posts(): BelongsToMany
{
Expand Down
4 changes: 3 additions & 1 deletion demo/app/Sharp/Authors/Commands/InviteUserCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ public function label(): ?string
public function buildCommandConfig(): void
{
$this->configureFormModalTitle('Invite a new user as author')
->configureFormModalDescription('Provide the email address of the new author, and an invitation will be sent to him (not true, we won’t send anything).');
->configureFormModalDescription('Provide the email address of the new author, and an invitation will be sent to him (not true, we won’t send anything).')
->configureFormModalButtonLabel('Send invitation')
->configureFormModalSubmitAndReopenButton('Send & send another');
}

public function buildFormFields(FieldsContainer $formFields): void
Expand Down
16 changes: 13 additions & 3 deletions demo/app/Sharp/Categories/CategoryForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Models\Category;
use Code16\Sharp\Form\Eloquent\WithSharpFormEloquentUpdater;
use Code16\Sharp\Form\Fields\SharpFormTextareaField;
use Code16\Sharp\Form\Fields\SharpFormTextField;
use Code16\Sharp\Form\Layout\FormLayout;
use Code16\Sharp\Form\Layout\FormLayoutColumn;
Expand All @@ -21,13 +22,21 @@ public function buildFormFields(FieldsContainer $formFields): void
SharpFormTextField::make('name')
->setLabel('Name')
->setMaxLength(150),
)
->addField(
SharpFormTextareaField::make('description')
->setLabel('Description')
->setRowCount(4)
->setLocalized()
->setMaxLength(500),
);
}

public function buildFormLayout(FormLayout $formLayout): void
{
$formLayout->addColumn(6, function (FormLayoutColumn $column) {
$column->withField('name');
$column->withField('name')
->withField('description');
});
}

Expand All @@ -49,8 +58,9 @@ public function find($id): array
public function update($id, array $data)
{
$this->validate(
$data,
['name' => ['required', 'string', 'max:150']]
$data, [
'name' => ['required', 'string', 'max:150'],
]
);

$category = $id
Expand Down
3 changes: 2 additions & 1 deletion demo/app/Sharp/Categories/CategoryList.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ protected function buildList(EntityListFieldsContainer $fields): void

public function buildListConfig(): void
{
$this->configureReorderable(new SimpleEloquentReorderHandler(Category::class));
$this->configureReorderable(new SimpleEloquentReorderHandler(Category::class))
->configureQuickCreationForm(['name']);
}

protected function getEntityCommands(): ?array
Expand Down
21 changes: 16 additions & 5 deletions demo/app/Sharp/Categories/CategoryShow.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,20 @@ public function find(mixed $id): array
protected function buildShowFields(FieldsContainer $showFields): void
{
$showFields
->addField(SharpShowTextField::make('name')->setLabel('Name'))
->addField(
SharpShowTextField::make('name')
->setLabel('Name'))
->addField(
SharpShowTextField::make('description')
->setLocalized()
->setLabel('Description')
)
->addField(
SharpShowEntityListField::make('posts')
->setLabel('Related posts')
->showCreateButton(false)
->showCount()
->hideFilterWithValue(CategoryFilter::class, function ($instanceId) {
return $instanceId;
}),
->hideFilterWithValue(CategoryFilter::class, fn ($instanceId) => $instanceId)
);
}

Expand All @@ -45,7 +50,8 @@ protected function buildShowLayout(ShowLayout $showLayout): void
->addSection('', function (ShowLayoutSection $section) {
$section
->addColumn(6, function (ShowLayoutColumn $column) {
$column->withField('name');
$column->withField('name')
->withField('description');
});
})
->addEntityListSection('posts', collapsable: true);
Expand All @@ -55,4 +61,9 @@ public function delete($id): void
{
Category::findOrFail($id)->delete();
}

public function getDataLocalizations(): array
{
return ['fr', 'en'];
}
}
3 changes: 2 additions & 1 deletion demo/app/Sharp/Posts/Blocks/PostBlockList.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ protected function buildList(EntityListFieldsContainer $fields): void
public function buildListConfig(): void
{
$this->configureMultiformAttribute('type')
->configureReorderable(new SimpleEloquentReorderHandler(PostBlock::class));
->configureReorderable(new SimpleEloquentReorderHandler(PostBlock::class))
->configureQuickCreationForm();
}

protected function getFilters(): ?array
Expand Down
1 change: 1 addition & 0 deletions demo/database/factories/CategoryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public function definition()
{
return [
'name' => $this->faker->unique()->randomElement(static::$categoryNames),
'description' => $this->faker->paragraph(),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public function up()
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->unsignedSmallInteger('order')->default(100);
$table->timestamps();
});
Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export function sidebar(): DefaultTheme.SidebarItem[] {
{ text: 'Create a Form', link: '/guide/building-form.md' },
{ text: 'Multi-Forms', link: '/guide/multiforms.md' },
{ text: 'Using Single Form for unique resources', link: '/guide/single-form.md' },
{ text: 'Quick creation form', link: '/guide/quick-creation-form.md' },
{ text: 'Write an Embed for the Editor field', link: '/guide/form-editor-embeds.md' },
{ text: 'Text', link: '/guide/form-fields/text.md' },
{ text: 'Textarea', link: '/guide/form-fields/textarea.md' },
Expand Down
2 changes: 2 additions & 0 deletions docs/guide/building-entity-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ Here is the full list of available methods:

- `configurePrimaryEntityCommand(string $commandKeyOrClassName)`: define an instance command as "primary", by passing its key or full cass name. The command should be declared for this Entity List ([see related doc](commands.md)).

- `configureQuickCreationForm(?array $fields = null)`: show the creation form in a modal instead of a full page ([see detailed doc](quick-creation-form.md))

- `configureDelete(bool $hide = false, ?string $onfirmationText = null)`: the first argument is to show / hide the delete command on each instance (shown by default); this is only useful to hide the link if you want to only display the delete action in the Show Page (if you have defined one), this is NOT to be used for authorization purpose (see [dedicated documentation on this topic](entity-authorizations.md)). The second argument is the message to display in the confirmation dialog (a sensible default will be used).

- `configureCreateButtonLabel(string $label)` to set a custom "New..." button label.
Expand Down
48 changes: 25 additions & 23 deletions docs/guide/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ The example above is an "entity" case, which is reserved to Entity Lists: Comman
To create an instance Command (relative to a specific instance, which can be placed on each Entity List row, or in a Show Page), the Command class must extend `Code16\Sharp\EntityList\Commands\InstanceCommand`. The execute method signature is a bit different:

```php
public function execute($instanceId, array $params = []): array
class PromoteToAdminCommand extends InstanceCommand
{
// [...]
public function execute($instanceId, array $params = []): array
{
// ...
}
}
```

Expand All @@ -60,7 +63,7 @@ The second parameter in the `execute()` function is an array named `$data`, whic
```php
class SendInvoiceToCustomerCommand extends InstanceCommand
{
// [...]
// ...

function buildFormFields(FieldsContainer $formFields): void
{
Expand All @@ -84,7 +87,7 @@ Once this method has been declared, a form will be prompted to the user in a mod
```php
class SendInvoiceToCustomerCommand extends InstanceCommand
{
// [...]
// ...

public function execute($instanceId, array $data = []): array
{
Expand All @@ -101,7 +104,7 @@ class SendInvoiceToCustomerCommand extends InstanceCommand
```

::: tip
Notice that validation can be extracted to a dedicated `rules()` method instead.
Validation can be extracted to a dedicated `rules()` method instead.
:::

#### Initializing form data
Expand All @@ -122,7 +125,7 @@ For an Instance command, add the `$instanceId` as a parameter:
```php
protected function initialData($instanceId): array
{
// [...]
// ...
}
```

Expand Down Expand Up @@ -162,10 +165,11 @@ Here is the full list of available methods:
- `configureFormModalTitle(string $formModalTitle)`: if the Command has a Form, the title of the modal will be its label, or `$formModalTitle` if defined
- `configureFormModalButtonLabel(string $formModalButtonLabel)`: if the Command has a Form, the label of the OK button will be `$formModalButtonLabel`
- `configurePageAlert(string $template, string $alertLevel = null, string $fieldKey = null, bool $declareTemplateAsPath = false)`: display a dynamic message above the Form; [see detailed doc](page-alerts.md)
- `configureFormModalSubmitAndReopenButton(?string $label = null)`: only useful to Commands with forms; if set, an additional button will be displayed to allow the user to submit the form and immediately reopen the Command; the label of the button will be `$label` if defined.

### Command return types

Finally, let's review the return possibilities: after a Command has been executed, the code must return something to tell to the front what to do next. There are six of them:
Finally, let's review the return possibilities: after a Command has been executed, the code must return something to tell to the front what to do next. There are height of them:

- `return $this->info('some text')`: displays the entered text in a modal.
- `return $this->reload()`: reload the current page (with context).
Expand All @@ -181,16 +185,14 @@ Finally, let's review the return possibilities: after a Command has been execute
```php
class OrderList extends SharpEntityList
{
// [...]
function getListData()
// ...
function getListData(): array|Arrayble
{
$orders = Order::query();

if($params->specificIds()) {
$orders->whereIn('id', $this->queryParams->specificIds());
}

return $this->transform($orders->get());
return Order::query()
->when($this->queryParams->specificIds(), function (Builder $query, $ids) {
$query->whereIn('id', $ids);
})
->transform($orders->get());
}
}
```
Expand All @@ -202,7 +204,7 @@ In the same fashion as for a Form, you can display notifications after a Command
```php
public function execute($instanceId, array $data= []): array
{
// [...]
// ...

$this->notify('This is done.')
->setDetail('As you asked.')
Expand All @@ -226,7 +228,7 @@ Once the Command class is written, we must add it to the Entity List or Show Pag
```php
class OrderList extends SharpEntityList
{
// [...]
// ...
function getInstanceCommands(): ?array
{
return [
Expand All @@ -248,7 +250,7 @@ or to the Dashboard:
```php
class SalesDashboard extends SharpDashboard
{
// [...]
// ...

function getDashboardCommands(): ?array
{
Expand Down Expand Up @@ -305,7 +307,7 @@ An Entity List can declare one (and only one) of its entity Commands as "primary
```php
class UserList extends SharpEntityList
{
// [...]
// ...

function buildListConfig(): void
{
Expand Down Expand Up @@ -339,7 +341,7 @@ To achieve this, you must choose a unique key and attach it to the layout sectio
```php
class PostShow extends SharpShow
{
// [...]
// ...

protected function buildShowLayout(ShowLayout $showLayout): void
{
Expand Down Expand Up @@ -386,7 +388,7 @@ As seen before, Entity Commands are executed on multiple instances: either all o
```php
class MyBulkCommand extends EntityCommand
{
// [...]
// ...

public function buildCommandConfig(): void
{
Expand All @@ -406,7 +408,7 @@ Use the `$this->selectedIds()` method to retrieve the list of selected instances
```php
class MyBulkCommand extends EntityCommand
{
// [...]
// ...

public function execute(array $data = []): array
{
Expand Down
41 changes: 41 additions & 0 deletions docs/guide/quick-creation-form.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Quick creation form

Sometimes you may want to allow the creation of a new instance directly from the list page, without having to navigate to a dedicated creation page. It's especially useful when the create form does not require a lot of fields, to keep the user in the list context — and since Sharp will display a "submit and reopen" button in the modal, the user can quickly create multiple instances.

## Prerequisites

This feature will only work if a Form is defined for the entity (since Sharp will entirely rely on it).

## Configuration

The configuration is done in the Entity List:

```php
class MyList extends SharpEntityList
{
public function buildListConfig(): void
{
$this->configureQuickCreationForm();
}
// ...
}
```

With this, when the user clicks on the "New..." button, a modal will open with the form fields defined in the Form. One common practice is to limit the fields to the strict minimum: this can be achieved by passing an array of field keys to the `configureQuickCreationForm` method:

```php
class MyList extends SharpEntityList
{
public function buildListConfig(): void
{
$this->configureQuickCreationForm(['name', 'price']);
}
// ...
}
```

Of course, ensure that these fields are defined in the Form and that all the required fields are present.

## Redirect to the Show Page

When the Form is configured with `configureDisplayShowPageAfterCreation()`, and if the user does not choose to stay in creation (with the "submit and reopen" button), Sharp will redirect to the Show Page after the creation.
5 changes: 3 additions & 2 deletions resources/js/Pages/EntityList/EntityList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
const entityList: Ref<EntityList> = ref(new EntityList(props.entityList, entityKey));
const filters = useFilters(entityList.value.config.filters, entityList.value.filterValues);
const commands = useCommands('entityList', {
refresh: (data) => {
entityList.value = entityList.value.withRefreshedItems(data.items)
refresh: (data, { formModal }) => {
entityList.value = entityList.value.withRefreshedItems(data.items);
formModal.shouldReopen && formModal.reopen();
},
});

Expand Down
Loading
Loading