nova-issues icon indicating copy to clipboard operation
nova-issues copied to clipboard

Repeater styling

Open mrleblanc101 opened this issue 1 year ago • 17 comments

  • Laravel Version: 10.41.0
  • Nova Version: 4.32.11
  • PHP Version: 8.1

Description:

Is it normal that the repeater trash icon is not uniform with the rest of nova ?

Screenshot 2024-01-25 at 12 36 31 AM Screenshot 2024-01-25 at 12 42 08 AM

mrleblanc101 avatar Jan 25 '24 05:01 mrleblanc101

Also, my field is shown in the edit view and save just fine.

Repeater::make(__('Links'), 'links')
    ->repeatables([
        \App\Nova\Repeater\ProjectLink::make()->confirmRemoval(),
    ])->asJson(),
Screenshot 2024-01-25 at 12 44 59 AM

But is it normal that my field is not shown in the detail view ?

Screenshot 2024-01-25 at 12 45 07 AM

mrleblanc101 avatar Jan 25 '24 05:01 mrleblanc101

The ->confirmRemoval() does not appear to do anything either 🤔

mrleblanc101 avatar Jan 25 '24 05:01 mrleblanc101

Having the same, seems weird it does not show anything when viewing the resource detail page. It should display an overview of the line items.

Navi2016 avatar Feb 05 '24 10:02 Navi2016

@Navi2016 Yeah I opened a PR to the docs, but they don't seem to care: https://github.com/laravel/nova-docs/pull/570.

mrleblanc101 avatar Feb 05 '24 17:02 mrleblanc101

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Mar 17 '24 16:03 stale[bot]

Not stale

mrleblanc101 avatar Mar 17 '24 16:03 mrleblanc101

@Navi2016 Yeah I opened a PR to the docs, but they don't seem to care: laravel/nova-docs#570.

I don't think it's a matter of not caring - it's not apparent from that pull request that you're wanting the repeater details to display in the detail view.

sp4cecat avatar Mar 27 '24 07:03 sp4cecat

Which BTW I would like to see also

sp4cecat avatar Mar 27 '24 07:03 sp4cecat

@sp4cecat The doc PR was to inform that the component was for display only but they closed it and didn't add any info about this in the doc

mrleblanc101 avatar Mar 27 '24 09:03 mrleblanc101

Text::make('Item content', 'line_items', function ($value, $resource, $attribute) { if ($value) { $value = json_decode($value); $arr = []; foreach ($value as $item) { $arr[] = $item->fields->item_content; } return implode("
", $arr); } })->asHtml();

caongan2 avatar Apr 25 '24 04:04 caongan2

Text::make('Item content', 'line_items', function ($value, $resource, $attribute) { if ($value) { $value = json_decode($value); $arr = []; foreach ($value as $item) { $arr[] = $item->fields->item_content; } return implode("", $arr); } })->asHtml();

Thanks for having a crack :)

jsondecode is not needed if you've cast the repeated field in your model file, ie:

protected $casts = [
	'line_items' => 'array',
];

And also the individual line item structure is a bit more complex than that -

- type (string)
- fields (array)
  \
    [key, value]...

sp4cecat avatar Apr 26 '24 06:04 sp4cecat

Any Update/Roadmap on this?

christian-heiko avatar May 14 '24 08:05 christian-heiko

Ive made a quick Shortcut where one can pass a Repeater to view it on Detail:

Usage:

Panel::make('Panel', [
     ...RepeaterDetailView::makeBoth(Repeater::make('Label', 'attribute'), $request)
]);

app/Nova/Fields/RepeaterDetailView.php

<?php

namespace App\Nova\Fields;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\Hidden;
use Laravel\Nova\Fields\Repeater;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;

class RepeaterDetailView {

    public static function makeBoth(Repeater $repeater, NovaRequest $request): array {
        return [
            $repeater,
            self::make($repeater, $request)
        ];
    }

    public static function make(Repeater $repeater, NovaRequest $request): Text {
        return Text::make(
            $repeater->name, function (Model $model) use ($repeater, $request): string {
                $items = $model->{$repeater->attribute};

                if (is_null($items)) return '';

                $tables = [];

                foreach ($items as $item) {
                    $type = $repeater->repeatables->findByKey($item['type']);
                    /** @var Collection<Field> $fields */
                    $fields = $type->fields($request);
                    $table = [
                        'headers' => [],
                        'rows' => [[]]
                    ];

                    foreach ($fields as $field) {
                        if ($field instanceof Hidden) continue;

                        $table['headers'][] = $field->name;
                        $table['rows'][0][] = $item['fields'][$field->attribute];
                    }
                    $tables[] = $table;
                }

                return implode(
                    '<br />',
                    array_map(
                        fn(array $table) => view('partials.table',
                            $table
                        )->render(),
                        $tables
                    )
                );
        })->onlyOnDetail()->asHtml();
    }

}

table.partials.php

<table class="table w-full divide-y divide-gray-100 dark:divide-gray-700 mb-6">
    <thead>
    <tr>
        @foreach($headers as $header)
            <th>{{$header}}</th>
        @endforeach
    </tr>
    </thead>
    <tbody class="divide-y divide-gray-100 dark:divide-gray-700">
    @foreach($rows as $row)
        <tr class="table-row">
            @foreach($row as $cell)
                <td class="">
                    {{ $cell }}
                </td>
            @endforeach
        </tr>
    @endforeach
    </tbody>
</table>

christian-heiko avatar May 14 '24 09:05 christian-heiko

This wasn't obvious for me, so posting for other who also might struggle with this issue.

Basically in your Nova/Resource file you can have both Repeater and HasMany:

            Repeater::make('Line Items')
                ->repeatables([
                    \App\Nova\Repeater\LineItem::make()
                ])
                ->asHasMany()
                ->showOnDetail(),

            HasMany::make('Line Items'),

However for some unknown reason, each calls a different functions in Model:

Repeater::make('Line Items') calls line_items()

but

HasMany::make('Line Items') calls lineItems()

You can however mitigate that by a few more arguments:

HasMany::make('Line Items', 'line_items', \App\Nova\LineItem::class),

This way you will see Repeater editor while editing and table view of when viewing.

Screenshot 2024-05-17 at 22 30 02

bergstar avatar May 17 '24 20:05 bergstar

I would also like to see the JSON column details on the resource page as mentioned in https://github.com/laravel/nova-issues/issues/6166#issuecomment-1909396838 by @mrleblanc101

shriramms99 avatar Jul 23 '24 14:07 shriramms99

+1

msucevan avatar Aug 02 '24 19:08 msucevan

Not totally sure if I just stack below this issue, but the name of the issue is 'Repeater styling' so here I go. I am trying to use the Repeater field as a block builder, but the select when having multiple repeaterables isn't that UX friendly.

Screenshot 2024-08-12 at 23 20 01

When having multiple types of repeatables the vue swaps to Dropdownmenu instead of InvertedButton. Only the DropdownMenu inside of the RepeaterField.vue is missing a width defination or the fallback width value of the DropdownMenu should be 'auto'.

In the current situation when nothing is defined it will be fixed to 120px. Which isn't a lot with also the icon before, and leaving therefor only space for about 7 character as label.

PaLemmen avatar Aug 12 '24 21:08 PaLemmen