commit 5f6ce82fd2c737438ff8c62fd0e79eb63e0334d7 Author: Dave M Date: Tue Oct 20 14:01:34 2020 +0000 - First commit, routes and database builder are usable diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b2711bc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Dave Mc Nicoll + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..9dde68c --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "mcnd/lean-console", + "description": "A powerful enough debug console for LEAN.", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Dave Mc Nicoll", + "email": "mcndave@gmail.com" + } + ], + "require": { + "mcnd/lean": "dev-master" + }, + "autoload": { + "psr-4": { + "Lean\\Console\\": "src/" + } + } +} diff --git a/meta/i18n/en/lean.console.json b/meta/i18n/en/lean.console.json new file mode 100644 index 0000000..63c3e28 --- /dev/null +++ b/meta/i18n/en/lean.console.json @@ -0,0 +1,5 @@ +{ + "title": "Console -- LEAN", + "page-title": "LEAN - Console" + +} \ No newline at end of file diff --git a/meta/i18n/en/lean.nav.json b/meta/i18n/en/lean.nav.json new file mode 100644 index 0000000..000e983 --- /dev/null +++ b/meta/i18n/en/lean.nav.json @@ -0,0 +1,32 @@ +{ + "lean": { + "label": "Lean", + "dashboard": "Dashboard" + }, + + "storage": { + "label": "Storage", + "summary": "Summary", + "database": "Database", + "session": "Session" + }, + + "templating": { + "label": "Templating", + "picea": "Picea" + }, + + "caching": { + "label": "Caching" + }, + + "request": { + "label": "Request", + "routes": "Routes" + }, + + "email": { + "label": "Email", + "routes": "Activity" + } +} \ No newline at end of file diff --git a/meta/i18n/en/lean.request.json b/meta/i18n/en/lean.request.json new file mode 100644 index 0000000..18015de --- /dev/null +++ b/meta/i18n/en/lean.request.json @@ -0,0 +1,12 @@ +{ + "title": "Request -- LEAN", + "page-title": "LEAN - Request", + "route": { + "header": "List of active routes", + "name": "Name", + "uri": "URI", + "methods": "HTTP Methods", + "target": "class::method()" + } + +} \ No newline at end of file diff --git a/meta/i18n/en/lean.storage.json b/meta/i18n/en/lean.storage.json new file mode 100644 index 0000000..3459fd2 --- /dev/null +++ b/meta/i18n/en/lean.storage.json @@ -0,0 +1,25 @@ +{ + "title": "Storage -- LEAN", + "page-title": "LEAN - Storage", + + "database": { + "header": "List of databases", + "name": "Database", + "adapter": "Adapter", + "host": "Hostname:port", + "username": "Username", + "connection": "Connection", + + "table": { + "header": "Tables details", + "fields": "{$count} fields", + "name": "Name", + "actions": "Actions", + "table-fields" : "Fields in table", + "create": "Create table", + "createAll": "Create all tables", + "query": "SQL Query" + } + } + +} \ No newline at end of file diff --git a/meta/i18n/fr/lean.console.json b/meta/i18n/fr/lean.console.json new file mode 100644 index 0000000..0758a4d --- /dev/null +++ b/meta/i18n/fr/lean.console.json @@ -0,0 +1,7 @@ +{ + "title" : "Console -- LEAN", + "page-title": "Console", + "breadcrumb" : { + "index" : "Negundo" + } +} diff --git a/meta/i18n/fr/lean.setup.json b/meta/i18n/fr/lean.setup.json new file mode 100644 index 0000000..08fa935 --- /dev/null +++ b/meta/i18n/fr/lean.setup.json @@ -0,0 +1,7 @@ +{ + "title" : "Setup -- LEAN", + + "breadcrumb" : { + "index" : "Negundo" + } +} diff --git a/src/Controller/Console.php b/src/Controller/Console.php new file mode 100644 index 0000000..82d4719 --- /dev/null +++ b/src/Controller/Console.php @@ -0,0 +1,32 @@ + "lean.console:home") + * @param ServerRequestInterface $request + * @param array $arguments + * @return ResponseInterface + */ + public function home(ServerRequestInterface $request, array $arguments) : ResponseInterface + { + return $this->renderView("page/dashboard/index", [ + + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Request.php b/src/Controller/Request.php new file mode 100644 index 0000000..fc4c57b --- /dev/null +++ b/src/Controller/Request.php @@ -0,0 +1,41 @@ + "lean.console:request.route") + * @param ServerRequestInterface $request + * @param array $arguments + * @return ResponseInterface + */ + public function routes(ServerRequestInterface $request, array $arguments) : ResponseInterface + { + $routes = $this->container->has(UrlExtension::class) ? $this->container->get(UrlExtension::class)->getRouteList(true) : false; + + uksort($routes, function($a, $b) { + return $a <=> $b; + }); + + return $this->renderView("page/request/route", [ + 'routes' => $routes + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Storage.php b/src/Controller/Storage.php new file mode 100644 index 0000000..1f23a16 --- /dev/null +++ b/src/Controller/Storage.php @@ -0,0 +1,55 @@ + "lean.console:request.route") + * @param ServerRequestInterface $request + * @param array $arguments + * @return ResponseInterface + */ + public function database(ServerRequestInterface $request, array $arguments) : ResponseInterface + { + $connections = $this->container->has(AdapterProxy::class) ? $this->container->get(AdapterProxy::class)->connections : false; + $migrations = $this->container->has(Lib\DatabaseMigrations::class) ? $this->container->get(Lib\DatabaseMigrations::class) : false; + $migrations->getEntities(); + + $form = new FormHandler($request, new Form\Database($migrations), null); + $context = $form->context; + + return $this->renderView("page/storage/database", get_defined_vars()); + } + + public function createTable() : void + { + foreach($migrations->entities as $table) { +// $repository = $table + // $entity::repository()->createTable(); + } + } +} \ No newline at end of file diff --git a/src/Entity/Column.php b/src/Entity/Column.php new file mode 100644 index 0000000..b498fc8 --- /dev/null +++ b/src/Entity/Column.php @@ -0,0 +1,44 @@ + "columns", 'database' => "information_schema") + */ +class Column extends InformationSchema\Column +{ + + public function differsFromFieldDefinition(FieldDefinition $definition) : bool + { + switch(true) { + //case $definition-> + + // return true; + + + } + + return false; + } + +/* public static function entityCollection(...$arguments) : EntityCollection + { + return new class(...$arguments) extends EntityCollection + { + public function getEntityData() : array + { + return [ + + ]; + } + }; + } +*/ + +} \ No newline at end of file diff --git a/src/Form/Database.php b/src/Form/Database.php new file mode 100644 index 0000000..f713780 --- /dev/null +++ b/src/Form/Database.php @@ -0,0 +1,96 @@ +migration = $migration; + } + + public function initialize(FormContextInterface $context) : void + { + $context->tableExist = []; + + foreach($this->migration->entities as $entity => $table) { + + $table = Table::repository()->where(Table::field('name'), $table->tableName()) + ->where(Table::field('schema'), $table->databaseName()) + ->loadOne(); + + if ( $table ) { + #$fields = $entiy::resolveEntity()->fieldList(); + + foreach($table->columns as $col) { + dump( $entity::field($col->name) ); + } + + # if columns are different + $context->status[$entity] = [ + 'msg' => "up-to-date", + 'query' => "", + ]; + } + else { + $context->status[$entity] = [ + 'msg' => "unexisting", + 'query' => $entity::repository()->createSqlQuery()->getSqlQuery(true), + ]; + } + } + + if ( $context->formSent() ) { + + } + } + + public function validate(FormContextInterface $context) : bool + { + return $context->valid(); + } + + public function execute(FormContextInterface $context) : void + { + try { + if ( $context->create ?? false ) { + $context->create::repository()->createTable(); + } + elseif ( $context->createAll ?? false ) { + foreach(explode(',', $context->createAll) as $entity) { + $entity::repository()->createTable(); + } + } + + $this->initialize($context); + } + catch (\Exception $ex) { + dump($ex); + + $context->pushMessage(new Message( + "Une erreur inattendue semble avoir été provoquée lors de la sauvegarde des données. Le programmeur en charge du logiciel en a été avisé par courriel." + )); + + # @TODO ADD THEBUGS EMAIL SENDING HERE !!! + } + } + public function getContext(ServerRequestInterface $request) : FormContextInterface + { + return new class($request) extends FormContext { + + public array $status = []; + + public array $actions = []; + }; + } +} \ No newline at end of file diff --git a/src/Lib/ConsoleControllerTrait.php b/src/Lib/ConsoleControllerTrait.php new file mode 100644 index 0000000..85abab9 --- /dev/null +++ b/src/Lib/ConsoleControllerTrait.php @@ -0,0 +1,28 @@ + [ 'GET', 'POST', 'DELETE' ], "base" => "/~") + * @Security('locked' => false) + */ +trait ConsoleControllerTrait +{ + use \Lean\Console\ControllerTrait; + + protected ContainerInterface $container; + + public function __construct(? Picea\Picea $picea, Session $session, ContainerInterface $container) { + $this->picea = $picea; + $this->session = $session; + $this->container = $container; + // $this->mailer = $mailer; + } +} \ No newline at end of file diff --git a/src/Lib/DatabaseMigrations.php b/src/Lib/DatabaseMigrations.php new file mode 100644 index 0000000..4d7b7d5 --- /dev/null +++ b/src/Lib/DatabaseMigrations.php @@ -0,0 +1,46 @@ +folderList = $folders; + } + + public function getEntities() : void + { + $this->entities = []; + + foreach($this->folderList as $folder => $namespace) { + foreach(static::files($folder) as $file) { + $name = $file->getBasename(".".$file->getExtension()); + $entity = rtrim($namespace, "\\") . "\\{$name}"; + $this->entities[$entity] = $entity::resolveEntity(); + } + } + } + + protected static function files(string $path, string $fileExtension = "") : \Generator + { + if ( \file_exists($path) ) { + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST, \RecursiveIteratorIterator::CATCH_GET_CHILD); + + foreach ($iterator as $file) { + if ( $file->isFile() || $file->isDir() ) { + if ($fileExtension && ( $file->getExtension() === $fileExtension )) { + yield $file; + } + else { + yield $file; + } + } + } + } + } +} \ No newline at end of file diff --git a/view/base/asset/lean.css b/view/base/asset/lean.css new file mode 100644 index 0000000..7bc26ad --- /dev/null +++ b/view/base/asset/lean.css @@ -0,0 +1,43 @@ +/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:left} +.grid{box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:-webkit-box;display:flex;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;-webkit-box-flex:0;flex:0 1 auto;-webkit-flex-direction:row;-ms-flex-direction:row;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0 -8px 0 -8px}.grid.grid-nogutter{margin:0}.grid.grid-nogutter>.col{padding:0}.col{box-sizing:border-box;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-flex-grow:1;-ms-flex-positive:1;-webkit-box-flex:1;flex-grow:1;-ms-flex-preferred-size:0;-webkit-flex-basis:0;flex-basis:0;max-width:100%;min-width:0;padding:0 8px 0 8px}.col-align-top{-webkit-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start}.col-align-bottom{align-self:flex-end}.col-align-middle{-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.col-top{justify-content:flex-start !important;flex-direction:column;display:flex}.col-bottom{justify-content:flex-end !important;flex-direction:column;display:flex}.col-middle{justify-content:center;flex-direction:column;display:flex}.grid-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.grid-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.grid-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.grid-around{justify-content:space-around}.grid-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.col-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.col-last{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.grid-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.col-fixed{flex:initial}.col-grow-2{flex-grow:2}.col-grow-3{flex-grow:3}.col-grow-4{flex-grow:4}.col-grow-5{flex-grow:5}.col-grow-6{flex-grow:6}.col-grow-7{flex-grow:7}.col-grow-8{flex-grow:8}.col-grow-9{flex-grow:9}.col-grow-10{flex-grow:10}.col-grow-11{flex-grow:11}.col-1{-ms-flex-preferred-size:8.33333%;-webkit-flex-basis:8.33333%;flex-basis:8.33333%;max-width:8.33333%}.col-2{-ms-flex-preferred-size:16.66667%;-webkit-flex-basis:16.66667%;flex-basis:16.66667%;max-width:16.66667%}.col-3{-ms-flex-preferred-size:25%;-webkit-flex-basis:25%;flex-basis:25%;max-width:25%}.col-4{-ms-flex-preferred-size:33.33333%;-webkit-flex-basis:33.33333%;flex-basis:33.33333%;max-width:33.33333%}.col-5{-ms-flex-preferred-size:41.66667%;-webkit-flex-basis:41.66667%;flex-basis:41.66667%;max-width:41.66667%}.col-6{-ms-flex-preferred-size:50%;-webkit-flex-basis:50%;flex-basis:50%;max-width:50%}.col-7{-ms-flex-preferred-size:58.33333%;-webkit-flex-basis:58.33333%;flex-basis:58.33333%;max-width:58.33333%}.col-8{-ms-flex-preferred-size:66.66667%;-webkit-flex-basis:66.66667%;flex-basis:66.66667%;max-width:66.66667%}.col-9{-ms-flex-preferred-size:75%;-webkit-flex-basis:75%;flex-basis:75%;max-width:75%}.col-10{-ms-flex-preferred-size:83.33333%;-webkit-flex-basis:83.33333%;flex-basis:83.33333%;max-width:83.33333%}.col-11{-ms-flex-preferred-size:91.66667%;-webkit-flex-basis:91.66667%;flex-basis:91.66667%;max-width:91.66667%}.col-12{-ms-flex-preferred-size:100%;-webkit-flex-basis:100%;flex-basis:100%;max-width:100%}@media only screen and (max-width: 480px){.col-sm{flex:100%;max-width:100%}}@media only screen and (max-width: 624px){.col-md{flex:100%;max-width:100%}}@media only screen and (max-width: 744px){.col-lg{flex:100%;max-width:100%}} +.align-items-center{align-items:center}.align-items-top{align-items:start} + +:root { + --color-red: #d47474 +} + +.text-center{text-align:center;}.text-right{text-align:right}.text-left{text-align:left;} + +[class^="btn-"], [class~=" btn-"] { display: inline-block; font-weight: 400; text-align: center; white-space: nowrap; vertical-align: middle; user-select: none; border: 1px solid transparent; padding: .375rem .75rem; font-size: 1rem; line-height: 1.5; border-radius: .25rem; cursor:pointer; transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; background:rgba(0,0,0,0.3); color:rgba(255,255,255,0.8); } +[class^="btn-"]:hover, [class~=" btn-"]:hover {border-color: rgba(0, 0, 0, 0.5);text-decoration: underline;} +.btn-red {background: rgba(255,0,0,0.5);color: rgba(255, 255, 255, 0.9);} + +code {white-space:pre;font-family:monospace;color: #cacaca;background: #434446;display: block;padding: 1rem;line-height: 1.5em;border: 1px solid #2e2e30;} +h1 {font-size:2rem;color:#525960} +body {font-family:Helvetica Neue, Helvetica, Arial, sans-serif;} +summary {cursor:pointer;} + +#body-main {background:#ccc;min-height:calc(100vh - 90px);display:flex} + +/* Header */ +#body-header {background: #385075; color:#fff; min-height:60px;line-height:60px;padding:0 1rem} +#body-header .page-title {font-size:1.5rem} +#body-header .page-title:before {content:"🔳"; margin-right:10px} + +/* Footer */ +#body-footer {background: #2e2e30;color: #fff;height: 30px;line-height: 30px;font-size: 0.8rem;padding: 0 0.5rem;text-align: right;border-top:2px solid #434446;} + +/* Sidebar */ +#main-nav {background:#393a3c;border-top:2px solid #172842;min-width:210px;color:#fff;font-family:consolas, courier new, monospace;font-size:0.9rem} +#main-nav label {background:rgba(0,0,0,0.2);text-transform:uppercase ; display:block;padding:0.8rem 1rem;font-size:1.15em;} +#main-nav label:before {content:"⊙"; margin-right:10px} +#main-nav a {color: #efecec;text-decoration:none;display:block;padding:0rem 1rem;background:rgba(255,255,255,0.05);transition:all 0.3s ease;line-height:3em;font-size:0.9em} +#main-nav a:before {content:"›"; margin-right:10px;line-height:3em} +#main-nav a:hover {background:rgba(255,255,255,0.1)} +#main-nav li + li {border-top:1px solid #555} + +/* Main content */ +#main-content {padding:4vh 2vw;border-top:2px solid #172842;width:100%;} +#main-content section {border-radius:4px;box-shadow: 1px 1px 3px rgba(0,0,0,0.5)} +#main-content section article {background:#fff;padding:2vh 1vw;} +#main-content section header {background:#e8e8e8;padding:2vh 1vw;} \ No newline at end of file diff --git a/view/base/console/layout.phtml b/view/base/console/layout.phtml new file mode 100644 index 0000000..51bf499 --- /dev/null +++ b/view/base/console/layout.phtml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + {{ title() }} + + + + {% section "head" %}{% endsection %} + + + +
+ {% section "header" %}{% endsection %} +
+ +
+ {% section "nav" %} + {% view "lean/base/console/main-nav" %} + {% endsection %} + +
+ {% section "content" %}{% endsection %} +
+
+ + + + \ No newline at end of file diff --git a/view/base/console/main-nav.phtml b/view/base/console/main-nav.phtml new file mode 100644 index 0000000..c22d02a --- /dev/null +++ b/view/base/console/main-nav.phtml @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/view/base/layout/console.phtml b/view/base/layout/console.phtml new file mode 100644 index 0000000..f4e41b5 --- /dev/null +++ b/view/base/layout/console.phtml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + {{ title() }} + + + + {% section "head" %}{% endsection %} + + + +
{% section "header" %}{% endsection %}
+
{% section "content" %}{% endsection %}
+ + + \ No newline at end of file diff --git a/view/page/dashboard/index.phtml b/view/page/dashboard/index.phtml new file mode 100644 index 0000000..2829bf0 --- /dev/null +++ b/view/page/dashboard/index.phtml @@ -0,0 +1,13 @@ +{% extends "lean/base/console/layout" %} + +{% language.set "lean.console" %} + +{% title _("title") %} + +{% section "header" %} +
{% _ "page-title" %}
+{% endsection %} + +{% section "content" %} + +{% endsection %} \ No newline at end of file diff --git a/view/page/request/route.phtml b/view/page/request/route.phtml new file mode 100644 index 0000000..4452bac --- /dev/null +++ b/view/page/request/route.phtml @@ -0,0 +1,49 @@ +{% extends "lean/base/console/layout" %} + +{% language.set "lean.request" %} + +{% title _("title") %} + +{% section "header" %} +
{% _ "page-title" %}
+{% endsection %} + +{% section "content" %} +
+
+

{% _ 'route.header' %}

+
+ +
+ {% if $routes %} + +
{% _ 'route.name' %}
+
{% _ 'route.uri' %}
+
{% _ 'route.methods' %}
+
{% _ 'route.target' %}
+
+ + {% foreach $routes as $name => $route %} +
+ {{ $name }} +
{{ $route['route'] }}
+
{{ implode(', ', $route['routeMethods']) }}
+
+ {{ $route['class'] }}::{{ $route['classMethod'] }} +
+
+ {% endforeach %} + + {% else %} + {% _ 'routeless' %} + {% endif %} +
+
+ + +{% endsection %} \ No newline at end of file diff --git a/view/page/setup/index.phtml b/view/page/setup/index.phtml new file mode 100644 index 0000000..de5206a --- /dev/null +++ b/view/page/setup/index.phtml @@ -0,0 +1,7 @@ +{% extends "lean/base/layout/console" %} + + +{% section "content" %} + Welcome to Setup! + +{% endsection %} \ No newline at end of file diff --git a/view/page/storage/database.phtml b/view/page/storage/database.phtml new file mode 100644 index 0000000..e38c92b --- /dev/null +++ b/view/page/storage/database.phtml @@ -0,0 +1,104 @@ +{% extends "lean/base/console/layout" %} + +{% language.set "lean.storage" %} + +{% title _("title") %} + +{% section "header" %} +
{% _ "page-title" %}
+{% endsection %} + +{% section "content" %} +
+
+

{% _ 'database.header' %}

+
+ +
+ {% if $connections %} + +
{% _ 'database.connection' %}
+
{% _ 'database.adapter' %}
+
{% _ 'database.host' %}
+
{% _ 'database.name' %}
+
{% _ 'database.username' %}
+
+ + {% foreach $connections as $connection %} + {% php $conf = $connection->getConfiguration(); %} + +
+
{{ $connection->name }}
+
{{ $conf['adapter'] }}
+
{{ $conf['host'] }}:{{ $conf['port'] }}
+
{{ $conf['database'] }}
+
{{ $conf['username'] }}
+
+ +
+ + {% _ 'database.table.header' %} + + +
+ +
{% _ 'database.table.name' %}
+
{% _ 'database.table.table-fields' %}
+
{% _ 'database.table.query' %}
+
{% _ 'database.table.actions' %}
+
+ + {% ui.form.post "database" %} + {% foreach array_filter($migrations->entities, fn($e) => $e->databaseAdapter() === $connection) as $entity => $item %} +
+
📄 {{ $item->tableName() }}
+
{% _ "database.table.fields", [ 'count' => count( $item->fieldList() ) ] %}
+
+ {% if $context->status[$entity]['query'] %} + {{ $context->status[$entity]['query'] }} + {% else %} +
🗸 This table is up-to-date
+ {% endif %} +
+
+ {% switch $context->status[$entity]['msg'] %} + {% case 'unexisting' %} + {% php $createAll[] = $entity %} + +
+ +
+ {% break %} + {% endswitch %} +
+
+ {% endforeach %} + + {% if ($createAll ?? 0) > 1 %} +
+ +
+ {% endif %} + {% ui.endform %} +
+
+ {% endforeach %} + {% endif %} +
+
+ + +{% endsection %} \ No newline at end of file