Upgrading from 8.x to 9.x
This is a very big release, with a lot of changes. We try to limit breaking changes, but there are some... This guide will help you to upgrade your Sharp 8.x app to Sharp 9.x.
General
Get new assets, clear cache
This is true for every update: be sure to grab the latest assets and to clear the view cache:
php artisan vendor:publish --tag=sharp-assets --force
php artisan view:clear
Update your composer.json
The command used to publish sharp's assets changed, you should update your composer.json
:
{
"scripts": {
"post-update-cmd": [
"@php artisan vendor:publish --tag=sharp-assets --force"
]
}
}
INFO
Note that in addition to the command modification, we previously advice to put this script in the post-autoload-dump
section, but this is not recommended anymore, move it to post-update-cmd
instead.
Deprecated methods have been removed
- Entity List: deprecated
buildListFields()
andbuildListLayout()
were removed, usebuildList()
instead - Form: deprecated
delete()
method was removed (since it was moved to show / entity list in 8.x)
New way to configure Sharp, via a dedicated builder class
The config/sharp.php
file was entirely removed in favor of a dedicated builder class. This is not a breaking change since the config file is still supported, but deprecated, so you are encouraged to migrate to the new builder class.
To migrate, you should first create a new Service Provider which extends Code16\Sharp\SharpAppServiceProvider
and implements the configureSharp()
method:
use Code16\Sharp\SharpAppServiceProvider;
class MySharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->setName('My project')
->addEntity('posts', PostEntity::class)
// ...
}
}
Report all you configuration using the API of this new SharpConfigBuilder
class. It should be pretty straightforward, as all the methods are named after the config keys they replace. For example:
In 8.x:
// Old config/sharp.php
return [
'name' => 'Demo project',
'custom_url_segment' => 'sharp',
'display_breadcrumb' => true,
'entities' => [
'posts' => \App\Sharp\Entities\PostEntity::class,
],
'global_filters' => fn () => auth()->id() === 1 ? [] : [\App\Sharp\DummyGlobalFilter::class],
'search' => [
'enabled' => true,
'placeholder' => 'Search for posts or authors...',
'engine' => \App\Sharp\AppSearchEngine::class,
],
'menu' => \App\Sharp\SharpMenu::class,
// ...
];
In 9.x:
class MySharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->setName('Demo project')
->setCustomUrlSegment('sharp')
->setDisplayBreadcrumb()
->addEntity('posts', PostEntity::class)
->addGlobalFilter(DummyGlobalFilter::class) // The auth()->id() === 1 no longer can be handled here, as the auth context is yet not available. Use the new authorize() method of the global filter instead.
->enableGlobalSearch(AppSearchEngine::class, 'Search for posts or authors...')
->setMenu(SharpMenu::class)
// ...
}
}
WARNING
Be sure to register this new Service Provider in your app.
New middleware to declare
Due to migration to inertia, two middleware must be added to the config.
INFO
if you migrated to the new config builder class, you should be ok unless you have explicitly overridden the whole middleware list.
Here is the impact on the deprecated config file:
// config/sharp.php
return [
'middleware' => [
// ...
'web' => [
// ...
\Code16\Sharp\Http\Middleware\HandleSharpErrors::class,
\Code16\Sharp\Http\Middleware\HandleInertiaRequests::class,
],
],
]
Migration to blade-icons
In 8.x, menu icons was FontAwesome classes like fa fa-user
or fas fa-user
. Now icons must be blade-icons icon names with its associated package installed.
Icons are not required but if you want to keep FontAwesome, you can install the following package:
composer require owenvoke/blade-fontawesome
And rename old icon names to blade-fontawesome names in your SharpMenu
:
# Solid icons
- ->addEntityLink('entity', 'Entity', 'fas fa-user')
- ->addEntityLink('entity', 'Entity', 'fa fa-user')
+ ->addEntityLink('entity', 'Entity', logo: 'fas-user')
# Regular (outline) icons
- ->addEntityLink('entity', 'Entity', 'far fa-envelope')
- ->addEntityLink('entity', 'Entity', 'fa fa-envelope-o')
+ ->addEntityLink('entity', 'Entity', logo: 'far-envelope')
# Brand icons
- ->addEntityLink('entity', 'Entity', 'fa fa-github')
- ->addEntityLink('entity', 'Entity', 'fab fa-github')
+ ->addEntityLink('entity', 'Entity', logo: 'fab-github')
If you were using old fontawesome 4 icons you may need to rename them.
No more Bootstrap.css / Font awesome classes
You may be using Custom HTML (entity list row, editor embeds, form HTML field, form Autocomplete item template, page alerts) with CSS classes that was present in Sharp 8.x but that don't exist anymore:
- If you were using bootstrap classes like
row
/col
/badge
in HTML content. These are no longer available, you can either :- Convert to inline CSS (for bootstrap grid classes / utilities)
- Inject a custom CSS file as described here
- If you were using inline Font Awesome icons like
<i class="fas fa-user">
- Using blade-fontawesome component like :
<x-fas-user style="width: 1rem; height: 1rem" />
. In Sharp 9.x all templates are now Blade. - For
<i class="fas fa-user">
inside a custom transformer of an EntityList field, you must now doBlade::render('<x-fas-user style="width: 1rem; height: 1rem" />')
- Using blade-fontawesome component like :
Page Alerts (aka global messages) are not based on Vue templates anymore
This part has been entirely rewritten, and will need substantial changes in your code.
In 8.x and below, you were asked to configure page alerts in the buildConfig()
method; and if your page alert was displaying dynamic data, you had to use a custom transformer to inject the data in the page alert. All of this was removed, in favor of a much simpler "back only" system. Here’s an example of a page alert in a Show Page (this is the same in Form, Dashboard, Entity List, Embed and Command cases):
class MyShow extends SharpShow
{
// ...
protected function buildPageAlert(PageAlert $pageAlert): void
{
$pageAlert
->setLevelInfo()
->setMessage(function (array $data) {
return $data['is_planned']
? 'This post is planned for publication, on ' . $data['published_at']
: null;
});
}
}
As you can see, this new buildPageAlert()
method takes a PageAlert
object as parameter to work with. You'll have access to the $data
array returned by your find()
or getListData()
method, to inject dynamic data in your page alert if needed. Vue templates are no longer handled, as the page alert is now rendered on the back only.
See global page alert documentation for more detail.
Related models handling in custom transformers was fixed (and potentially breaking)
This bug fix potentially brings a breaking change: if you were using a custom transformer to handle related models, you may have to update it.
Here’s code which will work in Sharp 8.x and below:
$this
->setCustomTransformer('customer:name', function ($value, $instance, $attribute) {
return $instance->customer->name; // $instance is the Order
})
->transform(Order::find(1))
Is has to be rewritten like this in Sharp 9.x:
$this
->setCustomTransformer('customer:name', function ($value, $instance, $attribute) {
return $instance->name; // $instance is the Customer, as it should be.
})
->transform(Order::find(1))
The main difference is that the $instance
parameter refers to the related model, not the main model anymore. To summarize:
In 8.x:
$value: 'Joe Doe'
$instance: // the Order instance
$attribute: 'customer:name'
In 9.x:
$value: 'Joe Doe'
$instance: // the **Customer** instance
$attribute: 'name'
Thumbnails custom filters must be refactored to Modifiers
First, if you defined custom filters classes for your thumbnails, you must refactor it to the new ThumbnailModifier API, which is very close:
In 8.x
class MyFilter extends ThumbnailFilter
{
public function applyFilter(Image $image): Image
{
// ...
}
}
In 9.x
use Code16\Sharp\Form\Eloquent\Uploads\Thumbnails\ThumbnailModifier;
use Intervention\Image\Interfaces\ImageInterface;
class MyModifier extends ThumbnailModifier
{
public function apply(ImageInterface $image): ImageInterface
{
// ...
}
}
And secondly, in 9.x you can’t pass modifier's parameters as an array anymore:
In 8.x
$book->cover->thumbnail(100, 100, ['fit'=>['w'=>100, 'h'=>100]]);
In 9.x
$book->cover->thumbnail(100, 100, [new FitModifier(100, 100)]);
// or with the new fluent API
$book->cover->thumbnail()
->addModifier(new FitModifier(100, 100))
->make();
currentSharpRequest()
is now deprecated in favor of sharp()->context()
helper
The currentSharpRequest()
helper is now deprecated, and will be entirely removed in a future version. You should migrate your code to use the sharp()->context()
helper instead (see the dedicated documentation).
SharpAuthenticationCheckHandler
is now deprecated in favor of viewSharp
Gate
The use of a SharpAuthenticationCheckHandler
is now deprecated, and will be entirely removed in a future version. You should migrate your handler to a Gate:
In 8.x:
class MySharpAuthenticationCheckHandler implements SharpAuthenticationCheckHandler
{
public function check(Authenticatable $user): bool;
{
return $user->is_sharp_admin;
}
}
In 9.x:
class AppServiceProvider extends ServiceProvider
{
// ...
public function boot(): void
{
Gate::define('viewSharp', fn ($user) => $user->is_sharp_admin);
}
}
TIP
You should place this code in the new Sharp dedicated Service Provider you will create to configure your Sharp app, overriding the declareAccessGate()
method. See the dedicated documentation.
Next, the sharp.auth.check_handler
config key can be safely removed from your config/sharp.php
file (in case you have not yet migrated to the dedicated builder class, see above), along with the SharpAuthenticationCheckHandler
implementation class.
Injected CSS must now be loaded with the SharpConfigBuilder
In 8.x,
// config/sharp.php
return [
'extensions' => [
'assets' => [
'strategy' => 'vite',
'head' => [
'resources/css/sharp.css',
],
],
],
];
In 9.x :
class MySharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->loadViteAssets(['resources/css/sharp.css']) // to load a CSS file built with Vite
->loadStaticCss(asset('/css/sharp.css')) // Or to load a static CSS file
}
}
All test assertions were removed
All assertions, like for instance assertSharpHasAuthorization
, were removed because they were clumsy and not really useful. You must remove them from your tests, and use standard comparisons instead — although in real world, it’s easier and cleaner to just check the return status (ie: assertOk()
) and check, if needed, the consequences in the database directly.
This means you also need to remove all $this->initSharpAssertions()
calls from your tests.
Of course, the test helpers remain available, see the dedicated testing documentation.
Dashboard
SharpWidgetPanel
s are now based on blade template
In a similar way to Page Alerts, we abandoned Vue templates for custom SharpWidgetPanel
s in favor of blade templates. This is a breaking change, as the setTemplatePath(...)
and setInlineTemplate(...)
methods were removed, placed by a unique setTemplate(View $template)
.
There's almost nothing to change on the PHP side:
In 8.x:
class MyDashboard extends SharpDashboard
{
// ...
protected function buildWidgets(WidgetsContainer $widgetsContainer): void
{
$widgetsContainer
->addWidget(
SharpPanelWidget::make('my_custom_panel')
->setTitle('My custom panel')
->setTemplatePath('sharp.templates.my_template') // Must be an existing **vue file**
);
}
}
In 9.x:
class MyDashboard extends SharpDashboard
{
// ...
protected function buildWidgets(WidgetsContainer $widgetsContainer): void
{
$widgetsContainer
->addWidget(
SharpPanelWidget::make('my_custom_panel')
->setTitle('My custom panel')
->setTemplate(view('sharp.templates.my_template')) // Must be an existing **blade view**
);
}
}
The main change is the template itself, which must be a blade view now.
See panel widget documentation for more detail.
Entity Lists
Entity Lists have a new authorization: reorder
Previously the reorder
authorization was handled by the update
authorization, which can lead to unwanted effects. You should now declare a specific reorder
authorization in your Policies:
class PostPolicy extends SharpEntityPolicy
{
public function reorder($user): bool
{
return $user->isEditor();
}
// ...
}
Entity List's setWidth()
method as a new signature (non-breaking change: old signature is still supported)
The ->setWith($width)
method now expects a percentage value, expressed as a string (eg: '20'
or '20%'
), a float (eg: .2
for 20%) or an integer (eg: 20
for 20%). The old signature use to accept a 1 to 12 integer (12-grid): it is still supported (Sharp will transform a 6 in 50%), but deprecated, and you are strongly encourage to migrate to the new signature.
Methods to handle Entity List columns width on small screen were deprecated
The ->setWithOnSmallScreen($width)
and ->setWithOnSmallScreenFill()
methods were deprecated, because they are no more used in the new front table UI system. You can safely remove them, Sharp will rely on the setWidth($width)
method, or, even easier, will deduce width based on content like a regular table.
The ->hideOnSmallScreens()
method remains.
All filters must be declared in order to be used
In Sharp 8.x it was possible, in an Embedded Entity List (EEL) case, to use a filter without declaring it. This was a kind of bug, and has been fixed in 9.x: all filters must be declared in the getFilters()
method.
Consider this code in 8.x, where we have a PostShow
that embeds a PostBlockList
as an EEL:
class PostShow extends SharpShow
{
protected function buildShowFields(FieldsContainer $showFields): void
{
$showFields
->addField(SharpShowTextField::make('title')->setLabel('Title'))
->addField(
SharpShowEntityListField::make('blocks')
->setLabel('Blocks')
->hideFilterWithValue('post', fn($instanceId) => $instanceId)
);
}
// ...
}
class PostBlockList extends SharpEntityList
{
// ...
protected function getFilters(): ?array
{
return [
// Nothing there
];
}
public function getListData(): array|Arrayable
{
return $this->transform(
PostBlock::query()
->where('post_id', $this->queryParams->filterFor('post'))
->get()
);
}
}
We can see that PostBlockList
does not define any Filter, but uses one in the getListData()
method, valued by the PostShow
via hideFilterWithValue()
. In 9.x, this won't work as the Filter must be declared in the getFilters()
method. There is a new way to quickly declare such Filters that are not meant to be shown to the user, HiddenFiler
:
In 9.x
use \Code16\Sharp\EntityList\Filters\HiddenFilter;
class PostBlockList extends SharpEntityList
{
// ...
protected function getFilters(): ?array
{
return [
HiddenFilter::make('post')
];
}
// ... The rest is the same
}
You can of course instead declare a real Filter.
Select filter configureTemplate()
has been dropped
If you were using this method, you must do the string transformation in the label of each value.
New performance optimization for Commands and Policies in Entity List (n+1)
This is not a breaking change, in fact you can ignore this step entirely, but since it's can lead to a significative performance boost, this is worth mentioning: you can now quite easily implement a caching mechanism of instances for your Commands and Policies in Entity List.
Forms & Shows
Form and Show layout methods were renamed (old ones are deprecated)
The ->withSingleField()
method was deprecated, in favor of:
->withField(string $fieldKey)
for simple fields->withListField(string $fieldKey, Closure $subLayoutCallback)
for List fields, which requires a sub-layout handled by a callback.
The method ->withFields(string ...$fieldKeys)
, used for multiple fields layout, remains unchanged.
Form and Show Fields are now formatted even if you don’t transform them
This shouldn’t cause any trouble, as this is a fix, but it could break unorthodox code: field formatters (which are used to format the field value for the frontend) are now properly and always called before displaying data to the front, even if you don’t transform your data with $this->transform()
method.
Forms
New validation system (and deprecation of the old one)
The validation system was odd, for legacy reasons. In 9.x, it has been rewritten to be in phase with Laravel and to be more consistent:
- validation rules can now be defined in a
rules()
method of the form / command class, - or with a
->validate($data, $rules)
call before update / store. - The
$formValidatorClass
property usage, in aSharpForm
, is now deprecated (you are strongly encouraged to migrate to therules()
method instead).
This code in 8.x:
class PostForm extends SharpForm
{
protected ?string $formValidatorClass = PostFormValidator::class;
// ...
}
class PostFormValidator extends SharpFormRequest
{
public function rules(): array
{
return [
'title' => 'required',
'content' => 'required',
];
}
}
Should be rewritten in this in 9.x:
class PostForm extends SharpForm
{
public function rules(): array
{
return [
'title' => 'required',
'content' => 'required',
];
}
// ...
}
Or:
class PostForm extends SharpForm
{
// ...
public function update($id, array $data)
{
$this->validate($data, [
'title' => 'required',
'content' => 'required',
]);
// ...
}
}
This version brings two huge benefits (besides the fact that it's clearer):
- the "delayed creation" thing is gone (hooray!): the
{id}
parameter in aSharpFormUploadField
storageBasePath isn't anymore an issue in creation case as Sharp will no longer call theupdate()
method twice. - Validation is now called AFTER data formatters, even in
SharpForm
(it was already the case withCommand
).
Breaking changes: the 8.x and below validation is still allowed, but deprecated.
If you decide to migrate (and you should), pay attention to:
- remove special workarounds you may have done to handle the "delayed creation" thing,
- remove the
.text
suffix you may have added forSharpFormEditorField
validation rules.
If you decide not to migrate just now, you should ensure that the \Code16\Sharp\Http\Middleware\Api\BindSharpValidationResolver
middleware in added to the api
group:
either in the (deprecated) config file:
// config/sharp.php
return [
'middleware' => [
//...
'api' => [
// ...
\Code16\Sharp\Http\Middleware\Api\BindSharpValidationResolver::class,
],
],
]
... or in the shinny new config builder:
class MySharpServiceProvider extends SharpAppServiceProvider
{
protected function configureSharp(SharpConfigBuilder $config): void
{
$config
->appendToMiddlewareApiGroup(
\Code16\Sharp\Http\Middleware\Api\BindSharpValidationResolver::class
)
// ...
}
}
Localization feature was removed for SharpFormSelectField
, SharpFormTagsField
and SharpFormAutocompleteField
fields
Those fields could be localized in 8.x in a weird way: labels were localized, but not values. This was really misleading, so we decided to remove entirely this behavior in 9.x. The only real impact should be to remove setLocalized() calls in your code for these fields.
SharpFormGeolocationField
using Google Maps API must now provide a Map ID
Sharp 9.x now uses Advanced Markers which requires a Map ID, register it with the following method of the field :
class PostForm extends SharpForm
{
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields->addField(
SharpFormGeolocationField::make('position')
->setMapsProvider('gmaps')
->setApiKey('...')
->setGoogleMapsMapId('...') // new method
);
}
}
SharpFormAutocompleteFormField
was rewritten and need to be migrated
First, the SharpFormAutocompleteFormField
class was split into two classes: SharpFormAutocompleteLocalField
and SharpFormAutocompleteRemoteField
, to clearly separate these two different use cases.
Second, Vue templates must be migrated to Blade templates (similar to the SharpWidgetPanel
or Page Alerts migrations). You can either pass a view name or a blade template directly to the newly named setListItemTemplate()
and setResultItemTemplate()
methods (the old setListItemInlineTemplate()
, setListItemTemplatePath()
, setResultItemInlineTemplate()
and setResultItemTemplatePath()
were removed).
The setAdditionalTemplateData()
method was also removed, in favor of a more straightforward way to pass additional data to the template.
Example in 8.x:
class PostForm extends SharpForm
{
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields
->addField(
SharpFormAutocompleteField::make('author_id', 'remote')
->setRemoteEndpoint('/api/admin/users')
->setListItemInlineTemplate('{{name}}')
->setResultItemInlineTemplate('{{name}}')
)
->addField(
SharpFormAutocompleteField::make('category_id', 'local')
->setLocalValues([
1 => 'Category 1',
2 => 'Category 2',
3 => 'Category 3',
])
)
->addField(
// ...
);
}
// ...
}
In 9.x:
class PostForm extends SharpForm
{
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields
->addField(
SharpFormAutocompleteRemoteField::make('author_id')
->setRemoteEndpoint('/api/admin/users')
->setListItemTemplate('{{$name}}')
)
->addField(
SharpFormAutocompleteLocalField::make('category_id')
->setLocalValues([
1 => 'Category 1',
2 => 'Category 2',
3 => 'Category 3',
])
)
->addField(
// ...
);
}
// ...
}
Finally, there is a big evolution which concerns the remote autocomplete endpoint: your 8.x implementation should still work, but you should note that:
- you can now directly write the autocomplete endpoint as a callback closure in the field (no need to use a dedicated route + controller),
- external endpoint URLs aren’t supported anymore (you must write a wrapper around this external endpoint, either as a route + controller or via the new callback option).
Example in 8.x:
class PostForm extends SharpForm
{
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields
->addField(
SharpFormAutocompleteField::make('author_id', 'remote')
->setRemoteEndpoint('/api/admin/users')
->setListItemInlineTemplate('{{name}}')
->setResultItemInlineTemplate('{{name}}')
);
}
// ...
}
In 9.x:
class PostForm extends SharpForm
{
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields
->addField(
SharpFormAutocompleteRemoteField::make('author_id')
->setRemoteCallback(function ($search) {
return User::where('name', 'like', "%$search%")->get();
})
->setListItemTemplate('{{$name}}')
);
}
// ...
}
SharpFormUploadField
’s image related methods were renamed
This isn't a breaking change, since the old methods are still available, but deprecated. You should migrate to the new methods:
setFileFilterImage()
->setImageOnly()
setCropRatio()
=setImageCropRatio()
shouldOptimizeImage()
=setImageOptimize()
setTransformable()
=setImageTransformable()
setCompactThumbnail()
=setImageCompactThumbnail()
and in addition:
setFilterFilter()
->setAllowedExtensions()
The API for embedded uploads in Editor field was rewritten
The SharpFormEditorField
no longer has all the upload-related methods directly in the class. Instead, you must use a new SharpFormEditorUpload
builder class, passed as a parameter to the allowUploads()
method.
In 8.x:
// in a SharpForm
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields->addField(
SharpFormEditorField::make('content')
->setMaxLength(1000)
->setToolbar([
SharpFormEditorField::B,
SharpFormEditorField::A,
SharpFormEditorField::UPLOAD,
])
->setStorageDisk('local')
->setStorageBasePath('data/posts/{id}/embed'),
)
);
}
In 9.x:
// in a SharpForm
public function buildFormFields(FieldsContainer $formFields): void
{
$formFields->addField(
SharpFormEditorField::make('content')
->setMaxLength(1000)
->setToolbar([
SharpFormEditorField::B,
SharpFormEditorField::A,
SharpFormEditorField::UPLOAD,
])
->allowUploads(
SharpFormEditorUpload::make()
->setStorageDisk('local')
->setStorageBasePath('data/posts/{id}/embed')
);
);
}
New markup for Embedded uploads (in Editor field)
If you are using SharpFormEditorField
uploads, you will need migrate <x-sharp-image>
and <x-sharp-file>
elements in the content, meaning in the database. Sharp provides a helper trait intended to be used in your migration like this:
use Code16\Sharp\Form\Eloquent\Migrations\MigrateEditorContentsForSharp9;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
new class extends Migration
{
use MigrateEditorContentsForSharp9;
public function up(): void
{
$this->updateEditorContentOf(DB::table('posts'), ['content']);
}
}
Editor embeds has now blade templates
Like Autocomplete / Dashboard Widget panel, Editor embeds must now be blade inline string or a view('...')
:
Inline templates
Inline templates in 8.x :
public function buildEmbedConfig(): void
{
$this
->configureFormInlineTemplate('<div v-if="online">{{ title }}</div>')
->configureShowInlineTemplate('<div v-if="online">{{ title }}</div>');
}
Inline templates in 9.x :
public function buildEmbedConfig(): void
{
$this
// if only one template is defined (for both form & show)
->configureTemplate('@if($online) <div>{{ $title }}</div> @endif')
// if form & show has 2 different templates
->configureFormTemplate('@if($online) <div>{{ $title }}</div> @endif')
->configureShowTemplate('@if($online) <div>{{ $title }}</div> @endif');
}
Path templates
Path templates in 8.x :
public function buildEmbedConfig(): void
{
$this
->configureFormTemplatePath('sharp/embed.vue')
->configureShowTemplatePath('sharp/embed.vue');
}
Path templates in 9.x :
public function buildEmbedConfig(): void
{
$this
// if only one template is defined (for both form & show)
->configureTemplate(view('sharp.embed'))
// if form & show has 2 different templates
->configureFormTemplate(view('sharp.embed'))
->configureShowTemplate(view('sharp.embed'));
}
SharpFormListField
collapsed items template feature was removed
setCollapsedItemInlineTemplate()
& setCollapsedItemTemplatePath()
methods was removed due to limited usage and general migration into blade templates.
SharpFormHtmlField
has migrated to blade templates
setInlineTemplate()
& setTemplatePath()
must be converted to :
setTemplate('blade template string')
orsetTemplate(view('sharp.form-field'))
.
See field page for more information.