From 784355c726b96bc01f81dca2dc8c17942e51afb1 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sun, 22 Nov 2020 19:00:06 +0100 Subject: [PATCH 01/61] Js routes, layout, menu --- src/Pckg/Generic/Entity/MenuItems.php | 7 ++++++- src/Pckg/Generic/Service/Generic.php | 13 ++++++++++--- src/Pckg/Generic/Service/Generic/Action.php | 13 +++++++++++-- src/Pckg/Generic/View/_foot.twig | 1 + 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/Pckg/Generic/Entity/MenuItems.php b/src/Pckg/Generic/Entity/MenuItems.php index 001f5d12..ca8dc333 100644 --- a/src/Pckg/Generic/Entity/MenuItems.php +++ b/src/Pckg/Generic/Entity/MenuItems.php @@ -19,7 +19,12 @@ public function boot() public function menuItems() { return $this->hasMany(MenuItems::class) - ->foreignKey('parent_id'); + ->foreignKey('parent_id'); + } + + public function menu() + { + return $this->belongsTo(Menus::class)->foreignKey('menu_id'); } } \ No newline at end of file diff --git a/src/Pckg/Generic/Service/Generic.php b/src/Pckg/Generic/Service/Generic.php index 4b7efa82..87f698cc 100644 --- a/src/Pckg/Generic/Service/Generic.php +++ b/src/Pckg/Generic/Service/Generic.php @@ -166,7 +166,7 @@ public function hasAction(array $actions = []) }); } - public function readRoute(Route $route, $resolvers = true) + public function readRoute(Route $route, $resolvers = true, $nativeResolvers = null) { $this->route = $route; @@ -175,7 +175,7 @@ public function readRoute(Route $route, $resolvers = true) */ $resolved = []; if ($resolvers && $route->resolvers) { - $router = router()->get(); + $router = is_null($nativeResolvers) ? router()->get() : $nativeResolvers; $decoded = @json_decode($route->resolvers, true); foreach ($decoded ?? [] as $key => $conf) { if (is_array($conf)) { @@ -614,9 +614,16 @@ public static function addRoutesFromDb() if ($route->layout && strpos($route->layout->template, 'frontend') !== false) { $tags->push('layout:frontend'); - $tags = $tags->unique(); } + /** + * Mark as Vue route. + */ + $tags->push('vue:route'); + $tags->push('session:close'); + $tags->push($route->id, 'generic:id'); + $tags->push('', 'vue:route:template'); + $tags = $tags->all(); $newRoute = [ diff --git a/src/Pckg/Generic/Service/Generic/Action.php b/src/Pckg/Generic/Service/Generic/Action.php index 4f647afc..768f3a75 100644 --- a/src/Pckg/Generic/Service/Generic/Action.php +++ b/src/Pckg/Generic/Service/Generic/Action.php @@ -60,13 +60,22 @@ public function toView(string $template, $data = []) */ public function toVue(string $component, $props = []) { + /** + * @var $generic Generic + */ + $generic = resolve(Generic::class); $mergedProps = []; + $action = $this->getAction(); foreach ($props as $prop => $value) { - $mergedProps[] = ' ' . $prop . '="' . (is_numeric($value) ? $value : (substr($prop, 0, 1) === ':' ? $value : htmlspecialchars(json_encode($value)))) . '"'; + if (is_numeric($value) || (is_string($prop) && substr($prop, 0, 1) === ':')) { + $mergedProps[] = ' ' . $prop . '="' . $value . '"'; + } else { + $mergedProps[] = ' :' . $prop . '="' . $generic->pushMetadata($action->pivot->id, $prop, $value) . '"'; + } } return '<' . $component . - ($this->getAction()->pivot ? ' :action-id="' . $this->getAction()->pivot->id . '"' : '') + ($action->pivot ? ' :action-id="' . $action->pivot->id . '"' : '') . implode(' ', $mergedProps) . '>'; } diff --git a/src/Pckg/Generic/View/_foot.twig b/src/Pckg/Generic/View/_foot.twig index c7d11ca0..4782ae7e 100644 --- a/src/Pckg/Generic/View/_foot.twig +++ b/src/Pckg/Generic/View/_foot.twig @@ -20,6 +20,7 @@ {{ _vueManager.getViews() | raw }} +{{ _assetManager.getMeta(['js'], ['page']) | raw }} {{ _assetManager.getMeta(['js'], ['php', 'vue', 'footer']) | raw }} {{ _metaManager.getMeta('footer') | raw }} {# google fonts #} From 084576c8f2aa63a9ef441fbcd55aee876574d45a Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Tue, 24 Nov 2020 14:02:17 +0100 Subject: [PATCH 02/61] Cleanup form, tables, vueify --- src/Pckg/Dynamic/Controller/Records.php | 103 ++++-------- src/Pckg/Dynamic/Form/Dynamic.php | 2 +- src/Pckg/Dynamic/Provider/Dynamic.php | 121 ++++++++------ src/Pckg/Dynamic/Record/Table.php | 19 +++ src/Pckg/Dynamic/Resolver/Table.php | 5 + src/Pckg/Dynamic/View/edit/singular.twig | 6 - src/Pckg/Dynamic/View/edit/singular.vue | 90 ++++++++++ src/Pckg/Dynamic/View/edit/tabs.twig | 5 - src/Pckg/Dynamic/public/less/dynamic.less | 4 +- src/Pckg/Generic/Service/Generic.php | 2 +- src/Pckg/Generic/Service/Generic/Action.php | 3 + src/Pckg/Maestro/Service/Tabelize.php | 2 +- src/Pckg/Maestro/View/_form.vue | 88 ++++++---- .../View/_pckg_dynamic_record_tabs.vue | 154 ++++++++++++++++++ src/Pckg/Maestro/View/_table.vue | 6 +- src/Pckg/Maestro/View/_table_actions.vue | 4 +- src/Pckg/Maestro/public/less/maestro.less | 5 +- 17 files changed, 441 insertions(+), 178 deletions(-) create mode 100644 src/Pckg/Dynamic/View/edit/singular.vue delete mode 100644 src/Pckg/Dynamic/View/edit/tabs.twig create mode 100644 src/Pckg/Maestro/View/_pckg_dynamic_record_tabs.vue diff --git a/src/Pckg/Dynamic/Controller/Records.php b/src/Pckg/Dynamic/Controller/Records.php index 8b161645..d79a77a2 100644 --- a/src/Pckg/Dynamic/Controller/Records.php +++ b/src/Pckg/Dynamic/Controller/Records.php @@ -21,6 +21,7 @@ use Pckg\Framework\Controller; use Pckg\Framework\Service\Plugin; use Pckg\Framework\View\Twig; +use Pckg\Generic\Service\Generic; use Pckg\Htmlbuilder\Datasource\Method\Request; use Pckg\Locale\Lang; use Pckg\Locale\Record\Language; @@ -289,6 +290,7 @@ public function getViewTableApiAction( 'record' => $tabelize->getRecordActionsArray(), ], 'table' => $tableRecord, + 'tabs' => $tableRecord->tabs, 'fields' => $tableRecord->fields->map(function(Field $field){ $data = $field->toArray(); @@ -326,47 +328,10 @@ public function getAddAction( Relation $relation = null, Record $foreign = null ) { - (new Tables())->joinPermissionTo('write') - ->where('id', $table->id) - ->oneOrFail(function(){ - $this->response()->unauthorized(); - }); - - if (!$table->listableFields->count()) { - $this->response()->notFound('Missing view field permissions.'); - } - - $tableEntity = $table->createEntity(); - $record = $record ? $tableEntity->transformRecordToEntities($record) : $tableEntity->getRecord(); - $record->setEntity($tableEntity); - - $form->setRelation($relation); - - if ($foreign && $relation->on_field_id) { - $record->{$relation->onField->field} = $foreign->id; - $form->setForeignFieldId($relation->on_field_id); - $form->setForeignRecord($relation->onTable->createEntity()->where('id', $foreign->id)->one()); - } - - $form->setTable($table); - $form->setRecord($record); - $form->initFields(); - $form->populateFromRecord($record); - - if ($tableEntity->isTranslatable()) { - $form->initLanguageFields(); - } - - if ($tableEntity->isPermissionable()) { - $form->initPermissionFields(); - } - - $formalize = $this->formalize($form, $record, $table->getFormTitle('Add')); - - vueManager()->addView('Pckg/Maestro:_formalize', ['formalize' => $formalize, 'form' => $form]); - - return view('edit/singular', [ - 'formalize' => $formalize, + return component('dynamic-singular', [ + ':table' => $table, + ':record' => $record, + ':actions' => [], ]); } @@ -526,34 +491,13 @@ public function getViewAction(Dynamic $form, Record $record, Table $table, Dynam public function getEditAction(Dynamic $form, Record $record, Table $table, DynamicService $dynamicService, $mode = 'edit') { - (new TableActions())->joinPermissionTo('execute') - ->where('dynamic_table_id', $table->id) - ->where('slug', $mode) - ->oneOrFail(function(){ - $this->response()->unauthorized(); - }); - - $this->seoManager()->setTitle(($form->isEditable() ? 'Edit' : 'View') . ' ' . $table->title . ' #' . - $record->id . ' - ' . config('site.title')); - - $listableFields = $table->listableFields; - if (!$listableFields->count()) { - $this->response()->notFound('Missing view field permissions.'); - } + // $this->seoManager()->setTitle(($form->isEditable() ? 'Edit' : 'View') . ' ' . $table->title . ' #' . $record->id . ' - ' . config('site.title')); $tableEntity = $table->createEntity(); - $dir = path('app_src') . implode(path('ds'), array_slice(explode('\\', get_class($tableEntity)), 0, -2)) . - path('ds') . 'View' . path('ds'); - Twig::addDir($dir); - - /*if (config('app') != config('app_parent')) { - $partial = implode(path('ds'), array_slice(explode('\\', get_class($tableEntity)), 0, -2)) . path('ds') . - 'View' . path('ds'); - $dir = path('apps') . config('app_parent') . path('ds') . 'src' . path('ds') . $partial; - Twig::addDir($dir); - }*/ + $dir = path('app_src') . implode(path('ds'), array_slice(explode('\\', get_class($tableEntity)), 0, -2)) . path('ds') . 'View' . path('ds'); + Twig::addDir($dir); Twig::addDir($dir . 'tabelize' . path('ds') . 'recordActions' . path('ds')); Twig::addDir($dir . 'tabelize' . path('ds') . 'entityActions' . path('ds')); @@ -610,22 +554,31 @@ public function getEditAction(Dynamic $form, Record $record, Table $table, Dynam ->setFieldTransformations($fieldTransformations) ->setDynamicRecord($record); + /** + * @T00D00 - this is one of the remaining .twig templates. + */ $this->vueManager() - // ->addView('Pckg/Maestro:_pckg_chart') ->addView('Pckg/Maestro:_pckg_maestro_actions_template', [ 'recordActions' => $actions, 'table' => $table->table, - ])->addView('Pckg/Maestro:_pckg_dynamic_record_tabs', [ - 'tabelize' => $tabelize, - 'formalize' => $formalize, - 'tabs' => $tabs, - 'table' => $table->table, - 'tabelizes' => $tabelizes, - 'functionizes' => $functionizes, - 'record' => $record, ]); - return view('edit/tabs', ['tabelize' => $tabelize]); + $relations = (new Relations())->where('on_table_id', $table->id) + ->where('dynamic_table_tab_id', null, 'IS NOT') + ->all(); + + /** + * Resolve record for the frontend. + * @var $generic Generic + */ + return component('pckg-dynamic-record-tabs', [ + ':record' => $tabelize->transformRecord($record), + ':table' => $table, + ':actions' => $actions, + ':tabs' => $tabs, + ':relations' => $relations, + ':mode' => $form->isEditable() ? 'edit' : 'view', + ]); } public function getTabAction(Record $record, Table $table, Tab $tab) diff --git a/src/Pckg/Dynamic/Form/Dynamic.php b/src/Pckg/Dynamic/Form/Dynamic.php index a909feda..b85a5c33 100644 --- a/src/Pckg/Dynamic/Form/Dynamic.php +++ b/src/Pckg/Dynamic/Form/Dynamic.php @@ -605,7 +605,7 @@ protected function createElementByType($type, $name, Field $field) 'table' => $field->hasOneSelectRelation->showTable, ]), 'data-refresh-url' => url('dynamic.records.field.selectList' . - ($this->record->id ? '' : '.none'), [ + ($this->record && $this->record->id ? '' : '.none'), [ 'table' => $this->table, 'field' => $field, 'record' => $this->record, diff --git a/src/Pckg/Dynamic/Provider/Dynamic.php b/src/Pckg/Dynamic/Provider/Dynamic.php index a9f74a9d..a94896ca 100644 --- a/src/Pckg/Dynamic/Provider/Dynamic.php +++ b/src/Pckg/Dynamic/Provider/Dynamic.php @@ -5,9 +5,11 @@ use Pckg\Dynamic\Controller\Records; use Pckg\Dynamic\Controller\Relations; use Pckg\Dynamic\Controller\View; +use Pckg\Dynamic\Entity\Tables; use Pckg\Dynamic\Middleware\RegisterDynamicAssets; use Pckg\Dynamic\Middleware\SetContentLanguage; use Pckg\Dynamic\Middleware\SwitchLanguage; +use Pckg\Dynamic\Record\Table; use Pckg\Dynamic\Resolver\ExportStrategy; use Pckg\Dynamic\Resolver\Field as FieldResolver; use Pckg\Dynamic\Resolver\ForeignRecord; @@ -56,7 +58,78 @@ public function middlewares() public function routes() { + $backendData = function ($component = null) { + return [ + 'tags' => $component ? [ + 'group:backend', + 'layout:backend', + 'vue:route', + 'vue:route:template' => substr($component, 0, 1) !== '<' ? '<' . $component . '>' : $component, + ] : [ + 'group:backend', + 'layout:backend', + 'vue:route', + ] + ]; + }; return [ + /** + * Views. + */ + routeGroup([ + 'controller' => Records::class, + ], [ + 'dynamic.record.add' => route('/dynamic/records/add/[table]', 'add')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('write'); + }); + }, + ])->mergeToData($backendData('dynamic-singular')), + + 'dynamic.record.add.relation' => route('/dynamic/records/add/[table]/[relation]/[foreign]', 'add')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('write'); + }); + }, + 'relation' => Relation::class, + 'foreign' => ForeignRecord::class, + ])->mergeToData($backendData('dynamic-singular')), + + 'dynamic.record.view' => route('/dynamic/records/view/[table]/[record]', 'view')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('read'); + }); + }, + 'record' => RecordResolver::class, + ])->mergeToData($backendData('pckg-dynamic-record-tabs')), + + 'dynamic.record.edit' => route('/dynamic/records/edit/[table]/[record]', 'edit')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('write'); + }); + }, + 'record' => RecordResolver::class, + ])->mergeToData($backendData('pckg-dynamic-record-tabs')), + + 'dynamic.record.edit.foreign' => route('/dynamic/records/edit/[table]/[record]/[relation]/[foreign]', 'edit')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('write'); + }); + }, + 'record' => RecordResolver::class, + 'relation' => Relation::class, + 'foreign' => ForeignRecord::class, + ])->mergeToData($backendData('pckg-dynamic-record-tabs')), + + ]), + /** + * APIs. + */ 'url' => array_merge_array( [ 'tags' => ['group:backend', 'layout:backend'], @@ -145,54 +218,6 @@ public function routes() 'tableView' => ViewResolver::class, ], ], - '/dynamic/records/add/[table]' => [ - 'name' => 'dynamic.record.add', - 'view' => 'add', - 'resolvers' => [ - 'table' => TableResolver::class, - ], - ], - '/dynamic/records/add/[table]/[relation]/[foreign]' => [ - 'name' => 'dynamic.record.add.related', - 'view' => 'add', - 'resolvers' => [ - 'table' => TableResolver::class, - 'relation' => Relation::class, - 'foreign' => ForeignRecord::class, - ], - ], - '/dynamic/records/view/[table]/[record]' => [ - 'name' => 'dynamic.record.view', - 'view' => 'view', - 'resolvers' => [ - 'table' => TableResolver::class, - 'record' => RecordResolver::class, - ], - ], - '/dynamic/records/edit/[table]/[record]' => [ - 'name' => 'dynamic.record.edit', - 'view' => 'edit', - 'resolvers' => [ - 'table' => TableResolver::class, - 'record' => RecordResolver::class, - ], - 'middlewares' => [ - SwitchLanguage::class, - ], - ], - '/dynamic/records/edit/[table]/[record]/[relation]/[foreign]' => [ - 'name' => 'dynamic.record.edit.foreign', - 'view' => 'edit', - 'resolvers' => [ - 'table' => TableResolver::class, - 'record' => RecordResolver::class, - 'relation' => Relation::class, - 'foreign' => ForeignRecord::class, - ], - 'middlewares' => [ - SwitchLanguage::class, - ], - ], '/dynamic/records/clone/[table]/[record]' => [ 'name' => 'dynamic.record.clone', 'view' => 'clone', diff --git a/src/Pckg/Dynamic/Record/Table.php b/src/Pckg/Dynamic/Record/Table.php index d93154d4..606a0194 100644 --- a/src/Pckg/Dynamic/Record/Table.php +++ b/src/Pckg/Dynamic/Record/Table.php @@ -6,6 +6,7 @@ use Pckg\Database\Relation\BelongsTo; use Pckg\Database\Relation\HasMany; use Pckg\Database\Repository; +use Pckg\Dynamic\Entity\TableActions; use Pckg\Dynamic\Entity\Tables; use Pckg\Dynamic\Service\Filter; use Pckg\Framework\View\Twig; @@ -231,4 +232,22 @@ public function loadTwigDirsForEntity($entity, $dynamicService) return $entity; } + public function checkPermissionsFor($action = 'write') + { + if (!$this->hasPermissionTo($action)) { + response()->unauthorized('Missing permissions to write'); + } + + if (!$this->listableFields->count()) { + response()->unauthorized('Missing view field permissions.'); + } + + (new TableActions())->joinPermissionTo('execute') + ->where('dynamic_table_id', $this->id) + ->where('slug', $action === 'read' ? 'view' : 'edit') + ->oneOrFail(function(){ + $this->response()->unauthorized(); + }); + } + } \ No newline at end of file diff --git a/src/Pckg/Dynamic/Resolver/Table.php b/src/Pckg/Dynamic/Resolver/Table.php index 47b24981..f592cf60 100644 --- a/src/Pckg/Dynamic/Resolver/Table.php +++ b/src/Pckg/Dynamic/Resolver/Table.php @@ -4,11 +4,14 @@ use Pckg\Database\Relation\HasMany; use Pckg\Dynamic\Entity\Tables; use Pckg\Dynamic\Service\Dynamic; +use Pckg\Framework\Provider\Helper\PostValidationResolver; use Pckg\Framework\Provider\RouteResolver; class Table implements RouteResolver { + use PostValidationResolver; + /** * @var Dynamic */ @@ -53,6 +56,8 @@ function() { 'en_GB' ); + $this->validate($table); + return $table; } diff --git a/src/Pckg/Dynamic/View/edit/singular.twig b/src/Pckg/Dynamic/View/edit/singular.twig index bb7bce9d..83eeaba1 100644 --- a/src/Pckg/Dynamic/View/edit/singular.twig +++ b/src/Pckg/Dynamic/View/edit/singular.twig @@ -1,9 +1,3 @@ -{% if flash('dynamic.records.add.success', false) %} - -{% endif %} -{% if flash('dynamic.records.edit.success', false) %} - -{% endif %}
diff --git a/src/Pckg/Dynamic/View/edit/singular.vue b/src/Pckg/Dynamic/View/edit/singular.vue new file mode 100644 index 00000000..d84336fc --- /dev/null +++ b/src/Pckg/Dynamic/View/edit/singular.vue @@ -0,0 +1,90 @@ + + + \ No newline at end of file diff --git a/src/Pckg/Dynamic/View/edit/tabs.twig b/src/Pckg/Dynamic/View/edit/tabs.twig deleted file mode 100644 index e9f9163f..00000000 --- a/src/Pckg/Dynamic/View/edit/tabs.twig +++ /dev/null @@ -1,5 +0,0 @@ - - - -{#{ tabelize.__toStringViews() | raw }#} - \ No newline at end of file diff --git a/src/Pckg/Dynamic/public/less/dynamic.less b/src/Pckg/Dynamic/public/less/dynamic.less index 20a5a3a4..75eadd7b 100644 --- a/src/Pckg/Dynamic/public/less/dynamic.less +++ b/src/Pckg/Dynamic/public/less/dynamic.less @@ -944,7 +944,7 @@ div.form-control { margin-top: 12px; } -.tab-pane > div { +/*.tab-pane > div { &:not([class]):empty { padding: 12px; @@ -963,7 +963,7 @@ div.form-control { transform: translateY(-50%); } } -} +}*/ li.double-link { display: table; diff --git a/src/Pckg/Generic/Service/Generic.php b/src/Pckg/Generic/Service/Generic.php index 87f698cc..0856afe0 100644 --- a/src/Pckg/Generic/Service/Generic.php +++ b/src/Pckg/Generic/Service/Generic.php @@ -67,7 +67,7 @@ public function pushMetadata($actionId, $key, $value) { $this->metadata[$actionId][$key] = $value; - return '$store.state.generic.metadata[' . $actionId . '].' . $key; + return '$store.state.generic.metadata[\'' . $actionId . '\'].' . $key; } public function getMetaData() diff --git a/src/Pckg/Generic/Service/Generic/Action.php b/src/Pckg/Generic/Service/Generic/Action.php index 768f3a75..5cb82c2b 100644 --- a/src/Pckg/Generic/Service/Generic/Action.php +++ b/src/Pckg/Generic/Service/Generic/Action.php @@ -256,6 +256,9 @@ public function build($args = []) $this->getAction()->pivot->resolveSettings($args); $build = $this->getAction()->pivot->buildHtml($args); + /*if (response()->getCode() !== 200) { + ddd($this->getAction()->data()); + }*/ $this->getAction()->pivot->build = $build; } diff --git a/src/Pckg/Maestro/Service/Tabelize.php b/src/Pckg/Maestro/Service/Tabelize.php index 203579bd..1e05c0c8 100644 --- a/src/Pckg/Maestro/Service/Tabelize.php +++ b/src/Pckg/Maestro/Service/Tabelize.php @@ -869,7 +869,7 @@ public function getSavedViews() TableView $tableView ) { return [ - 'id' => $id, + 'id' => $tableView->id, 'type' => 'saved', 'title' => $tableView->title, 'settings' => json_decode($tableView->settings, true), diff --git a/src/Pckg/Maestro/View/_form.vue b/src/Pckg/Maestro/View/_form.vue index eb5275a5..617ac1c1 100644 --- a/src/Pckg/Maestro/View/_form.vue +++ b/src/Pckg/Maestro/View/_form.vue @@ -1,43 +1,57 @@ - \ No newline at end of file diff --git a/src/Pckg/Maestro/View/_table.vue b/src/Pckg/Maestro/View/_table.vue index 34b3c577..ea4e833f 100644 --- a/src/Pckg/Maestro/View/_table.vue +++ b/src/Pckg/Maestro/View/_table.vue @@ -117,11 +117,11 @@
-
+
{{ meta.delimiter }}
Automatically detected column delimiter.
-
+
{{ meta.columns.join(', ') }}
Columns that were properly detected and will be imported.
-
+
Automatically detected newline delimiter.
-
+
{{ meta.rows }}
Number of all rows in imported document
From 1558b0d44123345f298973e8dfc8e87c1bca6259 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Thu, 10 Dec 2020 16:08:28 +0100 Subject: [PATCH 12/61] Hub uuid --- src/Pckg/Generic/Controller/PageStructure.php | 8 +++--- src/Pckg/Generic/Record/Route.php | 4 +-- src/Pckg/Generic/Service/Generic.php | 26 ++++++++++++------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Pckg/Generic/Controller/PageStructure.php b/src/Pckg/Generic/Controller/PageStructure.php index 7d339428..681afe07 100644 --- a/src/Pckg/Generic/Controller/PageStructure.php +++ b/src/Pckg/Generic/Controller/PageStructure.php @@ -408,8 +408,8 @@ public function postContentAction(Content $content) public function postActionsMorphAddPartialAction(ActionsMorph $actionsMorph) { $partial = post('partial', null); - $hub = post('hub', null); - $partial = $hub ? $actionsMorph->addHubShare($hub, [ + $uuid = post('uuid', null); + $partial = $uuid ? $actionsMorph->addHubShare($uuid, [ 'order' => post('order', 0), 'variable' => post('variable', $actionsMorph->variable), ]) : $actionsMorph->addPartial($partial); @@ -451,8 +451,8 @@ public function postActionsMorphAddPartialAction(ActionsMorph $actionsMorph) public function postActionsMorphAddRoutePartialAction(Route $route) { $partial = post('partial', null); - $hub = post('hub', null); - $partial = $hub ? $route->addHubShare($hub, [ + $uuid = post('uuid', null); + $partial = $uuid ? $route->addHubShare($uuid, [ 'variable' => post('variable', 'content'), 'order' => post('order', 0), ]) : $route->addPartial($partial); diff --git a/src/Pckg/Generic/Record/Route.php b/src/Pckg/Generic/Record/Route.php index 5082c60c..ee407714 100644 --- a/src/Pckg/Generic/Record/Route.php +++ b/src/Pckg/Generic/Record/Route.php @@ -97,13 +97,13 @@ public function addPartial($partial) return $partial->addToRoute($this); } - public function addHubShare($share, $defaults = []) + public function addHubShare($uuid, $defaults = []) { /** * @var $generic Generic */ $generic = resolve(Generic::class); - $partial = $generic->prepareHubPartial($share); + $partial = $generic->prepareHubPartial($uuid); return $partial->addToRoute($this, $defaults); } diff --git a/src/Pckg/Generic/Service/Generic.php b/src/Pckg/Generic/Service/Generic.php index bfe4a465..c3520e15 100644 --- a/src/Pckg/Generic/Service/Generic.php +++ b/src/Pckg/Generic/Service/Generic.php @@ -690,7 +690,7 @@ public static function addRoutesFromDb() * @return mixed|object|AbstractPartial * @throws \Exception */ - public function prepareHubPartial($share) + public function prepareHubPartial($uuid) { /** * Get definition from hub? @@ -698,7 +698,7 @@ public function prepareHubPartial($share) * @var $hub Api */ $hub = resolve(Api::class); - $shareDefinition = $hub->getApi('share/' . $share . '/definition')->getApiResponse('share'); + $shareDefinition = $hub->getApi('share/' . $uuid . '/definition')->getApiResponse('share'); /** * Share definition now holds: @@ -707,28 +707,34 @@ public function prepareHubPartial($share) * - attributes * - settings */ - $partial = Reflect::create($shareDefinition['extends'] ?? $shareDefinition['object']); + $partial = Reflect::create($shareDefinition['props']['extends'] ?? $shareDefinition['props']['object']); - if (isset($shareDefinition['content'])) { + if (isset($shareDefinition['props']['content'])) { $partial->setContent($shareDefinition['content']); } - if (isset($shareDefinition['settings'])) { - $partial->setSettings($shareDefinition['settings']); + if (isset($shareDefinition['props']['settings'])) { + $partial->setSettings($shareDefinition['props']['settings']); } - if (isset($shareDefinition['attributes'])) { - $partial->setAttributes($shareDefinition['attributes']); + if (isset($shareDefinition['props']['attributes'])) { + $partial->setAttributes($shareDefinition['props']['attributes']); } - $multi = $shareDefinition['multi'] ?? []; + /** + * Add multiple shares to the parent? + */ + $multi = $shareDefinition['props']['multi'] ?? []; if ($multi) { // what to do when multi sub-shares are re-used? // - link group, button group // we should add first element (which needs a wrapper if needed), and then add all siblings to his parent? } - $style = $shareDefinition['style'] ?? []; + /** + * Basic events table on Overdose. + */ + $style = $shareDefinition['props']['style'] ?? []; if ($style) { // this is when style is shared // marked span styles, custom heading afters, styled table styles, ... From 7300bc37be3155f2b907fd3df63a69c27ae1498a Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sun, 24 Jan 2021 18:17:18 +0100 Subject: [PATCH 13/61] Allow layout --- src/Pckg/Generic/Middleware/EncapsulateResponse.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Pckg/Generic/Middleware/EncapsulateResponse.php b/src/Pckg/Generic/Middleware/EncapsulateResponse.php index 5a2114b2..45f64941 100644 --- a/src/Pckg/Generic/Middleware/EncapsulateResponse.php +++ b/src/Pckg/Generic/Middleware/EncapsulateResponse.php @@ -30,7 +30,7 @@ public function execute(callable $next) $tags = router()->get('tags', []); $template = config('pckg.generic.layouts.default', 'Pckg/Generic:frontend'); $disable = false; - foreach ($tags as $tag) { + foreach ($tags as $key => $tag) { if (!is_string($tag)) { continue; } @@ -38,6 +38,10 @@ public function execute(callable $next) $disable = true; break; } + if ($key === 'layout') { + $template = '<' . $tag . '>'; + break; + } if (strpos($tag, 'layout:') !== 0) { continue; } From 152dd080704378b45356349c689d2d581507b7eb Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sat, 6 Feb 2021 14:27:27 +0100 Subject: [PATCH 14/61] Fix missmerge --- src/Pckg/Dynamic/Record/Table.php | 71 +++++++++++++++---------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/Pckg/Dynamic/Record/Table.php b/src/Pckg/Dynamic/Record/Table.php index 4815e78f..df980373 100644 --- a/src/Pckg/Dynamic/Record/Table.php +++ b/src/Pckg/Dynamic/Record/Table.php @@ -1,6 +1,6 @@ -all() ->keyBy('action') ->map(function() { - + return true; }) ->all(); @@ -44,21 +44,21 @@ public function getPrivilegesAttribute() public function getEntityActions() { - return $this->actions(function (HasMany $relation) { - + return $this->actions(function (HasMany $relation) { + $relation->where('type', ['entity', 'entity-plugin', 'mixed']); $relation->joinPermission(); - }); + }); return $actions; } public function getRecordActions() { - return $this->actions(function (HasMany $relation) { - + return $this->actions(function (HasMany $relation) { + $relation->where('type', ['record', 'record-plugin', 'mixed']); $relation->joinPermission(); - }); + }); } public function getListTitle() @@ -74,21 +74,21 @@ public function getFormTitle($type = 'Add') public function getViewUrl(Record $record = null) { return $record - ? url('dynamic.record.view', [ + ? url('dynamic.record.view', [ 'table' => $this, 'record' => $record, ]) - : url('dynamic.record.list', [ + : url('dynamic.record.list', [ 'table' => $this, - ]); + ]); } public function getEditUrl(Record $record) { - return url('dynamic.record.edit', [ + return url('dynamic.record.edit', [ 'table' => $this, 'record' => $record, - ]); + ]); } public function getListUrl() @@ -100,20 +100,20 @@ public function getHasManyRelation() { return $this->relationExists('hasManyRelation') ? $this->getRelation('hasManyRelation') - : $this->hasManyRelation(function (HasMany $relation) { - + : $this->hasManyRelation(function (HasMany $relation) { + $relation->where('on_table_id', $this->id); - }); + }); } public function getBelongsToRelation() { return $this->relationExists('belongsToRelation') ? $this->getRelation('belongsToRelation') - : $this->belongsToRelation(function (BelongsTo $relation) { - + : $this->belongsToRelation(function (BelongsTo $relation) { + $relation->where('on_table_id', $this->id); - }); + }); } /** @@ -146,16 +146,16 @@ public function createEntity($alias = null, $extensions = true) $entityClass = $this->framework_entity ? $this->framework_entity : Entity::class; - $entity = runInLocale(function () use ($entityClass, $repository, $alias, $extensions) { + $entity = runInLocale(function () use ($entityClass, $repository, $alias, $extensions) { - $entity = new $entityClass($repository, $alias); + $entity = new $entityClass($repository, $alias); $entity->setTable($this->table); if ($extensions && $entity->isTranslatable() && !$entity->isTranslated()) { $entity->joinTranslations(); } return $entity; - }, $_SESSION['pckg_dynamic_lang_id']); + }, $_SESSION['pckg_dynamic_lang_id']); return $entity; } @@ -175,10 +175,10 @@ public function fetchFrameworkRecord(Record $record, Entity $entity) public function getFields($listableFields, Filter $filterService, $fields = []) { - return $listableFields->reduce(function (Field $field) use ($fields) { + return $listableFields->reduce(function (Field $field) use ($fields) { return in_array($field->field, $fields); - }); + }); } /*public function getStringVues($entity, $dynamicService) @@ -215,7 +215,6 @@ public function loadTwigDirsForEntity($entity, $dynamicService) return $entity; } -<<<<<<< HEAD public function checkPermissionsFor($action = 'write') { @@ -235,6 +234,4 @@ public function checkPermissionsFor($action = 'write') }); } -======= ->>>>>>> master } \ No newline at end of file From 9c4f585634c08e975bc86bdd58252d1b79e9b74f Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sun, 28 Feb 2021 12:55:01 +0100 Subject: [PATCH 15/61] Trim --- .../Middleware/EncapsulateResponse.php | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/Pckg/Generic/Middleware/EncapsulateResponse.php b/src/Pckg/Generic/Middleware/EncapsulateResponse.php index eff988e3..0459b93d 100644 --- a/src/Pckg/Generic/Middleware/EncapsulateResponse.php +++ b/src/Pckg/Generic/Middleware/EncapsulateResponse.php @@ -1,6 +1,6 @@ -request->isGet() && !$this->request->isAjax()) { - $output = $this->response->getOutput(); - - if ( - is_string($output) && (substr($output, 0, 5)) !== 'get('tags', []); - $template = config('pckg.generic.layouts.default', 'Pckg/Generic:frontend'); - $disable = false; - foreach ($tags as $key => $tag) { - if (!is_string($tag)) { - continue; - } - if ($tag == EncapsulateResponse::class . '.disable') { - $disable = true; - break; - } - if ($key === 'layout') { - $template = '<' . $tag . '>'; - break; - } - if (strpos($tag, 'layout:') !== 0) { - continue; - } + if (!$this->request->isGet() || $this->request->isAjax()) { + return $next(); + } + $output = $this->response->getOutput(); - $key = substr($tag, strlen('layout:')); - $template = config('pckg.generic.layouts.' . $key, $template); + if ( + is_string($output) && (substr($output, 0, 5)) !== 'get('tags', []); + $template = config('pckg.generic.layouts.default', 'Pckg/Generic:frontend'); + $disable = false; + foreach ($tags as $key => $tag) { + if (!is_string($tag)) { + continue; } - - if (!$disable) { - $output = $template == 'Pckg/Generic:backend' - ? Reflect::create(Generic::class)->wrapIntoGeneric($output, $template) - : Reflect::create(Generic::class)->wrapIntoGenericContainer($output, $template); - // $output = Reflect::create(Generic::class)->wrapIntoGeneric($output, $template); - $this->response->setOutput($output); + if ($tag == EncapsulateResponse::class . '.disable') { + $disable = true; + break; + } + if ($key === 'layout') { + $output = '<' . $tag . '>'; + break; } + if (strpos($tag, 'layout:') !== 0) { + continue; + } + + $key = substr($tag, strlen('layout:')); + $template = config('pckg.generic.layouts.' . $key, $template); + } + + if (!$disable) { + $output = $template == 'Pckg/Generic:backend' + ? Reflect::create(Generic::class)->wrapIntoGeneric($output, $template) + : Reflect::create(Generic::class)->wrapIntoGenericContainer($output, $template); + // $output = Reflect::create(Generic::class)->wrapIntoGeneric($output, $template); + $this->response->setOutput($output); } } return $next(); } -} \ No newline at end of file +} From c13b437d251e2bbd71beacb045a018c1112293d4 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Tue, 16 Mar 2021 21:56:41 +0100 Subject: [PATCH 16/61] Static fields --- src/Pckg/Dynamic/Entity/Fields.php | 5 ++++- src/Pckg/Dynamic/Record/Field.php | 4 ++-- src/Pckg/Dynamic/Service/Dynamic.php | 2 +- src/Pckg/Dynamic/Service/Filter.php | 2 +- src/Pckg/Generic/Service/Menu.php | 1 - 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Pckg/Dynamic/Entity/Fields.php b/src/Pckg/Dynamic/Entity/Fields.php index 15772bb6..c1db6e4e 100644 --- a/src/Pckg/Dynamic/Entity/Fields.php +++ b/src/Pckg/Dynamic/Entity/Fields.php @@ -24,7 +24,10 @@ public function boot() $this->joinFallbackTranslation(); $this->withFieldType(); $this->withSettings(function (MorphsMany $settings) { - + /** + * What settings do we use here? + * This is strictly because have settings table also? + */ $settings->getMiddleEntity()->setRepository($settings->getLeftRepository()); }); } diff --git a/src/Pckg/Dynamic/Record/Field.php b/src/Pckg/Dynamic/Record/Field.php index 637d4e38..c394207b 100644 --- a/src/Pckg/Dynamic/Record/Field.php +++ b/src/Pckg/Dynamic/Record/Field.php @@ -299,12 +299,12 @@ public function isTranslatable($entity) public function getTransformedValue($entity) { $field = $this; - if ($this->fieldType->slug == 'php') { + if ($this->fieldType && $this->fieldType->slug == 'php') { return function ($record) use ($field) { return $record->{'get' . ucfirst($field->field) . 'Attribute'}(); }; - } elseif ($this->fieldType->slug == 'geo') { + } elseif ($this->fieldType && $this->fieldType->slug == 'geo') { $entity->addSelect([ $this->field . '_x' => 'X(' . $this->field . ')', $this->field . '_y' => 'Y(' . $this->field . ')', diff --git a/src/Pckg/Dynamic/Service/Dynamic.php b/src/Pckg/Dynamic/Service/Dynamic.php index 5f79d23e..bd4ebb9a 100644 --- a/src/Pckg/Dynamic/Service/Dynamic.php +++ b/src/Pckg/Dynamic/Service/Dynamic.php @@ -152,7 +152,7 @@ public function selectScope(Entity $entity) public function optimizeSelectedFields(Entity $entity, Collection $listedFields) { $listedFields->each(function (Field $field) use ($entity) { - $slug = $field->fieldType->slug; + $slug = $field->fieldType ? $field->fieldType->slug : null; if (in_array($slug, ['php', 'mysql'])) { if (method_exists($entity, 'select' . ucfirst($field->field) . 'Field')) { $entity->{'select' . ucfirst($field->field) . 'Field'}(); diff --git a/src/Pckg/Dynamic/Service/Filter.php b/src/Pckg/Dynamic/Service/Filter.php index c509d41f..a16f2286 100644 --- a/src/Pckg/Dynamic/Service/Filter.php +++ b/src/Pckg/Dynamic/Service/Filter.php @@ -413,7 +413,7 @@ public function applyOnEntity(Entity $entity, $filters = []) } } - public function filterByGet(Entity $entity, Collection $relations = null, $search = null) + public function filterByGet(Entity $entity, \Pckg\Collection $relations = null, $search = null) { if (!$search) { $search = get('search'); diff --git a/src/Pckg/Generic/Service/Menu.php b/src/Pckg/Generic/Service/Menu.php index c3c5ead1..b0fed51c 100644 --- a/src/Pckg/Generic/Service/Menu.php +++ b/src/Pckg/Generic/Service/Menu.php @@ -20,7 +20,6 @@ public function build($slug, $repository = null, $language = null, $permissions $menus = new Menus($repositoryObject); $locale = first($language, config('pckg.locale.default'), 'en_GB'); $menus = runInLocale(function () use ($menus, $slug) { - return $menus->where('slug', $slug)->all(); }, $locale); if (!$menus->count()) { From 5c078bdd0236274b0c7e76ef4bbb7519ba96fa7e Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Tue, 6 Apr 2021 16:25:47 +0200 Subject: [PATCH 17/61] Better vue routes --- src/Pckg/Dynamic/Controller/Records.php | 29 +++-- src/Pckg/Dynamic/Provider/Dynamic.php | 115 ++++++++++-------- src/Pckg/Dynamic/Record/Table.php | 62 +++++++++- .../Resolver/FunctionizesTabelizes.php | 44 +++++++ src/Pckg/Dynamic/Resolver/Table.php | 1 + .../Dynamic/Resolver/TableRecordRelated.php | 38 ++++++ src/Pckg/Dynamic/View/edit/singular.vue | 13 +- src/Pckg/Generic/Service/Generic.php | 10 +- src/Pckg/Maestro/View/_form.vue | 19 +-- .../View/_pckg_dynamic_record_tabs.vue | 26 ++-- src/Pckg/Maestro/View/_table.vue | 11 ++ .../Maestro/View/tabelize-functionize.vue | 12 ++ 12 files changed, 276 insertions(+), 104 deletions(-) create mode 100644 src/Pckg/Dynamic/Resolver/FunctionizesTabelizes.php create mode 100644 src/Pckg/Dynamic/Resolver/TableRecordRelated.php create mode 100644 src/Pckg/Maestro/View/tabelize-functionize.vue diff --git a/src/Pckg/Dynamic/Controller/Records.php b/src/Pckg/Dynamic/Controller/Records.php index b56eaa59..05becea9 100644 --- a/src/Pckg/Dynamic/Controller/Records.php +++ b/src/Pckg/Dynamic/Controller/Records.php @@ -361,7 +361,7 @@ public function postAddAction(Dynamic $form, Table $table, Record $record = null 'descriptions' => $descriptions, ]); } - + $form->populateToRecord($record); $form->populatePasswords($record); if ($record->language_id) { @@ -503,13 +503,14 @@ public function getEditAction(Dynamic $form, Record $record, Table $table, Dynam * Resolve record for the frontend. * @var $generic Generic */ - return component('pckg-dynamic-record-tabs', [ - ':record' => $tabelize->transformRecord($record), - ':table' => $table, - ':actions' => $tabelize->getActionsArray(), - ':tabs' => $tabs, - ':relations' => $relations, - ':mode' => $form->isEditable() ? 'edit' : 'view', + return ([ + //return component('pckg-dynamic-record-tabs', [ + 'mappedRecord' => $tabelize->transformRecord($record), + //'table' => $table, + 'actions' => $tabelize->getActionsArray(), + 'tabs' => $tabs, + 'relations' => $relations, + 'mode' => $form->isEditable() ? 'edit' : 'view', ]); } @@ -558,20 +559,21 @@ public function getTabAction(Record $record, Table $table, Tab $tab) $functionize = $pluginService->make($function->class, $function->method, $args); $functionizes[] = (string)$functionize; }); - if (!get('html') && (request()->isAjax() || $this->request()->isJson())) { + /*if (!get('html') && (request()->isAjax() || $this->request()->isJson())) { return [ 'functionizes' => $functionizes, 'tabelizes' => $tabelizes, ]; - } + }*/ /** * We have to build tab. */ - return view('edit/tab', [ + return [ + //return view('edit/tab', [ 'functionizes' => $functionizes, 'tabelizes' => $tabelizes, - ]); + ]; } protected function getTabelizesAndFunctionizes($tabs, $record, Table $table, Entity $entity) @@ -949,6 +951,7 @@ public function getViewFormApiRecordAction(Table $table, Record $record = null) ]; return [ 'form' => $form, + 'table' => $table, ]; } -} \ No newline at end of file +} diff --git a/src/Pckg/Dynamic/Provider/Dynamic.php b/src/Pckg/Dynamic/Provider/Dynamic.php index a350408e..4e414a4e 100644 --- a/src/Pckg/Dynamic/Provider/Dynamic.php +++ b/src/Pckg/Dynamic/Provider/Dynamic.php @@ -15,12 +15,14 @@ use Pckg\Dynamic\Resolver\ExportStrategy; use Pckg\Dynamic\Resolver\Field as FieldResolver; use Pckg\Dynamic\Resolver\ForeignRecord; +use Pckg\Dynamic\Resolver\FunctionizesTabelizes; use Pckg\Dynamic\Resolver\Language; use Pckg\Dynamic\Resolver\Record; use Pckg\Dynamic\Resolver\Record as RecordResolver; use Pckg\Dynamic\Resolver\Relation; use Pckg\Dynamic\Resolver\Tab as TabResolver; use Pckg\Dynamic\Resolver\Table as TableResolver; +use Pckg\Dynamic\Resolver\TableRecordRelated; use Pckg\Dynamic\Resolver\TableView as ViewResolver; use Pckg\Framework\Provider; use Pckg\Framework\View\Event\RenderingView; @@ -91,87 +93,103 @@ public function routes() return [ /** * Views. + * What if there's a VueRoute attached to a controller? + * Shall we handle it as a normal route? */ routeGroup([ 'controller' => Records::class, - ], [ + 'urlPrefix' => '/dynamic/records/[table]/[record]', + ], [ - 'dynamic.record.add' => route('/dynamic/records/[table]/add', 'add')->resolvers([ - 'table' => function () { - return resolve(TableResolver::class)->validator(function (Table $table) { - $table->checkPermissionsFor('write'); - }); - }, - ])->mergeToData($backendData('dynamic-singular')), + 'dynamic.record' => vueRoute('', 'pckg-dynamic-record-tabs', [], [ - /*'dynamic.record.add.relation' => route('/dynamic/records/[table]/add/[relation]/[foreign]', 'add')->resolvers([ - 'table' => function () { - return resolve(TableResolver::class)->validator(function (Table $table) { - $table->checkPermissionsFor('write'); - }); - }, - 'relation' => Relation::class, - 'foreign' => ForeignRecord::class, - ])->mergeToData($backendData('')),*/ + 'view' => vueRoute('/view', '')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('read'); + }); + }, + 'record' => RecordResolver::class, + TableRecordRelated::class, + ])->mergeToData($backendData()), + + 'edit' => vueRoute('/edit', '')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('write'); + }); + }, + 'record' => RecordResolver::class, + TableRecordRelated::class, + ])->mergeToData($backendData()), + + 'tab' => vueRoute('/tab/[tab]', 'tabelize-functionize')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('read'); + }); + }, + 'record' => RecordResolver::class, // relation.show_table_id, relation.id + 'tab' => TabResolver::class, + FunctionizesTabelizes::class, + TableRecordRelated::class, + ])->mergeToData($backendData()), - 'dynamic.record.view' => route('/dynamic/records/[table]/[record]/view', 'view')->resolvers([ + ])->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('read'); }); }, 'record' => RecordResolver::class, - ])->mergeToData($backendData('', [ - 'vue:route:child', - ])), + TableRecordRelated::class, + ])->mergeToData($backendData('pckg-dynamic-record-tabs')), // vue route, no component, rendered in controller as tabs + + ]), + routeGroup([ + 'controller' => Records::class, + 'urlPrefix' => '/dynamic/records/[table]', + ], [ - 'dynamic.record.edit' => route('/dynamic/records/[table]/[record]/edit', 'edit')->resolvers([ + 'dynamic.record.add' => vueRoute('/add', 'dynamic-singular')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('write'); }); }, - 'record' => RecordResolver::class, - ])->mergeToData($backendData('', [ - 'vue:route:child', - ])), + ])->mergeToData($backendData()), - /*'dynamic.record.edit.foreign' => route('/dynamic/records/[table]/[record]/edit/[relation]/[foreign]', 'edit')->resolvers([ + 'dynamic.record.add.relation' => vueRoute('/add/[relation]/[foreign]', 'pckg-maestro-form')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('write'); }); }, - 'record' => RecordResolver::class, 'relation' => Relation::class, 'foreign' => ForeignRecord::class, - ])->mergeToData($backendData('')),*/ + ])->mergeToData($backendData()), - 'dynamic.record.tab' => route('/dynamic/records/[table]/[record]/tab/[tab]', 'edit')->resolvers([ + + /*'dynamic.record.add.relation' => route('/dynamic/records/[table]/add/[relation]/[foreign]', 'add')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('write'); }); }, - 'record' => RecordResolver::class, // relation.show_table_id, relation.id - 'tab' => TabResolver::class, - ])->mergeToData($backendData('', [ - 'vue:route:child', - ])), + 'relation' => Relation::class, + 'foreign' => ForeignRecord::class, + ])->mergeToData($backendData('')),*/ - 'dynamic.record' => vueRoute('/dynamic/records/[table]/[record]', 'pckg-dynamic-record-tabs', [ - 'vue:route:children' => [ - 'dynamic.record.view', - 'dynamic.record.edit', - 'dynamic.record.tab', - ], - ])->resolvers([ + /*'dynamic.record.edit.foreign' => route('/dynamic/records/[table]/[record]/edit/[relation]/[foreign]', 'edit')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('write'); }); }, - ])->mergeToData($backendData()), + 'record' => RecordResolver::class, + 'relation' => Relation::class, + 'foreign' => ForeignRecord::class, + ])->mergeToData($backendData('')),*/ ]), /** @@ -184,15 +202,6 @@ public function routes() 'controller' => Records::class, ], [ - /*'/dynamic/records/[table]/[record]/tab/[tab]' => [ - 'name' => 'dynamic.record.tab', - 'view' => 'tab', - 'resolvers' => [ - 'table' => TableResolver::class, - 'record' => RecordResolver::class, - 'tab' => TabResolver::class, - ], - ],*/ '/api/vue/dynamic/table/[table]/actions' => [ 'name' => 'api.vue.dynamic.table.actions', 'view' => 'tableActions', @@ -485,4 +494,4 @@ public function routes() ])), ]; } -} \ No newline at end of file +} diff --git a/src/Pckg/Dynamic/Record/Table.php b/src/Pckg/Dynamic/Record/Table.php index df980373..970797f6 100644 --- a/src/Pckg/Dynamic/Record/Table.php +++ b/src/Pckg/Dynamic/Record/Table.php @@ -26,7 +26,8 @@ class Table extends Record { protected $entity = Tables::class; - protected $toArray = ['privileges']; + protected $toArray = ['privileges', 'titleSingular', 'indexUrl']; + public function getPrivilegesAttribute() { $tables = (new Tables(null, null, false)); @@ -42,6 +43,63 @@ public function getPrivilegesAttribute() ->all(); } + public function getTitleSingularAttribute() { + $string = $this->title; + // save some time in the case that singular and plural are the same + /*if ( in_array( strtolower( $string ), self::$uncountable ) ) + return $string;*/ + + // check for irregular plural forms + /*foreach ( self::$irregular as $result => $pattern ) + { + $pattern = '/' . $pattern . '$/i'; + + if ( preg_match( $pattern, $string ) ) + return preg_replace( $pattern, $result, $string); + }*/ + + // check for matches using regular expressions + $singular = array( + '/(quiz)zes$/i' => "$1", + '/(matr)ices$/i' => "$1ix", + '/(vert|ind)ices$/i' => "$1ex", + '/^(ox)en$/i' => "$1", + '/(alias)es$/i' => "$1", + '/(octop|vir)i$/i' => "$1us", + '/(cris|ax|test)es$/i' => "$1is", + '/(shoe)s$/i' => "$1", + '/(o)es$/i' => "$1", + '/(bus)es$/i' => "$1", + '/([m|l])ice$/i' => "$1ouse", + '/(x|ch|ss|sh)es$/i' => "$1", + '/(m)ovies$/i' => "$1ovie", + '/(s)eries$/i' => "$1eries", + '/([^aeiouy]|qu)ies$/i' => "$1y", + '/([lr])ves$/i' => "$1f", + '/(tive)s$/i' => "$1", + '/(hive)s$/i' => "$1", + '/(li|wi|kni)ves$/i' => "$1fe", + '/(shea|loa|lea|thie)ves$/i'=> "$1f", + '/(^analy)ses$/i' => "$1sis", + '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => "$1$2sis", + '/([ti])a$/i' => "$1um", + '/(n)ews$/i' => "$1ews", + '/(h|bl)ouses$/i' => "$1ouse", + '/(corpse)s$/i' => "$1", + '/(us)es$/i' => "$1", + '/s$/i' => "" + ); + + foreach ( $singular as $pattern => $result ) + { + if ( preg_match( $pattern, $string ) ) { + return preg_replace( $pattern, $result, $string ); + } + } + + return $string; + } + public function getEntityActions() { return $this->actions(function (HasMany $relation) { @@ -234,4 +292,4 @@ public function checkPermissionsFor($action = 'write') }); } -} \ No newline at end of file +} diff --git a/src/Pckg/Dynamic/Resolver/FunctionizesTabelizes.php b/src/Pckg/Dynamic/Resolver/FunctionizesTabelizes.php new file mode 100644 index 00000000..904d9061 --- /dev/null +++ b/src/Pckg/Dynamic/Resolver/FunctionizesTabelizes.php @@ -0,0 +1,44 @@ +table = $table; + $this->record = $record; + $this->tab = $tab; + } + + public function resolve($value) + { + // mock the controller? + return resolve(Records::class)->getTabAction($this->record, $this->table, $this->tab); + } + + public function parametrize($record) + { + // TODO: Implement parametrize() method. + } + +} diff --git a/src/Pckg/Dynamic/Resolver/Table.php b/src/Pckg/Dynamic/Resolver/Table.php index 4337abb7..f5219978 100644 --- a/src/Pckg/Dynamic/Resolver/Table.php +++ b/src/Pckg/Dynamic/Resolver/Table.php @@ -18,6 +18,7 @@ class Table implements RouteResolver * @var Dynamic */ protected $dynamic; + public function __construct(Dynamic $dynamic) { $this->dynamic = $dynamic; diff --git a/src/Pckg/Dynamic/Resolver/TableRecordRelated.php b/src/Pckg/Dynamic/Resolver/TableRecordRelated.php new file mode 100644 index 00000000..2d1aecd0 --- /dev/null +++ b/src/Pckg/Dynamic/Resolver/TableRecordRelated.php @@ -0,0 +1,38 @@ +table = $table; + $this->record = $record; + } + + public function resolve($value) + { + // mock the controller? + return resolve(Records::class)->getViewAction(resolve(Dynamic::class), $this->record, $this->table, resolve(\Pckg\Dynamic\Service\Dynamic::class)); + } + + public function parametrize($record) + { + // TODO: Implement parametrize() method. + } + +} diff --git a/src/Pckg/Dynamic/View/edit/singular.vue b/src/Pckg/Dynamic/View/edit/singular.vue index a0800985..64959bd7 100644 --- a/src/Pckg/Dynamic/View/edit/singular.vue +++ b/src/Pckg/Dynamic/View/edit/singular.vue @@ -2,16 +2,9 @@
-

- - - {{ record.id ? mode : 'Add new' }} {{ table.title }} -

- -
- - + +
@@ -96,22 +96,22 @@ export default { }, computed: { table: function () { - return this.$store.state.generic.metadata.router.table || {}; + return this.$route.meta.resolved.table; }, record: function () { - return this.$store.state.generic.metadata.router.record || {}; + return this.$route.meta.resolved.mappedRecord || this.$route.meta.resolved.record; }, actions: function () { - return this.$store.state.generic.metadata.router.actions || {}; + return this.$route.meta.resolved.actions; }, tabs: function () { - return this.$store.state.generic.metadata.router.tabs || {}; + return this.$route.meta.resolved.tabs; }, relations: function () { - return this.$store.state.generic.metadata.router.relations || {}; + return this.$route.meta.resolved.relations; }, mode: function () { - return this.$store.state.generic.metadata.router.mode || {}; + return this.$route.meta.resolved.mode; }, tabRelations: function () { return this.relations.filter((relation) => relation.dynamic_table_tab_id > 0); @@ -134,7 +134,7 @@ export default { }, recordIdentifier: function () { let identifier = this.record.id || null; - $.each(['email', 'title', 'slug'], (i, prop) => { + $.each(['email', 'title', 'slug', 'identifier', 'num', 'id'], (i, prop) => { if (this.record[prop]) { identifier = this.record[prop]; } @@ -144,4 +144,4 @@ export default { } } } - \ No newline at end of file + diff --git a/src/Pckg/Maestro/View/_table.vue b/src/Pckg/Maestro/View/_table.vue index 71f59a4f..32300dbd 100644 --- a/src/Pckg/Maestro/View/_table.vue +++ b/src/Pckg/Maestro/View/_table.vue @@ -955,6 +955,7 @@ } }, created: function () { + console.log('created', this); this.initialFetch(); $('body').on('click', function () { @@ -990,6 +991,16 @@ $dispatcher.$on('pckg-maestro-table-' + this.table.table + ':setPaginatorTotal', this.setPaginatorTotal); $dispatcher.$on('pckg-maestro-table-' + this.table.table + ':refresh', this.refreshData); } + }, + beforeDestroy() { + if (this.onTab) { + $dispatcher.$off('dynamic-tab-' + tab.id + ':refresh', this.refreshData); + } + if (this.onTable) { + $dispatcher.$off('pckg-maestro-table-' + this.table.table + ':setRecords', this.setRecords); + $dispatcher.$off('pckg-maestro-table-' + this.table.table + ':setPaginatorTotal', this.setPaginatorTotal); + $dispatcher.$off('pckg-maestro-table-' + this.table.table + ':refresh', this.refreshData); + } } }; diff --git a/src/Pckg/Maestro/View/tabelize-functionize.vue b/src/Pckg/Maestro/View/tabelize-functionize.vue new file mode 100644 index 00000000..5ebe9ad2 --- /dev/null +++ b/src/Pckg/Maestro/View/tabelize-functionize.vue @@ -0,0 +1,12 @@ + + + From d4c96f88bce3a4bbcb574938973a94d898f38909 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sun, 11 Apr 2021 18:51:28 +0200 Subject: [PATCH 18/61] Pre-release fixes --- src/Pckg/Dynamic/Controller/Records.php | 16 +- src/Pckg/Dynamic/Form/Dynamic.php | 161 +++++++++--------- src/Pckg/Dynamic/Provider/Dynamic.php | 70 +++++--- src/Pckg/Dynamic/Record/Field.php | 72 ++++++++ src/Pckg/Dynamic/Record/Table.php | 16 +- src/Pckg/Dynamic/View/edit/singular.vue | 75 +++----- src/Pckg/Maestro/View/_form.vue | 10 +- .../View/_pckg_dynamic_record_tabs.vue | 1 + 8 files changed, 244 insertions(+), 177 deletions(-) diff --git a/src/Pckg/Dynamic/Controller/Records.php b/src/Pckg/Dynamic/Controller/Records.php index 05becea9..45d377b6 100644 --- a/src/Pckg/Dynamic/Controller/Records.php +++ b/src/Pckg/Dynamic/Controller/Records.php @@ -42,6 +42,7 @@ class Records extends Controller protected $pluginService; + public function __construct(Plugin $pluginService) { $this->pluginService = $pluginService; @@ -916,6 +917,7 @@ public function getViewFormApiRecordAction(Table $table, Record $record = null) 'order' => 'number', 'integer' => 'number', 'slug' => 'text', + 'picture' => 'file:picture', ]; $typeMapper = function(Field $field) use ($vueTypeMap) { @@ -926,25 +928,17 @@ public function getViewFormApiRecordAction(Table $table, Record $record = null) return $field->fieldType->slug; }; $formObject = (new Dynamic())->setTable($table)->setRecord($record)->initFields(); - $initialOptions = $formObject->getInitialOptions(); + $initialOptions = $formObject->getDynamicInitialOptions(); $form = [ - 'fields' => $fields->map(function(Field $field) use ($typeMapper, $initialOptions) { - - $options = new \stdClass(); + 'fields' => $fields->map(function(Field $field) use ($initialOptions, $record, $typeMapper) { $type = $typeMapper($field); - if ($field->fieldType->slug === 'select') { - $options = [ - 'options' => $initialOptions[$field->field] ?? [], - ]; - } - return [ 'title' => $field->title, 'slug' => $field->field, 'type' => $type, 'help' => $field->help, 'required' => !!$field->required, - 'options' => $options, + 'options' => $field->getVueOptions($initialOptions, $record), 'group' => $field->fieldGroup, ]; })->rekey(), diff --git a/src/Pckg/Dynamic/Form/Dynamic.php b/src/Pckg/Dynamic/Form/Dynamic.php index 0c5e2849..1fe414cf 100644 --- a/src/Pckg/Dynamic/Form/Dynamic.php +++ b/src/Pckg/Dynamic/Form/Dynamic.php @@ -1,6 +1,6 @@ -all(); $fields->each(function(Field $field) use ($record, $data) { - $password = $data[$field->field]; + $password = $data[$field->field]; if (!$password) { return; } @@ -111,10 +114,10 @@ public function populatePasswords(Record $record) if ($provider = $field->getSetting('pckg.dynamic.field.passwordProvider')) { $record->{$field->field} = auth($provider)->hashPassword($password); } elseif ($encrypt = $field->getSetting('pckg.dynamic.field.encrypt')) { - $record->{$field->field} = Crypto::encrypt( - $password, - Key::loadFromAsciiSafeString(config('security.key')) - ); + $record->{$field->field} = Crypto::encrypt( + $password, + Key::loadFromAsciiSafeString(config('security.key')) + ); } else { $record->{$field->field} = $password; } @@ -136,8 +139,8 @@ public function initLanguageFields() /** * @T00D00 - field language_id could/will interfere with main table fields ... */ - $this->addSelect('language_id')->setValue($languageId)->addOptions($languages->keyBy('slug')->map(function (Language $language) { - + $this->addSelect('language_id')->setValue($languageId)->addOptions($languages->keyBy('slug')->map(function (Language $language) { + return $language->title; }))->setLabel('Language'); if ($this->isEditable()) { @@ -154,7 +157,7 @@ public function initPermissionFields() * @T00D00 - this should be handled separately, like in different form or even different page/tab. */ $allPermissions = $this->record->allPermissions->groupBy('user_group_id')->map(function($permissions) { - + return (new Collection($permissions))->keyBy('action'); })->toArray(); $this->addFieldset('permissionable'); @@ -192,7 +195,7 @@ public function initPermissionFields() $child .= ''; $child .= '' . $action->slug . ' '; $allActionPermissions = $action->allPermissions->groupBy('user_group_id')->each(function($permissions) { - + return (new Collection($permissions))->groupBy('id'); })->toArray(); foreach ($authGroups as $group) { @@ -206,27 +209,23 @@ public function initPermissionFields() $this->addDiv()->addChild($child); } - public function initFields() + public function getListableFields() { - $this->setDecoratorClasses([ - 'label' => '', - 'field' => '', - 'fullField' => '', - 'offset' => '', - 'offsetField' => '', - 'offsetFullField' => '', - ]); + if ($this->listableFields) { + return $this->listableFields; + } + $fields = collect(); for ($i = 0; $i < 2; $i++) { $fields = $this->table->listableFields(function(HasMany $fields) use ($i) { - + $fields->getRightEntity()->orderBy('dynamic_field_group_id ASC, `order` ASC'); $fields->withPermissions(); - $fields->withHasOneSelectRelation(function(HasOne $relation) { - + // @T00D00 - line below does not work with json? + /*$fields->withHasOneSelectRelation(function(HasOne $relation) { $relation->withOnTable(); $relation->withShowTable(); - }); + });*/ $fields->withFieldGroup(); if ($i || ($this->record && $this->record->id) || context()->exists(Auth::class . ':api')) { return; @@ -239,24 +238,39 @@ public function initFields() } } + return $this->listableFields = $fields; + } + + public function initFields() + { + $this->setDecoratorClasses([ + 'label' => '', + 'field' => '', + 'fullField' => '', + 'offset' => '', + 'offsetField' => '', + 'offsetFullField' => '', + ]); + $fields = $this->getListableFields(); + $prevGroup = null; $fieldPositions = $fields->groupBy(function(Field $field) { - + return $field->dynamic_field_group_id ? ($field->fieldGroup->position ?? 'left') : 'left'; }); foreach ($fieldPositions as $position => $fields) { // $positionFieldset = $this->addFieldset('position-' . $position); foreach ($fields as $field) { - if ( - ($prevGroup && $prevGroup != $field->dynamic_field_group_id) || - (!$prevGroup && $field->dynamic_field_group_id) || (!$prevGroup && !$this->lastFieldset) - ) { + if ( + ($prevGroup && $prevGroup != $field->dynamic_field_group_id) || + (!$prevGroup && $field->dynamic_field_group_id) || (!$prevGroup && !$this->lastFieldset) + ) { $this->lastFieldset = $fieldset = $this->addFieldset('position-' . $position) - ->setAttribute( - 'data-field-group', - $field->dynamic_field_group_id - ); + ->setAttribute( + 'data-field-group', + $field->dynamic_field_group_id + ); $fieldset->addChild('

' . ($field->fieldGroup->title ?? 'General') . '

'); $prevGroup = $field->dynamic_field_group_id; @@ -278,10 +292,10 @@ public function initFields() $field->id . '">
' . $this->record->{$field->field} . '
' . $helpHtml . '
'); continue; - } elseif ( - $type != 'hidden' && !$field->hasPermissionTo('write') && - config('pckg.dynamic.permissions') - ) { + } elseif ( + $type != 'hidden' && !$field->hasPermissionTo('write') && + config('pckg.dynamic.permissions') + ) { $element = $fieldset->addDiv() ->addChild('
@@ -363,10 +377,10 @@ protected function createReadonlyElementByType($type, $name, Field $field) '" style="border: 0; width: 100%; min-height: 360px;">'; } elseif (in_array($type, ['file', 'pdf'])) { if ($this->record->{$field->field}) { - $dir = $field->getAbsoluteDir( - $field->getSetting('pckg.dynamic.field.dir'), - $field->getSetting('pckg.dynamic.field.privateUpload') - ); + $dir = $field->getAbsoluteDir( + $field->getSetting('pckg.dynamic.field.dir'), + $field->getSetting('pckg.dynamic.field.privateUpload') + ); $fullPath = $this->record->{$field->field} ? media($this->record->{$field->field}, null, true, $dir) : null; $value = 'setAttribute( + 'onfocus', + "if (this.hasAttribute('readonly')) { this.removeAttribute('readonly'); this.blur(); this.focus(); }" + ); return $element; } elseif (in_array($type, ['slug', 'order', 'hash'])) { return $this->getFieldset()->addText($name); @@ -533,36 +547,13 @@ protected function createElementByType($type, $name, Field $field) $element->setPrefix(''); return $element; } elseif ($type == 'select') { - $relation = $field->getRelationForSelect($this->record, $this->foreignRecord); $element = $this->getFieldset()->addSelect($name); + /** * @T00D00 - add setting for select placeholder for speciffic field */ - $options = []; - $rawValue = $this->record->{$field->field} ?? null; - $foundValue = false; - foreach ($relation as $id => $value) { - if (is_array($value)) { - $optgroup = []; - foreach ($value as $k => $v) { - $optgroup[$k] = str_replace(['
', '
', '
'], ' - ', $v); - $foundValue = $foundValue || $k == $rawValue; - } - $options[$id] = $optgroup; - } else { - $options[$id] = str_replace(['
', '
', '
'], ' - ', $value); - $foundValue = $foundValue || $id == $rawValue; - } - } - - if (!$foundValue && $rawValue) { - $item = $field->getItemForSelect($this->record, null, $rawValue); - if (!trim($item)) { - $item = $rawValue; - } - - $options[$rawValue] = str_replace(['
', '
', '
'], ' - ', $item); - } + $relation = $field->getRelationForSelect($this->record, $this->foreignRecord); + $options = $field->getRelationOptions($relation, $this->record); $element->setAttribute('data-options', json_encode($options)); $element->setAttribute(':initial-multiple', 'false'); @@ -587,4 +578,20 @@ protected function createElementByType($type, $name, Field $field) ddd('Unknown dynamic form type: ' . $type); } } -} \ No newline at end of file + + public function getDynamicInitialOptions() + { + $fields = $this->getListableFields(); + return $fields->realReduce(function(Field $field, $key, $reduced){ + $type = $field->fieldType->slug; + if ($type !== 'select') { + return $reduced; + } + + $relation = $field->getRelationForSelect($this->record, $this->foreignRecord); + $reduced[$field->field] = $field->getRelationOptions($relation, $this->record); + + return $reduced; + }, []); + } +} diff --git a/src/Pckg/Dynamic/Provider/Dynamic.php b/src/Pckg/Dynamic/Provider/Dynamic.php index 4e414a4e..0a504d9e 100644 --- a/src/Pckg/Dynamic/Provider/Dynamic.php +++ b/src/Pckg/Dynamic/Provider/Dynamic.php @@ -98,10 +98,28 @@ public function routes() */ routeGroup([ 'controller' => Records::class, - 'urlPrefix' => '/dynamic/records/[table]/[record]', + 'urlPrefix' => '/dynamic/records/[table]', ], [ - 'dynamic.record' => vueRoute('', 'pckg-dynamic-record-tabs', [], [ + 'dynamic.record.add' => vueRoute('/add', 'dynamic-singular')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + //$table->checkPermissionsFor('write'); + }); + }, + ])->mergeToData($backendData()), + + 'dynamic.record.add.relation' => vueRoute('/add/[relation]/[foreign]', 'pckg-maestro-form')->resolvers([ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + $table->checkPermissionsFor('write'); + }); + }, + 'relation' => Relation::class, + 'foreign' => ForeignRecord::class, + ])->mergeToData($backendData()), + + 'dynamic.record' => vueRoute('/[record]', 'pckg-dynamic-record-tabs', [], [ 'view' => vueRoute('/view', '')->resolvers([ 'table' => function () { @@ -113,7 +131,7 @@ public function routes() TableRecordRelated::class, ])->mergeToData($backendData()), - 'edit' => vueRoute('/edit', '')->resolvers([ + 'edit' => vueRoute('/[record]/edit', '')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('write'); @@ -123,7 +141,7 @@ public function routes() TableRecordRelated::class, ])->mergeToData($backendData()), - 'tab' => vueRoute('/tab/[tab]', 'tabelize-functionize')->resolvers([ + 'tab' => vueRoute('/[record]/tab/[tab]', 'tabelize-functionize')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('read'); @@ -151,24 +169,6 @@ public function routes() 'urlPrefix' => '/dynamic/records/[table]', ], [ - 'dynamic.record.add' => vueRoute('/add', 'dynamic-singular')->resolvers([ - 'table' => function () { - return resolve(TableResolver::class)->validator(function (Table $table) { - $table->checkPermissionsFor('write'); - }); - }, - ])->mergeToData($backendData()), - - 'dynamic.record.add.relation' => vueRoute('/add/[relation]/[foreign]', 'pckg-maestro-form')->resolvers([ - 'table' => function () { - return resolve(TableResolver::class)->validator(function (Table $table) { - $table->checkPermissionsFor('write'); - }); - }, - 'relation' => Relation::class, - 'foreign' => ForeignRecord::class, - ])->mergeToData($backendData()), - /*'dynamic.record.add.relation' => route('/dynamic/records/[table]/add/[relation]/[foreign]', 'add')->resolvers([ 'table' => function () { @@ -202,6 +202,32 @@ public function routes() 'controller' => Records::class, ], [ + + '/api/dynamic/records/[table]/add' => [ + 'name' => 'api.dynamic.records.add', + 'view' => 'add', + 'method' => 'POST', + 'resolvers' => [ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + //$table->checkPermissionsFor('write'); + }); + } + ] + ], + '/api/dynamic/records/[table]/[record]/edit' => [ + 'name' => 'api.dynamic.records.edit', + 'view' => 'add', + 'method' => 'POST', + 'resolvers' => [ + 'table' => function () { + return resolve(TableResolver::class)->validator(function (Table $table) { + //$table->checkPermissionsFor('write'); + }); + }, + 'record' => RecordResolver::class, + ] + ], '/api/vue/dynamic/table/[table]/actions' => [ 'name' => 'api.vue.dynamic.table.actions', 'view' => 'tableActions', diff --git a/src/Pckg/Dynamic/Record/Field.php b/src/Pckg/Dynamic/Record/Field.php index c394207b..dd7cd76c 100644 --- a/src/Pckg/Dynamic/Record/Field.php +++ b/src/Pckg/Dynamic/Record/Field.php @@ -3,6 +3,7 @@ namespace Pckg\Dynamic\Record; use Pckg\Database\Entity; +use Pckg\Database\Record; use Pckg\Database\Record as DatabaseRecord; use Pckg\Dynamic\Entity\Fields; use Throwable; @@ -337,4 +338,75 @@ public function isImportable() { return !in_array($this->fieldType->slug, ['mysql', 'php']); } + + public function getRelationOptions($relation, Record $record = null) + { + $options = []; + $rawValue = $record->{$this->field} ?? null; + $foundValue = false; + foreach ($relation as $id => $value) { + if (is_array($value)) { + $optgroup = []; + foreach ($value as $k => $v) { + $optgroup[$k] = str_replace(['
', '
', '
'], ' - ', $v); + $foundValue = $foundValue || $k == $rawValue; + } + $options[$id] = $optgroup; + } else { + $options[$id] = str_replace(['
', '
', '
'], ' - ', $value); + $foundValue = $foundValue || $id == $rawValue; + } + } + + if (!$foundValue && $rawValue) { + $item = $this->getItemForSelect($record, null, $rawValue); + if (!trim($item)) { + $item = $rawValue; + } + + $options[$rawValue] = str_replace(['
', '
', '
'], ' - ', $item); + } + + return $options; + } + + public function getVueOptions($initialOptions, $record = null) + { + $options = new \stdClass(); + $slug = $this->fieldType->slug; + if ($slug === 'select') { + $options = [ + 'options' => $initialOptions[$this->field] ?? [], + ]; + } else if ($slug === 'picture') { + + /*$url = $this->relation && $this->foreignRecord + ? url('dynamic.records.field.upload.newForeign', [ + 'table' => $this->table, + 'field' => $field, + 'relation' => $this->relation, + 'record' => $this->foreignRecord, + ]) + : ($this->record->id + ? url('dynamic.records.field.upload', [ + 'table' => $this->table, + 'field' => $field, + 'record' => $this->record, + ]) + : url('dynamic.records.field.upload.new', [ + 'table' => $this->table, + 'field' => $field, + ]));*/ + + $options = [ + 'url' => url('dynamic.records.field.upload', [ + 'table' => $this->table, + 'field' => $this, + 'record' => $record, + ]), + ]; + } + + return $options; + } } diff --git a/src/Pckg/Dynamic/Record/Table.php b/src/Pckg/Dynamic/Record/Table.php index 970797f6..38606a85 100644 --- a/src/Pckg/Dynamic/Record/Table.php +++ b/src/Pckg/Dynamic/Record/Table.php @@ -30,17 +30,11 @@ class Table extends Record public function getPrivilegesAttribute() { - $tables = (new Tables(null, null, false)); - $tables->usePermissionableTable(); - return $tables->where('id', $this->id) - ->where('user_group_id', auth()->getGroupId()) - ->all() - ->keyBy('action') - ->map(function() { - - return true; - }) - ->all(); + return $this->allPermissions + ->filter('user_group_id', auth()->getGroupId()) + ->keyBy('action') + ->map(true) + ->all(); } public function getTitleSingularAttribute() { diff --git a/src/Pckg/Dynamic/View/edit/singular.vue b/src/Pckg/Dynamic/View/edit/singular.vue index 64959bd7..929a9e3c 100644 --- a/src/Pckg/Dynamic/View/edit/singular.vue +++ b/src/Pckg/Dynamic/View/edit/singular.vue @@ -1,64 +1,25 @@ diff --git a/src/Pckg/Maestro/View/_form.vue b/src/Pckg/Maestro/View/_form.vue index ff273941..936237d4 100644 --- a/src/Pckg/Maestro/View/_form.vue +++ b/src/Pckg/Maestro/View/_form.vue @@ -7,7 +7,7 @@

{{ field.group.title }}

@@ -55,7 +55,9 @@ export default { default: 'edit' }, formModel: { - default: null + default() { + return {}; + }, }, onSuccess: { default: null @@ -135,8 +137,8 @@ export default { this.state = 'submitting'; this.validateAndSubmit(function () { let url = this.formModel.id - ? ('/dynamic/records/' + this.table.id + '/' + this.formModel.id + '/edit') - : ('/dynamic/records/' + this.table.id + '/add'); + ? ('/api/dynamic/records/' + this.table.id + '/' + this.formModel.id + '/edit') + : ('/api/dynamic/records/' + this.table.id + '/add'); http.post(url, this.collectFormData(), function (data) { this.$emit('saved'); this.state = 'success'; diff --git a/src/Pckg/Maestro/View/_pckg_dynamic_record_tabs.vue b/src/Pckg/Maestro/View/_pckg_dynamic_record_tabs.vue index b1dc75dd..e620f47a 100644 --- a/src/Pckg/Maestro/View/_pckg_dynamic_record_tabs.vue +++ b/src/Pckg/Maestro/View/_pckg_dynamic_record_tabs.vue @@ -137,6 +137,7 @@ export default { $.each(['email', 'title', 'slug', 'identifier', 'num', 'id'], (i, prop) => { if (this.record[prop]) { identifier = this.record[prop]; + return false; } }) From c4b6696684564172dff8144b68ef91764254cb06 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Mon, 26 Apr 2021 12:50:43 +0200 Subject: [PATCH 19/61] Request mock --- src/Pckg/Generic/Controller/PageStructure.php | 8 ++++++-- src/Pckg/Generic/View/_foot.twig | 4 ++-- src/Pckg/Generic/View/_head.twig | 2 +- src/Pckg/Generic/View/error/default.twig | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Pckg/Generic/Controller/PageStructure.php b/src/Pckg/Generic/Controller/PageStructure.php index 9622e03e..d4fae7b7 100644 --- a/src/Pckg/Generic/Controller/PageStructure.php +++ b/src/Pckg/Generic/Controller/PageStructure.php @@ -425,7 +425,11 @@ public function postActionsMorphAddPartialAction(ActionsMorph $actionsMorph) */ $originalContext = context(); $tempContext = clone $originalContext; - $request = (new Request())->setConstructs([], [], $_SERVER, [], $_COOKIE, []); + + $request = (new Request())/*->setConstructs([], [], $_SERVER, [], $_COOKIE, [])*/; + $request->get()->setData([]); + $request->post()->setData([]); + $request->request()->setData([]); $originalRequest = request(); $originalContext->bind(Context::class, $tempContext); $originalContext->bind(Request::class, $request); @@ -587,4 +591,4 @@ public function getRouteResolversAction(Route $route) return ['resolvers' => $resolvers]; } -} \ No newline at end of file +} diff --git a/src/Pckg/Generic/View/_foot.twig b/src/Pckg/Generic/View/_foot.twig index df129c06..97b9908f 100644 --- a/src/Pckg/Generic/View/_foot.twig +++ b/src/Pckg/Generic/View/_foot.twig @@ -7,7 +7,7 @@ auth: {user:{{ _auth.getUserDataArray() | json_encode | raw }}} }; - {% if true or _env.isDev() %} + {% if _env.isDev() %} Vue.config.debug = true; Vue.config.silent = false; Vue.config.devtools = true; @@ -32,4 +32,4 @@ {% do _debugBar.sendDataInHeaders(true) %} {{ renderer.renderHead() | raw }} {{ renderer.render() | raw }} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/src/Pckg/Generic/View/_head.twig b/src/Pckg/Generic/View/_head.twig index 5f56f7ae..b86fabbc 100644 --- a/src/Pckg/Generic/View/_head.twig +++ b/src/Pckg/Generic/View/_head.twig @@ -7,4 +7,4 @@ {{ _assetManager.getMeta(['js'], ['libraries', noTheme ? '' : 'theme', 'main']) | raw }} {{ _seoManager.getOgTags() | raw }} {{ _seoManager.getFaviconTags() | raw }} -{{ _metaManager.getMeta('headerLast') | raw }} \ No newline at end of file +{{ _metaManager.getMeta('headerLast') | raw }} diff --git a/src/Pckg/Generic/View/error/default.twig b/src/Pckg/Generic/View/error/default.twig index 6e9413de..a8c064a4 100644 --- a/src/Pckg/Generic/View/error/default.twig +++ b/src/Pckg/Generic/View/error/default.twig @@ -19,4 +19,4 @@
{% include 'vendor/pckg/generic/src/Pckg/Generic/View/_foot.twig' %} - \ No newline at end of file + From 2fbc646073090e55cffeb3bac6e88729193d50da Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sun, 2 May 2021 12:45:08 +0200 Subject: [PATCH 20/61] Admin group --- src/Pckg/Dynamic/Provider/HttpQl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pckg/Dynamic/Provider/HttpQl.php b/src/Pckg/Dynamic/Provider/HttpQl.php index 3cd4255d..dbffc02d 100644 --- a/src/Pckg/Dynamic/Provider/HttpQl.php +++ b/src/Pckg/Dynamic/Provider/HttpQl.php @@ -13,7 +13,7 @@ public function routes() routeGroup([ 'controller' => \Pckg\Dynamic\Controller\HttpQl::class, 'tags' => [ - 'group:admin', + 'group:api', ], ], [ 'api.httpql' => route('/api/http-ql', 'index')/*->methods(['GET', 'SEARCH', 'PUT'])*/, From bd368baa20a959ee6020ac990139623eb1bb480c Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sat, 8 May 2021 16:40:34 +0200 Subject: [PATCH 21/61] Enriched, httpql --- src/Pckg/Dynamic/Controller/HttpQl.php | 104 +++++++++++++++++++++--- src/Pckg/Dynamic/Controller/Records.php | 4 + src/Pckg/Dynamic/Provider/HttpQl.php | 11 +++ src/Pckg/Dynamic/Resolver/TableQl.php | 37 +++++---- src/Pckg/Dynamic/Service/Paginate.php | 6 +- src/Pckg/Dynamic/Service/Sort.php | 4 +- src/Pckg/Maestro/Service/Tabelize.php | 40 +++++---- 7 files changed, 160 insertions(+), 46 deletions(-) diff --git a/src/Pckg/Dynamic/Controller/HttpQl.php b/src/Pckg/Dynamic/Controller/HttpQl.php index 25260403..e54a76d6 100644 --- a/src/Pckg/Dynamic/Controller/HttpQl.php +++ b/src/Pckg/Dynamic/Controller/HttpQl.php @@ -2,6 +2,7 @@ namespace Pckg\Dynamic\Controller; +use Pckg\Concept\Reflect; use Pckg\Database\Entity; use Pckg\Database\Helper\Convention; use Pckg\Database\Record; @@ -9,9 +10,11 @@ use Pckg\Dynamic\Entity\Fields; use Pckg\Dynamic\Record\Field; use Pckg\Dynamic\Record\Relation; +use Pckg\Dynamic\Record\Tab; use Pckg\Dynamic\Record\Table; use Pckg\Dynamic\Resolver\TableQl; use Pckg\Dynamic\Service\Dynamic; +use Pckg\Generic\Controller\Generic; use Pckg\Maestro\Service\Tabelize; class HttpQl @@ -33,6 +36,73 @@ protected function fetchTable(Dynamic $dynamicService) return (new TableQl($dynamicService))->resolve($path); } + /** + * Get all records. + * + * @param Table $table + * @return mixed|null + * @throws \Throwable + */ + public function getTableAction(Table $table) + { + $tabelize = resolve(Tabelize::class); + $tabelize->setEnriched(false); + + return Reflect::method($this, 'searchIndexAction', ['table' => $table, 'tabelize' => $tabelize]); + } + + /** + * Insert multiple records. + */ + public function postTableAction() + { + + } + + /** + * Patch multiple records. + */ + public function patchTableAction() + { + + } + + /** + * Delete multiple records. + */ + public function deleteTableAction() + { + + } + + public function getRecordAction(Table $table, Record $record) + { + $tabelize = resolve(Tabelize::class); + $tabelize->setEnriched(false); + + return [ + 'record' => Reflect::method(Records::class, 'getViewAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord'] + ]; + } + + public function patchRecordAction(Table $table, Record $record) + { + $tabelize = resolve(Tabelize::class); + $tabelize->setEnriched(false); + + return [ + 'record' => Reflect::method(Records::class, 'postEditAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord'] + ]; + } + + public function deleteRecordAction(Table $table, Record $record) + { + $tabelize = resolve(Tabelize::class); + $tabelize->setEnriched(false); + + return Reflect::method(Records::class, 'deleteDeleteAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord']; + } + /** * This works the same as postAddAction from Record. * Except, it accepts data in other format. @@ -46,9 +116,8 @@ public function putIndexAction(Dynamic $dynamicService) /** * This works only for file uploads. - * It will be refactored to a separate method in next version. */ - public function postIndexAction(Dynamic $dynamic) + public function postUploadAction(Dynamic $dynamic) { if (!files()->all()) { throw new \Exception('Incomplete request'); @@ -78,18 +147,32 @@ public function searchIndexAction( Tabelize $tabelize, Table $table = null, $noLimit = false - ) { + ) + { if (!$table) { $table = $this->fetchTable($dynamicService); } + /** - * Read Orm data. + * Read Orm data from body or headers. */ - $ormFields = json_decode(post('X-Pckg-Orm-Fields'), true); - $ormFilters = json_decode(post('X-Pckg-Orm-Filters'), true); - $ormPaginator = json_decode(post('X-Pckg-Orm-Paginator'), true); - $ormSearch = json_decode(post('X-Pckg-Orm-Search'), true); - $ormMeta = json_decode(post('X-Pckg-Orm-Meta'), true); + $ormFields = json_decode(post('X-Pckg-Orm-Fields', ''), true); + $ormFilters = json_decode(post('X-Pckg-Orm-Filters', ''), true); + $ormPaginator = json_decode(post('X-Pckg-Orm-Paginator', ''), true); + $ormSearch = json_decode(post('X-Pckg-Orm-Search', ''), true); + $ormMeta = json_decode(post('X-Pckg-Orm-Meta', ''), true); + + foreach (['Fields' => [], 'Filters' => [], 'Paginator' => [], 'Search' => null, 'Meta' => []] as $key => $def) { + if (!${'orm' . $key}) { + ${'orm' . $key} = json_decode(request()->getHeader('X-Pckg-Orm-' . $key, ''), true); + } + if (!${'orm' . $key}) { + ${'orm' . $key} = get(strtolower($key), []); + } + if (!${'orm' . $key}) { + ${'orm' . $key} = $def; + } + } /** * Set defaults. @@ -225,7 +308,8 @@ public function getOrmFieldsAndTransformations( $ormFields, &$fields, &$fieldTransformations - ) { + ) + { foreach ($ormFields as $field) { if (strpos($field, '.') === false) { $fieldRecord = Field::gets(['field' => $field, 'dynamic_table_id' => $table->id]); diff --git a/src/Pckg/Dynamic/Controller/Records.php b/src/Pckg/Dynamic/Controller/Records.php index 45d377b6..6cf15d90 100644 --- a/src/Pckg/Dynamic/Controller/Records.php +++ b/src/Pckg/Dynamic/Controller/Records.php @@ -500,6 +500,10 @@ public function getEditAction(Dynamic $form, Record $record, Table $table, Dynam ->where('dynamic_table_tab_id', null, 'IS NOT') ->all(); + if (strpos(router()->getUri(), '/api/http-ql') !== false) { + $tabelize->setEnriched(false); + } + /** * Resolve record for the frontend. * @var $generic Generic diff --git a/src/Pckg/Dynamic/Provider/HttpQl.php b/src/Pckg/Dynamic/Provider/HttpQl.php index dbffc02d..640807c4 100644 --- a/src/Pckg/Dynamic/Provider/HttpQl.php +++ b/src/Pckg/Dynamic/Provider/HttpQl.php @@ -2,6 +2,9 @@ namespace Pckg\Dynamic\Provider; +use Pckg\Dynamic\Resolver\Record; +use Pckg\Dynamic\Resolver\Table; +use Pckg\Dynamic\Resolver\TableQl; use Pckg\Framework\Provider; class HttpQl extends Provider @@ -20,6 +23,14 @@ public function routes() 'api.httpql.definition' => route('/api/http-ql/definition', 'definition'), 'api.httpql.export' => route('/api/http-ql/export', 'export'), 'api.httpql.download' => route('/api/http-ql/download', 'download'), + 'api.httpql.upload' => route('/api/http-ql/upload', 'upload'), + 'api.httpql.table' => route('/api/http-ql/[table]', 'table')->resolvers([ + 'table' => TableQl::class, + ]), + 'api.httpql.record' => route('/api/http-ql/[table]/[record]', 'record')->resolvers([ + 'table' => TableQl::class, + 'record' => Record::class, + ]), ]), ]; } diff --git a/src/Pckg/Dynamic/Resolver/TableQl.php b/src/Pckg/Dynamic/Resolver/TableQl.php index 08110677..2d91f3e9 100644 --- a/src/Pckg/Dynamic/Resolver/TableQl.php +++ b/src/Pckg/Dynamic/Resolver/TableQl.php @@ -15,6 +15,7 @@ class TableQl implements RouteResolver * @var Dynamic */ protected $dynamic; + public function __construct(Dynamic $dynamic) { $this->dynamic = $dynamic; @@ -25,27 +26,27 @@ public function resolve($value) $dynamic = $this->dynamic; $table = runInLocale(function () use ($dynamic, $value) { - $tables = new Tables(); + $tables = new Tables(); $dynamic->joinTranslationsIfTranslatable($tables); $dynamic->joinPermissionsIfPermissionable($tables); return $tables->where(is_numeric($value) ? 'id' : 'table', $value) - ->withRelations(function (HasMany $relations) { - - $relations->joinTranslations(); - $relations->joinFallbackTranslation(); - }) - ->withFields() - ->withTabs(function (HasMany $tabs) { - - $tabs->joinTranslation(); - $tabs->joinFallbackTranslation(); - }) - ->withActions() - ->withListableFields() - ->oneOrFail(function () { - - response()->unauthorized('Table not found'); - }); + ->withRelations(function (HasMany $relations) { + + $relations->joinTranslations(); + $relations->joinFallbackTranslation(); + }) + ->withFields() + ->withTabs(function (HasMany $tabs) { + + $tabs->joinTranslation(); + $tabs->joinFallbackTranslation(); + }) + ->withActions() + ->withListableFields() + ->oneOrFail(function () { + + response()->unauthorized('Table not found'); + }); }, 'en_GB'); return $table; } diff --git a/src/Pckg/Dynamic/Service/Paginate.php b/src/Pckg/Dynamic/Service/Paginate.php index 6a6f4b05..2723a692 100644 --- a/src/Pckg/Dynamic/Service/Paginate.php +++ b/src/Pckg/Dynamic/Service/Paginate.php @@ -13,6 +13,8 @@ class Paginate protected $get; + const LIMIT = 25; + public function __construct(Get $get) { $this->get = $get; @@ -29,10 +31,10 @@ public function applyOnEntity(Entity $entity, $ormPaginator) { $entity->count(); - $limit = $ormPaginator['limit']; + $limit = $ormPaginator['limit'] ?? static::LIMIT; $entity->limit($limit == 'all' ? null : $limit); - $page = $ormPaginator['page']; + $page = $ormPaginator['page'] ?? 1; $entity->page($page); return $this; diff --git a/src/Pckg/Dynamic/Service/Sort.php b/src/Pckg/Dynamic/Service/Sort.php index 39f15b70..4d752a57 100644 --- a/src/Pckg/Dynamic/Service/Sort.php +++ b/src/Pckg/Dynamic/Service/Sort.php @@ -51,6 +51,8 @@ public function applyOnEntity(Entity $entity, $paginator = []) $directionMapper = [ 'up' => 'ASC', 'down' => 'DESC', + 'asc' => 'ASC', + 'desc' => 'DESC', ]; if ($field) { @@ -62,7 +64,7 @@ public function applyOnEntity(Entity $entity, $paginator = []) ->getExtendeeTableForField($entity->getTable(), $field->field); $entity->orderBy('`' . ($table ?? $entity->getTable()) . '`.`' . $field->field . '` ' . - ($directionMapper[$paginator['dir']] ?? 'DESC')); + ($directionMapper[$paginator['dir'] ?? 'down'] ?? 'DESC')); } else { $entity->orderBy('`' . $field->field . '` ' . ($directionMapper[$paginator['dir']] ?? 'DESC')); } diff --git a/src/Pckg/Maestro/Service/Tabelize.php b/src/Pckg/Maestro/Service/Tabelize.php index c7edd28d..6f7f5f5a 100644 --- a/src/Pckg/Maestro/Service/Tabelize.php +++ b/src/Pckg/Maestro/Service/Tabelize.php @@ -1,6 +1,6 @@ -entity = $entity; @@ -85,6 +88,13 @@ public function __construct(Entity $entity = null, $fields = []) ]); } + public function setEnriched(bool $enriched = true) + { + $this->enriched = $enriched; + + return $this; + } + public function make() { $all = $this->entity->count()->all(); @@ -225,7 +235,7 @@ public function getFields() } return $this->fields->map(function($item) { - + if (is_only_callable($item)) { return $item; } @@ -485,7 +495,7 @@ public function __toString() try { $string = ''; measure('Tabelize', function() use (&$string) { - + $string .= ''; $string .= $this->view->autoparse(); $string .= ''; @@ -557,7 +567,7 @@ public function transformRecord(Obj $record) : $field['field'])); $enriched = null; $transformed[$realKey] = $this->getRecordValue($field, $record, $enrichedValue, $enriched); - if ($enriched) { + if ($this->enriched && $enriched) { $transformed['*' . $realKey] = $enrichedValue; } } @@ -574,7 +584,7 @@ public function transformRecord(Obj $record) } } - if ($this->dataOnly) { + if ($this->dataOnly || !$this->enriched) { return $transformed; } @@ -671,10 +681,10 @@ public function getEntityActionsArray($normal = true) $template = 'tabelize/entityActions/' . $action; } - if ( - ($normal && in_array($action, ['add', 'edit', 'export', 'view', 'import', 'delete'])) || - (!$normal && !in_array($action, ['add', 'edit', 'export', 'view', 'import', 'delete'])) - ) { + if ( + ($normal && in_array($action, ['add', 'edit', 'export', 'view', 'import', 'delete'])) || + (!$normal && !in_array($action, ['add', 'edit', 'export', 'view', 'import', 'delete'])) + ) { $html .= "\n" . ''; $parsed = trim(view($template, $data)->autoparse()); if (strpos($parsed, '{') !== 0) { @@ -811,8 +821,8 @@ public function getAddUrl() public function getSavedViews() { - $savedViews = (new TableViews())->where('dynamic_table_id', $this->getDynamicTable()->id)->all()->map(function (TableView $tableView) { - + $savedViews = (new TableViews())->where('dynamic_table_id', $this->getDynamicTable()->id)->all()->map(function (TableView $tableView) { + return [ 'id' => $tableView->id, 'type' => 'saved', @@ -832,7 +842,7 @@ public function getDynamicTable() { if (!$this->table) { $this->table = (new Tables())->where('framework_entity', get_class($this->entity))->oneOrFail(function() { - + response()->notFound('Dynamic table is missing'); }); } @@ -870,4 +880,4 @@ public function setTableView(TableView $tableView = null) $this->tableView = $tableView; return $this; } -} \ No newline at end of file +} From b9e2ff65d520ff303e5b4b95b70ad285501c9bf3 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sat, 8 May 2021 17:28:46 +0200 Subject: [PATCH 22/61] Update httpql --- src/Pckg/Dynamic/Controller/HttpQl.php | 57 +++++++++++-------- src/Pckg/Dynamic/Controller/Records.php | 9 ++- src/Pckg/Dynamic/Form/Dynamic.php | 2 +- src/Pckg/Dynamic/Provider/HttpQl.php | 2 +- src/Pckg/Dynamic/Resolver/Record.php | 1 - .../Middleware/EncapsulateResponse.php | 7 +++ 6 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/Pckg/Dynamic/Controller/HttpQl.php b/src/Pckg/Dynamic/Controller/HttpQl.php index e54a76d6..d670033f 100644 --- a/src/Pckg/Dynamic/Controller/HttpQl.php +++ b/src/Pckg/Dynamic/Controller/HttpQl.php @@ -51,41 +51,28 @@ public function getTableAction(Table $table) return Reflect::method($this, 'searchIndexAction', ['table' => $table, 'tabelize' => $tabelize]); } - /** - * Insert multiple records. - */ - public function postTableAction() - { - - } - - /** - * Patch multiple records. - */ - public function patchTableAction() - { - - } - - /** - * Delete multiple records. - */ - public function deleteTableAction() + public function getRecordAction(Table $table, Record $record) { + $tabelize = resolve(Tabelize::class); + $tabelize->setEnriched(false); + return [ + 'record' => Reflect::method(Records::class, 'getViewAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord'] + ]; } - public function getRecordAction(Table $table, Record $record) + public function patchRecordAction(Table $table, Record $record) { $tabelize = resolve(Tabelize::class); $tabelize->setEnriched(false); return [ - 'record' => Reflect::method(Records::class, 'getViewAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord'] + 'record' => Reflect::method(Records::class, 'patchEditAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord'] ]; } - public function patchRecordAction(Table $table, Record $record) + // full update + public function postRecordAction(Table $table, Record $record) { $tabelize = resolve(Tabelize::class); $tabelize->setEnriched(false); @@ -103,6 +90,30 @@ public function deleteRecordAction(Table $table, Record $record) return Reflect::method(Records::class, 'deleteDeleteAction', ['table' => $table, 'record' => $record, 'tabelize' => $tabelize])['mappedRecord']; } + /** + * Insert multiple records. + */ + public function postTableAction(Table $table) + { + return Reflect::method(Records::class, 'postAddAction', ['table' => $table]); + } + + /** + * Patch multiple records. + */ + public function patchTableAction() + { + + } + + /** + * Delete multiple records. + */ + public function deleteTableAction() + { + + } + /** * This works the same as postAddAction from Record. * Except, it accepts data in other format. diff --git a/src/Pckg/Dynamic/Controller/Records.php b/src/Pckg/Dynamic/Controller/Records.php index 6cf15d90..bc4e1bdf 100644 --- a/src/Pckg/Dynamic/Controller/Records.php +++ b/src/Pckg/Dynamic/Controller/Records.php @@ -317,6 +317,7 @@ public function postAddAction(Dynamic $form, Table $table, Record $record = null $form->setTable($table); $form->setRecord($record); $form->initFields(); + if ($entity->isTranslatable()) { $form->initLanguageFields(); } @@ -326,6 +327,7 @@ public function postAddAction(Dynamic $form, Table $table, Record $record = null } $form->populateFromRequest(); + /** * Populate from session? */ @@ -623,15 +625,20 @@ protected function getTabelizesAndFunctionizes($tabs, $record, Table $table, Ent return [$tabelizes, $functionizes]; } + public function patchEditAction(Dynamic $form, Record $record, Table $table, Entity $entity) + { + return $this->postEditAction($form, $record, $table, $entity); + } + public function postEditAction(Dynamic $form, Record $record, Table $table, Entity $entity) { (new TableActions())->joinPermissionTo('execute') ->where('dynamic_table_id', $table->id) ->where('slug', 'edit') ->oneOrFail(function(){ - $this->response()->unauthorized(); }); + $table = $this->router()->resolved('table'); $entity = $table->createEntity(); $record = $entity->transformRecordToEntities($record); diff --git a/src/Pckg/Dynamic/Form/Dynamic.php b/src/Pckg/Dynamic/Form/Dynamic.php index 1fe414cf..1abc1771 100644 --- a/src/Pckg/Dynamic/Form/Dynamic.php +++ b/src/Pckg/Dynamic/Form/Dynamic.php @@ -329,7 +329,7 @@ public function initFields() $element->setHelp($field->help); $element->setAttribute('data-field-id', $field->id); - if ($field->required) { + if ($field->required && !request()->isPatch()) { $element->required(); } } diff --git a/src/Pckg/Dynamic/Provider/HttpQl.php b/src/Pckg/Dynamic/Provider/HttpQl.php index 640807c4..4e36cc8d 100644 --- a/src/Pckg/Dynamic/Provider/HttpQl.php +++ b/src/Pckg/Dynamic/Provider/HttpQl.php @@ -19,7 +19,7 @@ public function routes() 'group:api', ], ], [ - 'api.httpql' => route('/api/http-ql', 'index')/*->methods(['GET', 'SEARCH', 'PUT'])*/, + 'api.httpql' => route('/api/http-ql', 'index'), 'api.httpql.definition' => route('/api/http-ql/definition', 'definition'), 'api.httpql.export' => route('/api/http-ql/export', 'export'), 'api.httpql.download' => route('/api/http-ql/download', 'download'), diff --git a/src/Pckg/Dynamic/Resolver/Record.php b/src/Pckg/Dynamic/Resolver/Record.php index df72acd2..7075d7b5 100644 --- a/src/Pckg/Dynamic/Resolver/Record.php +++ b/src/Pckg/Dynamic/Resolver/Record.php @@ -40,7 +40,6 @@ public function resolve($value) }); return $tablesEntity->where('id', $value) ->oneOrFail(function () { - response()->unauthorized('Record not found'); }); } diff --git a/src/Pckg/Generic/Middleware/EncapsulateResponse.php b/src/Pckg/Generic/Middleware/EncapsulateResponse.php index 0459b93d..5a7d6592 100644 --- a/src/Pckg/Generic/Middleware/EncapsulateResponse.php +++ b/src/Pckg/Generic/Middleware/EncapsulateResponse.php @@ -58,6 +58,13 @@ public function execute(callable $next) // $output = Reflect::create(Generic::class)->wrapIntoGeneric($output, $template); $this->response->setOutput($output); } + } elseif (is_array($output)) { + if (isset($output['success']) && !isset($output['error'])) { + $output['error'] = false; + } else if (isset($output['error']) && !isset($output['success'])) { + $output['success'] = false; + } + $this->response->setOutput($output); } return $next(); From 644d1481c24a9b51aab253c6a59108a1a51f51a7 Mon Sep 17 00:00:00 2001 From: Bojan Rajh Date: Sun, 6 Jun 2021 22:25:40 +0200 Subject: [PATCH 23/61] Styling, actions, tabs --- src/Pckg/Dynamic/Provider/Dynamic.php | 4 ++-- src/Pckg/Maestro/View/_form.vue | 2 +- .../Maestro/View/_pckg_maestro_actions.vue | 23 ++++++++++++++----- src/Pckg/Maestro/View/_table_actions.vue | 8 +++---- src/Pckg/Maestro/public/less/maestro.less | 15 ++++++++++-- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/Pckg/Dynamic/Provider/Dynamic.php b/src/Pckg/Dynamic/Provider/Dynamic.php index 0a504d9e..ecc9cd2a 100644 --- a/src/Pckg/Dynamic/Provider/Dynamic.php +++ b/src/Pckg/Dynamic/Provider/Dynamic.php @@ -131,7 +131,7 @@ public function routes() TableRecordRelated::class, ])->mergeToData($backendData()), - 'edit' => vueRoute('/[record]/edit', '')->resolvers([ + 'edit' => vueRoute('/edit', '')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('write'); @@ -141,7 +141,7 @@ public function routes() TableRecordRelated::class, ])->mergeToData($backendData()), - 'tab' => vueRoute('/[record]/tab/[tab]', 'tabelize-functionize')->resolvers([ + 'tab' => vueRoute('/tab/[tab]', 'tabelize-functionize')->resolvers([ 'table' => function () { return resolve(TableResolver::class)->validator(function (Table $table) { $table->checkPermissionsFor('read'); diff --git a/src/Pckg/Maestro/View/_form.vue b/src/Pckg/Maestro/View/_form.vue index 936237d4..bf3bf842 100644 --- a/src/Pckg/Maestro/View/_form.vue +++ b/src/Pckg/Maestro/View/_form.vue @@ -24,7 +24,7 @@
-
+
+ + +