@php use KFramework\Components\Visual\Button; use KFramework\Components\Visual\ButtonsGroup; use KFramework\Helpers\ReflectionHelper; use KFramework\Helpers\RolesHelper; use Laravel\SerializableClosure\SerializableClosure; $groupable = false; $groups = []; $searchable = false; $hideableSchema = []; $searchableCols = []; $columnsLabel = []; if(!empty($schema)) { foreach($schema as $item) { $itemHidden = $item->hidden ?? false; $itemAuthorize = $item->authorize ?? null; if($itemHidden instanceof SerializableClosure || $itemHidden instanceof \Closure) { $itemHidden = ReflectionHelper::reflectAnything($itemHidden, [], 'hidden'); } if($itemAuthorize instanceof SerializableClosure || $itemAuthorize instanceof \Closure) { $itemAuthorize = ReflectionHelper::reflectAnything($itemAuthorize, [], 'authorize'); } if($itemHidden) { continue; } if($itemAuthorize === false) { continue; } if(config('k-framework.roles.enabled', false) && isset($itemAuthorize) && !RolesHelper::hasPermission($itemAuthorize)) { continue; } if(isset($item->groupable) && $item->groupable) { $groupable = true; $groups[$item->name] = ($item->label ?? $item->name); } if(isset($item->searchable) && $item->searchable) { $searchable = true; $searchableCols[$item->name] = $item->label ?? $item->name; } $columnsLabel[$item->name] = $item->label ?? $item->name; } } foreach($columnsLabel as $key => $col) { $hideableSchema[] = \KFramework\Components\Visual\Button::make($col) ->setType('badge') ->setColor('primary') ->setPreIcon('eye-outline') ->setOnClick('kfwTableHideColumn(\'' . $uuid .'\',\'' . $key .'\')'); } @endphp
@if(!empty($headerSchema) || $downloadable || $printable || $hideableColumns || $groupable || (isset($customFilters) && isset($query)) || $advancedSearch || $saveState || $searchable) @php $headerSchemaModals = []; if(!empty($headerSchema)) { foreach($headerSchema as $component) { if(is_object($component) && method_exists($component, 'setCustomProperty')) { $component->setCustomProperty('kfw_table_uuid', $uuid); } if($component instanceof \KFramework\Components\Visual\Button) { if(!$component->callbacksExecuted) { $component->executeCallbacks(); } if($component->modal instanceof \KFramework\Components\Visual\Modal) { $component->modal->setCustomProperty('kfw_table_uuid', $uuid); $headerSchemaModals[] = $component->modal; $component->setModal($component->modal->uuid); } } elseif($component instanceof \KFramework\Components\Visual\ButtonsGroup && !empty($component->schema)) { foreach($component->schema as $groupComponent) { if(is_object($groupComponent) && method_exists($groupComponent, 'setCustomProperty')) { $groupComponent->setCustomProperty('kfw_table_uuid', $uuid); } if($groupComponent instanceof \KFramework\Components\Visual\Button) { if(!$groupComponent->callbacksExecuted) { $groupComponent->executeCallbacks(); } if($groupComponent->modal instanceof \KFramework\Components\Visual\Modal) { $groupComponent->modal->setCustomProperty('kfw_table_uuid', $uuid); $headerSchemaModals[] = $groupComponent->modal; $groupComponent->setModal($groupComponent->modal->uuid); } } } } } } if(isset($customFilters) && isset($query) && $customFilters instanceof \Laravel\SerializableClosure\SerializableClosure) { $customFilters = \KFramework\Helpers\ReflectionHelper::reflectClosure($customFilters->getClosure(), [ 'originalQuery' => \KFramework\Helpers\QueryHelper::unserialize($query), 'tableUUID' => $uuid ]); } $mobileControlsSchema = []; if($searchable) { $mobileControlsSchema[] = ''; } if($groupable) { $mobileControlsSchema[] = '
' . \KFramework\Components\Forms\Select::make('group-table') ->setOptions($groups) ->setClasses(['simple-select']) ->setPlaceholder(__('kfw::table.no_group')) ->setLabel(__('kfw::table.group_by')) . '
'; } if($saveState && (isset($id) || isset($name))) { $mobileControlsSchema[] = \KFramework\Components\Visual\Button::make() ->setPreIcon('backup-restore') ->setLabel(__('kfw::table.reset')) ->setOnClick('kfwTableResetState(\'' . ($id ?? $name) . '\')'); } if($downloadable) { $mobileControlsSchema[] = \KFramework\Components\Visual\ButtonsGroup::make() ->setPreIcon('download-outline') ->setLabel(__('kfw::table.download')) ->setExtraAttributes([ 'style' => 'background: rgba(var(--success-rgb), 0.1)' ]) ->setSchema([ \KFramework\Components\Visual\Button::make('CSV')->setPreIcon('file-delimited-outline') ->setType('badge') ->setClasses(['download-table-csv']) ->setColor('warning'), \KFramework\Components\Visual\Button::make('XLSX')->setPreIcon('file-excel-outline') ->setType('badge') ->setClasses(['download-table-xlsx']) ->setColor('success'), \KFramework\Components\Visual\Button::make('PDF')->setPreIcon('file-pdf-box') ->setType('badge') ->setClasses(['download-table-pdf']) ->setColor('danger') ]); } if($printable) { $mobileControlsSchema[] = \KFramework\Components\Visual\Button::make() ->setPreIcon('printer-outline') ->setLabel(__('kfw::table.print')) ->setClasses(['print-table']) ->setExtraAttributes([ 'style' => 'background: rgba(var(--warning-rgb), 0.1)' ]); } if($hideableColumns) { $mobileControlsSchema[] = \KFramework\Components\Visual\ButtonsGroup::make() ->setPreIcon('view-column-outline') ->setLabel(__('kfw::table.hide_columns')) ->setExtraAttributes([ 'style' => 'background: rgba(var(--primary-rgb), 0.1)' ]) ->setSchema($hideableSchema); } if(isset($customFilters) && isset($query)) { $mobileControlsSchema[] = \KFramework\Components\Visual\Button::make() ->setPreIcon('filter-outline') ->setLabel(__('kfw::table.customized_filters')) ->setModal('table_custom_filters_' . $uuid); } if($advancedSearch) { $mobileControlsSchema[] = \KFramework\Components\Visual\Button::make() ->setPreIcon('magnify-plus-outline') ->setLabel(__('kfw::table.advanced_search')) ->setModal('table_searchBuilder_' . $uuid); } @endphp
@if(!empty($headerSchemaModals)) @foreach($headerSchemaModals as $modal) {!! $modal !!} @endforeach @endif @if(!empty($headerSchema) || !empty($mobileControlsSchema))
@if(!empty($headerSchema)) {!! \KFramework\Components\Visual\ButtonsGroup::make() ->setType('secondary') ->setPreIcon('plus-outline') ->setSchema($headerSchema) !!} @endif @if(!empty($mobileControlsSchema)) {!! \KFramework\Components\Visual\ButtonsGroup::make() ->setType('secondary') ->setPreIcon('cog-outline') ->setSchema($mobileControlsSchema) !!} @endif
@endif @if(!empty($headerSchema))
@foreach($headerSchema as $component) {!! $component !!} @endforeach
@endif @if($downloadable || $printable || $hideableColumns || $groupable || (isset($customFilters) && isset($query)) || $advancedSearch || $saveState || $searchable)
@if($groupable)
{!! \KFramework\Components\Forms\Select::make('group-table') ->setOptions($groups) ->setClasses(['simple-select']) ->setPlaceholder(__('kfw::table.no_group')) ->setLabel(__('kfw::table.group_by')) !!}
@endif
@if($downloadable || $printable || $hideableColumns || $saveState)
@if($saveState && (isset($id) || isset($name))) {!! \KFramework\Components\Visual\Button::make() ->setPreIcon('backup-restore') ->setHint(__('kfw::table.reset')) ->setOnClick('kfwTableResetState(\'' . ($id ?? $name) . '\')') !!} @endif @if($downloadable) {!! \KFramework\Components\Visual\ButtonsGroup::make() ->setPreIcon('download-outline') ->setExtraAttributes([ 'style' => 'background: rgba(var(--success-rgb), 0.1)' ]) ->setHint(__('kfw::table.download')) ->setSchema([ \KFramework\Components\Visual\Button::make('CSV')->setPreIcon('file-delimited-outline') ->setType('badge') ->setClasses(['download-table-csv']) ->setColor('warning'), \KFramework\Components\Visual\Button::make('XLSX')->setPreIcon('file-excel-outline') ->setType('badge') ->setClasses(['download-table-xlsx']) ->setColor('success'), \KFramework\Components\Visual\Button::make('PDF')->setPreIcon('file-pdf-box') ->setType('badge') ->setClasses(['download-table-pdf']) ->setColor('danger') ]) !!} @endif @if($printable) {!! \KFramework\Components\Visual\Button::make() ->setHint(__('kfw::table.print')) ->setClasses(['print-table']) ->setExtraAttributes([ 'style' => 'background: rgba(var(--warning-rgb), 0.1)' ]) ->setPreIcon('printer-outline') !!} @endif @if($hideableColumns) {!! \KFramework\Components\Visual\ButtonsGroup::make() ->setPreIcon('view-column-outline') ->setExtraAttributes([ 'style' => 'background: rgba(var(--primary-rgb), 0.1)' ]) ->setHint(__('kfw::table.hide_columns')) ->setSchema($hideableSchema) !!} @endif
@endif @if(isset($customFilters) && isset($query)) {!! \KFramework\Components\Visual\Button::make() ->setPreIcon('filter-outline') ->setHint(__('kfw::table.customized_filters')) ->setModal('table_custom_filters_' . $uuid) !!} @endif @if($advancedSearch) {!! \KFramework\Components\Visual\Button::make() ->setPreIcon('magnify-plus-outline') ->setHint(__('kfw::table.advanced_search')) ->setModal('table_searchBuilder_' . $uuid) !!} @endif @if($searchable) @endif
@endif @if(isset($customFilters) && isset($query)) {!! \KFramework\Components\Visual\Modal::make('table_custom_filters_' . $uuid) ->setCustomProperty('kfw_table_uuid', $uuid) ->setLabel(__('kfw::table.customized_filters')) ->setDimension('medium-small') ->setSchema($customFilters) ->setAction(true) ->setDisableCancel() ->setDisableSubmit() !!} @endif @if($advancedSearch) @php $sbColTypes = []; $sbModel = null; $sbModelTable = null; try { if (isset($query) && is_object($query) && method_exists($query, 'getModel')) { $sbModel = $query->getModel(); $sbModelTable = method_exists($sbModel, 'getTable') ? $sbModel->getTable() : null; } } catch (\Throwable $e) { $sbModel = null; $sbModelTable = null; } foreach ($searchableCols as $sbColName => $sbColLabel) { $sbType = 'string'; try { if (is_string($sbColName) && $sbColName !== '') { if (!str_contains($sbColName, '.')) { if ($sbModelTable && \Illuminate\Support\Facades\Schema::hasColumn($sbModelTable, $sbColName)) { $sbType = (string) \Illuminate\Support\Facades\Schema::getColumnType($sbModelTable, $sbColName); } } else { $sbParts = array_values(array_filter(explode('.', $sbColName), fn ($p) => $p !== '')); if (count($sbParts) === 2 && \Illuminate\Support\Facades\Schema::hasColumn($sbParts[0], $sbParts[1])) { $sbType = (string) \Illuminate\Support\Facades\Schema::getColumnType($sbParts[0], $sbParts[1]); } elseif ($sbModel && count($sbParts) >= 2) { $sbRelField = array_pop($sbParts); $sbCurrent = $sbModel; foreach ($sbParts as $sbRel) { if (!method_exists($sbCurrent, $sbRel)) { $sbCurrent = null; break; } try { $sbRelation = $sbCurrent->$sbRel(); $sbCurrent = method_exists($sbRelation, 'getRelated') ? $sbRelation->getRelated() : null; if (!$sbCurrent) { break; } } catch (\Throwable $e) { $sbCurrent = null; break; } } if ($sbCurrent && method_exists($sbCurrent, 'getTable')) { $sbRelTable = $sbCurrent->getTable(); if (\Illuminate\Support\Facades\Schema::hasColumn($sbRelTable, $sbRelField)) { $sbType = (string) \Illuminate\Support\Facades\Schema::getColumnType($sbRelTable, $sbRelField); } } } } } } catch (\Throwable $e) { } $sbColTypes[$sbColName] = strtolower($sbType); } $sbKindOf = function ($col) use ($sbColTypes) { $t = strtolower((string) ($sbColTypes[$col] ?? 'string')); if (in_array($t, ['integer', 'int', 'bigint', 'smallint', 'tinyint', 'mediumint', 'decimal', 'numeric', 'float', 'double', 'real'], true)) { return 'numeric'; } if (in_array($t, ['date'], true)) { return 'date'; } if (in_array($t, ['datetime', 'datetimetz', 'timestamp'], true)) { return 'datetime'; } if (in_array($t, ['time', 'timetz'], true)) { return 'time'; } return 'text'; }; $sbInputTypeOf = function ($col) use ($sbKindOf) { return match ($sbKindOf($col)) { 'numeric' => 'number', 'date' => 'date', 'datetime' => 'datetime-local', 'time' => 'time', default => null, }; }; $sbTextConds = [ 'contains' => __('kfw::table.conditions.contains'), 'notContains' => __('kfw::table.conditions.notContains'), 'equals' => __('kfw::table.conditions.equals'), 'not' => __('kfw::table.conditions.not'), 'startsWith' => __('kfw::table.conditions.startsWith'), 'notStartsWith' => __('kfw::table.conditions.notStartsWith'), 'endsWith' => __('kfw::table.conditions.endsWith'), 'notEndsWith' => __('kfw::table.conditions.notEndsWith'), 'without' => __('kfw::table.conditions.without'), ]; $sbNumConds = [ 'equals' => __('kfw::table.conditions.equals'), 'not' => __('kfw::table.conditions.not'), 'gt' => __('kfw::table.conditions.gt'), 'gte' => __('kfw::table.conditions.gte'), 'lt' => __('kfw::table.conditions.lt'), 'lte' => __('kfw::table.conditions.lte'), 'between' => __('kfw::table.conditions.between'), 'notBetween' => __('kfw::table.conditions.notBetween'), ]; $sbDateConds = [ 'equals' => __('kfw::table.conditions.equals'), 'not' => __('kfw::table.conditions.not'), 'before' => __('kfw::table.conditions.before'), 'after' => __('kfw::table.conditions.after'), 'between' => __('kfw::table.conditions.between'), 'notBetween' => __('kfw::table.conditions.notBetween'), ]; $sbCondsOf = function ($col) use ($sbKindOf, $sbTextConds, $sbNumConds, $sbDateConds) { return match ($sbKindOf($col)) { 'numeric' => $sbNumConds, 'date', 'datetime', 'time' => $sbDateConds, default => $sbTextConds, }; }; $sbFirstCol = is_array($searchableCols) && !empty($searchableCols) ? array_key_first($searchableCols) : null; // Initial options stay complete (backward compatible); they are // narrowed to the column kind on change via updateOnChange + JS. $sbInitialConds = [ 'contains' => __('kfw::table.conditions.contains'), 'notContains' => __('kfw::table.conditions.notContains'), 'equals' => __('kfw::table.conditions.equals'), 'not' => __('kfw::table.conditions.not'), 'startsWith' => __('kfw::table.conditions.startsWith'), 'notStartsWith' => __('kfw::table.conditions.notStartsWith'), 'endsWith' => __('kfw::table.conditions.endsWith'), 'notEndsWith' => __('kfw::table.conditions.notEndsWith'), 'gt' => __('kfw::table.conditions.gt'), 'gte' => __('kfw::table.conditions.gte'), 'lt' => __('kfw::table.conditions.lt'), 'lte' => __('kfw::table.conditions.lte'), 'before' => __('kfw::table.conditions.before'), 'after' => __('kfw::table.conditions.after'), 'between' => __('kfw::table.conditions.between'), 'notBetween' => __('kfw::table.conditions.notBetween'), 'without' => __('kfw::table.conditions.without'), ]; $sbInitialInputType = $sbFirstCol ? $sbInputTypeOf($sbFirstCol) : null; @endphp {!! \KFramework\Components\Visual\Modal::make('table_searchBuilder_' . $uuid) ->setCustomProperty('kfw_table_uuid', $uuid) ->setLabel(__('kfw::table.advanced_search')) ->setURL('') ->setDimension('large') ->setDisableSubmit() ->setDisableCancel() ->setSchema([ \KFramework\Components\Forms\Repeater::make('searchBuilder') ->setMinRows(0) ->setSchema([ \KFramework\Components\Forms\Select::make('column') ->setLabel(__('kfw::table.column')) ->setOptions($searchableCols) ->setUpdateOnChange(function ($fields) use ($sbCondsOf, $sbInputTypeOf) { $col = $fields['column'] ?? null; $cond = $fields['condition'] ?? null; $needsTwo = in_array($cond, ['between', 'notBetween'], true); $inputType = $sbInputTypeOf($col); return [ \KFramework\Helpers\FormHelper\UpdateField::make('condition')->setOptions($sbCondsOf($col)), \KFramework\Helpers\FormHelper\UpdateField::make('value')->setType($inputType), \KFramework\Helpers\FormHelper\UpdateField::make('value2')->setType($inputType)->setHidden(!$needsTwo)->setDisabled(!$needsTwo), ]; }), \KFramework\Components\Forms\Select::make('condition') ->setLabel(__('kfw::table.condition')) ->setUpdateOnChange(function ($fields) use ($sbInputTypeOf) { $col = $fields['column'] ?? null; $cond = $fields['condition'] ?? null; $needsTwo = in_array($cond, ['between', 'notBetween'], true); $inputType = $sbInputTypeOf($col); return [ \KFramework\Helpers\FormHelper\UpdateField::make('value')->setType($inputType), \KFramework\Helpers\FormHelper\UpdateField::make('value2')->setType($inputType)->setHidden(!$needsTwo)->setDisabled(!$needsTwo), ]; }) ->setOptions($sbInitialConds), \KFramework\Components\Forms\Input::make('value') ->setLabel(__('kfw::table.value')) ->setType($sbInitialInputType), \KFramework\Components\Forms\Input::make('value2') ->setLabel(__('kfw::table.value')) ->setType($sbInitialInputType) ->setHidden() ->setDisabled() ]) ->setColumns(4) ]) !!} @endif
@endif
@if(!empty($selectableSchema))
@foreach($selectableSchema as $component) @php if(is_object($component) && method_exists($component,'setCustomProperty')) { $component->setCustomProperty('kfw_table_uuid', $uuid); $component->setCustomProperty('kfw_table_selectable_component', true); } @endphp {!! $component !!} @endforeach
@endif @if(!empty($selectableSchema)) @endif @if(isset($accordableSchema)) @endif @if($buttons && !empty($buttons)) @endif @foreach($schema as $column) {!! $column->setCustomProperty('kfw_orderable_column_table', $orderableColumns) !!} @endforeach @if(isset($values) && !empty($values) && !isset($query)) @foreach($values as $value) @if($buttons && !empty($buttons)) @endif @php $kfwFlexibleColumnsCount = collect($schema)->filter(function ($column) { return !(isset($column->maxContent) && $column->maxContent); })->count(); $kfwFlexibleColumnWidth = $kfwFlexibleColumnsCount > 0 ? (100 / $kfwFlexibleColumnsCount) . '%' : 'auto'; @endphp @foreach($schema as $column) @if(isset($column->value) && isset($column->name) && isset($value[$column->name])) @elseif(isset($column->name) && isset($value[$column->name])) @else @endif @endforeach @endforeach @endif
@php $buttonsHTML = '
'; foreach ($buttons as $button) { if (!is_object($button)) { continue; } $buttonInstance = clone $button; if ($buttonInstance instanceof Button) { $buttonInstance->setCustomProperty('kfw_original_uuid', $button->uuid); $buttonInstance->setCustomProperty('kfw_table_uuid', $uuid); } elseif ($buttonInstance instanceof ButtonsGroup && !empty($buttonInstance->schema)) { foreach ($buttonInstance->schema as $key => $groupButton) { if (is_object($groupButton)) { $groupButton->setCustomProperty('kfw_original_uuid', $button->schema[$key]->uuid); $groupButton->setCustomProperty('kfw_table_uuid', $uuid); } } } if (method_exists($buttonInstance, 'executeCallbacks')) { $buttonInstance->executeCallbacks([ 'record' => $value, ]); } $buttonsHTML .= $buttonInstance; } $buttonsHTML .= '
'; @endphp {!! $buttonsHTML !!}
maxContent) && $column->maxContent) style="width: max-content; min-width: max-content; max-width: max-content; white-space: nowrap;" @else style="width: {{ $kfwFlexibleColumnWidth }}; min-width: 0;" @endif>{!! \KFramework\Helpers\ReflectionHelper::reflectAnything($column->value, ['record' => $value]) !!}maxContent) && $column->maxContent) style="width: max-content; min-width: max-content; max-width: max-content; white-space: nowrap;" @else style="width: {{ $kfwFlexibleColumnWidth }}; min-width: 0;" @endif>{!! $value[$column->name] !!}maxContent) && $column->maxContent) style="width: max-content; min-width: max-content; max-width: max-content; white-space: nowrap;" @else style="width: {{ $kfwFlexibleColumnWidth }}; min-width: 0;" @endif>
@if($pageable) @endif