laravel / nova-issues

551 stars 36 forks source link

Repeater styling #6166

Open mrleblanc101 opened 5 months ago

mrleblanc101 commented 5 months ago

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 commented 5 months ago

Also, my field is show 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 commented 5 months ago

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

Navi2016 commented 5 months ago

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.

mrleblanc101 commented 5 months ago

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

stale[bot] commented 3 months ago

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.

mrleblanc101 commented 3 months ago

Not stale

sp4cecat commented 3 months ago

@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 commented 3 months ago

Which BTW I would like to see also

mrleblanc101 commented 3 months ago

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

caongan2 commented 2 months ago

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();

sp4cecat commented 2 months ago

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]...
christian-heiko commented 1 month ago

Any Update/Roadmap on this?

christian-heiko commented 1 month ago

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>
bergstar commented 1 month ago

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