50 Commits
Author SHA1 Message Date
Dave Mc Nicoll d8b208426a - Removed Database (again) from form) 2024-12-09 16:41:44 +00:00
Dave Mc Nicoll 3a8e56a617 - Moved Database into migration folder (form) 2024-12-02 15:25:03 -05:00
mcndave 39b02507a3 - Fixed path entity naming 2024-11-17 19:27:30 -05:00
Dave Mc Nicoll ce2b9399c2 Merge branch 'master' of https://git.mcnd.ca/mcndave/lean-console 2024-11-13 14:04:01 -05:00
Dave Mc Nicoll cd38800131 Merge branch 'notes-2.x' 2024-11-13 14:03:51 -05:00
Dave Mc Nicoll 8c71d0b4d8 - Removed firewall middleware 2024-11-12 13:56:12 +00:00
Dave Mc Nicoll 0b1286c05f - WIP on CLI 2024-11-11 20:19:24 +00:00
Dave Mc Nicoll e260177943 - Removed firewall parts, moved into another module 2024-11-10 13:09:23 +00:00
Dave Mc Nicoll 73fca52013 - Fixed a bug where an empty definition would crash the migration: 2024-11-01 16:14:52 -04:00
Dave Mc Nicoll 474ec986a6 - Work done URL overridding 2024-10-29 14:13:59 +00:00
Dave Mc Nicoll ac568b1750 - WIP on Lean console definition change 2024-08-30 19:01:21 +00:00
Dave Mc Nicoll d76148fed9 Merge branch 'master' into notes-2.x 2024-05-21 13:04:28 +00:00
Dave Mc Nicoll e032c89fdc - Fixed Lean' console default adapter 2024-05-21 13:04:11 +00:00
Dave Mc Nicoll 6001ecdecd - Fixed lean console name 2024-05-20 18:56:39 +00:00
mcndave 38638b5ad4 - WIP on Notes v2.x 2024-05-09 19:48:21 +00:00
mcndave 91ddd4d64c - Ignore most method of ControllerTrait 2024-05-09 19:47:05 +00:00
mcndave fd51903a8a - Started WIP on firewall 2023-12-04 12:32:25 -05:00
mcndave 55f5071475 - Begin work on firewall 2023-11-17 23:35:56 -05:00
mcndave e78ee3a458 - Prepping to begin the firewall module 2023-11-17 22:33:23 -05:00
mcndave a5f305fb7f - Removed an empty style 2023-11-08 06:51:45 -05:00
mcndave a5d8e0a1aa - Added config autoload 2023-11-07 16:25:26 +00:00
mcndave 10317a55f2 - Fixed default layout indentation 2023-11-07 16:22:54 +00:00
mcndave 0de4a9d05a - Merged latest work 2023-11-03 20:21:27 -04:00
mcndave e898c6a23e - Added a new phpinfo menu item: 2023-10-31 16:12:26 +00:00
mcndave 64b9a779de - tmp fix for css path while implementing path from picea-asset url builder 2023-10-31 14:19:11 +00:00
mcndave ce5a97ce45 Merge branch 'master' of https://git.mcnd.ca/mcndave/lean-console 2023-10-30 15:24:26 +00:00
mcndave ea82d8dd08 - WIP on assets 2023-10-30 15:24:12 +00:00
mcndave b64f416fc0 - WIP on asset 2023-10-17 21:59:41 -04:00
mcndave e3de6146ec - WIP on picea's asset. 2023-10-17 20:13:44 -04:00
mcndave 58a96c4b5c - WIP on Lean's autoload component 2023-10-17 18:04:13 +00:00
mcndave 74d88dc8bf - Fixed typo 2023-10-17 17:27:17 +00:00
mcndave 406694ce51 - WIP on Lean's definitions autoload 2023-10-17 17:21:03 +00:00
mcndave 6be483dcf7 - small quick css patch 2023-10-12 13:05:45 -04:00
mcndave 7ec6aa3f06 - Minor adjustment made 2023-09-19 23:51:49 -04:00
mcndave fbfbd48eb8 - Reworked the UI a bit 2023-09-19 23:39:28 -04:00
Dave Mc Nicoll 7b4d1e5cd7 - Small bugfixe in database migration tool 2023-08-31 09:17:29 -04:00
mcndave d133ac662e - Update on database migration 2023-08-29 20:28:45 +00:00
mcndave 5035a65672 - WIP on database migration 2023-07-14 19:14:50 -04:00
Dave Mc Nicoll f66ac02bcd - Working on databases migrations 2023-05-30 15:36:01 -04:00
mcndave 963598764a - WIP on Alter table 2023-03-30 15:25:27 +00:00
mcndave f9229b890d - WIP on SQLite migration 2023-03-27 18:39:20 +00:00
mcndave eda0ee6f33 - Minor bugfixes dones 2023-03-23 15:07:35 +00:00
mcndave bf1bec644b - Still WIP on storage and a new Update function also started 2023-03-22 19:09:37 -04:00
mcndave 689120dd44 Merged attributes with current main 2023-01-31 14:18:00 +00:00
mcndave 6ff29a576c - Some bugfixes were made and annotations were converted into attributes 2023-01-21 20:27:08 +00:00
mcndave 9c8f9903fc Merge branch 'master' of https://git.mcnd.ca/mcndave/lean-console 2022-11-29 19:44:39 +00:00
mcndave 24e5490c71 - Work done on the console to have at least some working functionality from every parts 2022-11-29 19:29:15 +00:00
Dave Mc Nicoll 94b5aff9e9 - Fixed the unmerged code from previous push 2022-11-11 13:58:50 +00:00
Dave Mc Nicoll 9c5cf3d1b1 Merge branch 'master' of https://git.mcnd.ca/mcndave/lean-console 2022-10-10 15:32:12 +00:00
Dave Mc Nicoll da72314c62 - Quickfix from error found during PHP 8 migration 2022-10-10 15:31:55 +00:00
58 changed files with 1462 additions and 304 deletions

No files matched your search

@@ -1,6 +1,8 @@
/*! 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}
.justify-content-around{justify-content: space-around;}.justify-content-end{justify-content: end}
.flex {display:flex}
:root {
--color-red: #d47474
@@ -8,36 +10,45 @@
.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-"], [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; 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); text-decoration:none; }
[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);}
.btn-red {background: rgba(155,0,0,0.5);color: rgba(255, 255, 255, 0.9);}
.btn-green {background: rgba(0,155,0,0.5);color: rgba(255, 255, 255, 0.9);}
.btn-blue {background: rgba(0,0,155,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{background:#f3f3f9}
code {white-space:pre-line;font-family:monospace;color: #e6e6e6;background: #343537;display: block;padding: 1rem;line-height: 1.5em;border: 1px solid #2e2e30;}
body {font-family:Helvetica Neue, Helvetica, Arial, sans-serif;}
summary {cursor:pointer;}
#body-main {background:#ccc;min-height:calc(100vh - 90px);display:flex}
#body-main {min-height:calc(100vh - 30px);display:flex}
/* Header */
#body-header {background: #6b7fa8; 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}
#body-header {background: #fff; color:#fff; min-height:60px;line-height:60px;padding:0 1rem;position:sticky;top:0;border-bottom:1px solid #ebedee;}
#body-header > div {min-height: 60px;}
#right-panel {max-width:calc(100% - 240px);width:100%;margin-left:auto}
#subheader {background:#fff; padding: 1rem 1.4rem;display:flex;justify-content: space-between;box-shadow:0 1px 2px rgba(55,65,75,0.15)}
#subheader h1 {font-size:1.1rem;font-size:inherit; font-weight:bold}
#subheader .breadcrumb {font-size:0.9rem;display:flex;align-items:end}
#subheader .breadcrumb-item + .breadcrumb-item:before {content:"›";padding:0 6px;}
/* Footer */
#body-footer {background: #475262;color: #fff;height: 30px;line-height: 30px;font-size: 0.8rem;padding: 0 0.5rem;text-align: right;border-top:2px solid #434446;}
#body-footer {background: #fff;color: #333;height: 30px;line-height: 30px;font-size: 0.8rem;padding: 0 0.5rem;text-align: right;border-top:1px solid #ebedee;}
/* Sidebar */
#main-nav {background:#6b7fa8;border-top:2px solid #44526f;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 {background:#242528;width:240px;color:#fff;font-family:consolas, courier new, monospace;font-size:0.9rem;position:fixed;top:0;bottom:0;overflow-y:scroll;padding-bottom:2rem;border-right: 2px solid #333;}
#main-nav .app-title {font-size:1.3rem; text-align:center;padding:1.8rem 0}
#main-nav .app-title:before {content:"🔳"; margin-right:10px}
#main-nav label {color: #a4a4a4;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 {color: #efecec;text-decoration:none;display:block;padding:0 1rem 0 2rem;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 #7d7d7d;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;}
#main-content {padding:4vh 2vw;width:100%;margin-left:auto;}
#main-content section {border-radius:0.3rem;box-shadow: 0 1px 2px rgba(56,65,74,.15)}
#main-content section article {border-radius:0.3rem;font-family: Courier New , Courier, monospace;font-size: 0.8em;background:#fff;padding:1.5rem;}
#main-content section header {border-top-left:0.3rem;border-top-right:4px;background:#fff;padding:1rem 1rem;font-size:1.2em;color: #4b4848;border-bottom:1px solid #e9ebec;display:flex;align-items:center}
#main-content section footer {border-bottom-left:0.3rem;border-bottom-right:0.3rem;background:#f9f9f9;padding:2vh 1vw;}
+14 -1
View File
@@ -6,7 +6,7 @@
"authors": [
{
"name": "Dave Mc Nicoll",
"email": "mcndave@gmail.com"
"email": "info@mcnd.ca"
}
],
"require": {
@@ -16,5 +16,18 @@
"psr-4": {
"Lean\\Console\\": "src/"
}
},
"extra" : {
"lean" : {
"autoload": {
"definitions" : [
"meta/definitions/software.php",
"meta/definitions/storage.php"
],
"config": [
"meta/config.php"
]
}
}
}
}
+20
View File
@@ -0,0 +1,20 @@
<?php
return [
'lean' => [
'autoload' => [
getenv('DEBUG') ? 'lean.console' : null,
]
],
'ulmus' => [
'connections' => [
'lean.console' => [
'adapter' => 'SQLite',
'path' => getenv('PROJECT_PATH') . DIRECTORY_SEPARATOR . "var/lean-console.sqlite3",
'pragma_begin' => array_filter([ "foreign_keys=ON", "synchronous=NORMAL", getenv('DEBUG') ? "journal_mode=WAL" : "" ]),
'pragma_close' => [ "analysis_limit=500", "optimize" ],
],
],
],
];
+24 -5
View File
@@ -2,30 +2,49 @@
use Lean\Console\Lib\DatabaseMigrations;
$path = dirname(__DIR__, 2);
return [
'lean.console' => [
'picea' => [
'context' => Lean\Console\View::class,
'view' => [
[
'path' => getenv("PROJECT_PATH") . "/vendor/mcnd/lean-console/view/",
'path' => implode(DIRECTORY_SEPARATOR, [ $path , "view", '' ]),
'order' => 99,
],
],
'asset' => [
[
'path' => implode(DIRECTORY_SEPARATOR, [ $path, "asset", '' ]),
'order' => 10
],
],
],
'ulmus' => [],
'ulmus' => [
'entities' => [
'Lean\\Console\\Entity\\Firewall' => implode(DIRECTORY_SEPARATOR, [ $path , "src", "Entity", "Firewall" ]),
],
],
'tell' => [
'json' => [
[
'path' => getenv("PROJECT_PATH") . "/vendor/mcnd/lean-console/meta/i18n",
'path' => implode(DIRECTORY_SEPARATOR, [ $path, "meta", "i18n", "" ]),
'order' => 99,
],
]
],
'routes' => [
'Lean\\Console\\Controller' => getenv("PROJECT_PATH") . "/vendor/mcnd/lean-console/src/Controller/",
'cli' => [
'Lean\\Console\\Cli' => implode(DIRECTORY_SEPARATOR, [ $path, "src", "Cli", "" ]),
],
'routes' => ! getenv('DEBUG') ? [] : [
'Lean\\Console\\Controller' => implode(DIRECTORY_SEPARATOR, [ $path, "src", "Controller", "" ]),
],
],
+27
View File
@@ -0,0 +1,27 @@
<?php
use Psr\Container\ContainerInterface;
use Ulmus\ConnectionAdapter,
Ulmus\Container\AdapterProxy;
use Storage\Session;
use function DI\autowire, DI\create, DI\get;
return [
/* 'lean:adapter.sqlite' => function($c) {
$adapter = new ConnectionAdapter('lean.console', $c->get('config')['ulmus'], false);
$adapter->resolveConfiguration();
return $adapter;
},
# @TODO BACKWARD COMPATIBILIY, TO BE REMOVED SOON !
'console.adapter' => function($c) {
$adapter = new ConnectionAdapter('lean.console', $c->get('config')['ulmus'], false);
$adapter->resolveConfiguration();
return $adapter;
}*/
];
+6
View File
@@ -0,0 +1,6 @@
{
"title": "Caching -- LEAN",
"page-title": "LEAN - Caching",
"clear": "Clear",
"breadcrumb": "Caching"
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"title": "Console -- LEAN",
"page-title": "LEAN - Console"
"page-title": "Console"
}
+10
View File
@@ -0,0 +1,10 @@
{
"title" : "Debugging -- LEAN",
"page-title": "Debugging",
"logs": {
"breadcrumb": "Logs"
},
"phpinfo": {
"breadcrumb": "phpinfo()"
}
}
+9 -1
View File
@@ -1,7 +1,8 @@
{
"lean": {
"label": "Lean",
"dashboard": "Dashboard"
"dashboard": "Dashboard",
"update": "Update(s)"
},
"storage": {
@@ -20,6 +21,13 @@
"label": "Caching"
},
"debugging": {
"label": "Debugging",
"logs": "Logs",
"phpinfo": "PhpInfo"
},
"request": {
"label": "Request",
"routes": "Routes"
+1
View File
@@ -2,6 +2,7 @@
"title": "Request -- LEAN",
"page-title": "LEAN - Request",
"route": {
"breadcrumb": "Routes",
"header": "List of active routes",
"name": "Name",
"uri": "URI",
+6 -3
View File
@@ -4,21 +4,24 @@
"database": {
"header": "List of databases",
"breadcrumb": "Database",
"name": "Database",
"adapter": "Adapter",
"host": "Hostname:port",
"username": "Username",
"connection": "Connection",
"table": {
"header": "Tables details",
"fields": "{$count} fields",
"name": "Name",
"name": "Table Name",
"actions": "Actions",
"table-fields" : "Fields in table",
"create": "Create table",
"createAll": "Create all tables",
"query": "SQL Query"
"query": "SQL Query",
"alter": "Alter table",
"alterAll": "Alter all tables",
"uptodate": "This table is up-to-date"
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"title": "Templating -- LEAN",
"page-title": "LEAN - Templating",
"breadcrumb": "Templating",
"header": "Views"
}
+8
View File
@@ -0,0 +1,8 @@
{
"title": "Update -- LEAN",
"page-title": "LEAN - Update",
"git": {
"breadcrumb": "Update",
"header": "Git Status"
}
}
-1
View File
@@ -2,6 +2,5 @@
"title" : "Console -- LEAN",
"page-title": "Console",
"breadcrumb" : {
"index" : "Negundo"
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"title" : "Debugging -- LEAN",
"page-title": "Déboguage",
"logs": {
"breadcrumb": "Journaux d'événements"
},
"phpinfo": {
"breadcrumb": "phpinfo()"
}
}
+6
View File
@@ -20,6 +20,12 @@
"label": "Caching"
},
"debugging": {
"label": "Déboguage",
"logs": "Journaux d'événements",
"phpinfo": "PhpInfo"
},
"request": {
"label": "Request",
"routes": "Routes"
+6 -1
View File
@@ -13,13 +13,18 @@
"table": {
"header": "Tables details",
"fields": "{$count} fields",
"name": "Name",
"name": "Table Name",
"actions": "Actions",
"table-fields" : "Fields in table",
"create": "Create table",
"createAll": "Create all tables",
"query": "SQL Query"
}
},
"session": {
"header": "Liste des sessions",
"breadcrumb": "Sessions",
"count": "{$count} session(s)"
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"title" : "Console -- LEAN",
"page-title": "Console",
"breadcrumb" : {
"index" : "Negundo"
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace Lean\Console\Cli;
use Notes\CLI\Attribute\{Option, Command};
use Psr\Http\Message\{ServerRequestInterface, ResponseInterface};
use Lean\Console\{Lib, };
# https://www.asciiart.eu/text-to-ascii-art
#[Command(description: PHP_EOL . <<<CLI
#[color:gray, bg: black]╔═════════════════════════╗[#]
#[color:gray, bg: black]║ _ ║[#]
#[color:gray, bg: black]║ | | ___ __ _ _ __ ║[#]
#[color:gray, bg: black]║ | | / _ \/ _` | '_ \ ║[#]
#[color:gray, bg: black]║ | |__| __/ (_| | | | | ║[#]
#[color:gray, bg: black]║ |_____\___|\__,_|_| |_| ║[#]
#[color:gray, bg: black]║ ║[#]
#[color:gray, bg: black]╚═════════════════════════╝[#]
Try #[color:gray, bg: black]'lean console --help'[#] for more information.
CLI
, command: 'console')]
#[Option(toggle: ['-h', '--help'], description: "Display help for the given command. When no command is given display help for the list command")]
#[Option(toggle: ['-q', '--quiet'], description: "Do not output any message")]
#[Option(toggle: ['-n', '--no-interaction'], description: "Run script without user interaction")]
#[Option(toggle: ['-v', '-vv', '-vvv', '--verbose'], description: "Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug", argument: Option::ARGUMENT_OPTIONAL)]
class Console
{
use Lib\ConsoleControllerTrait;
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace Lean\Console\Cli;
use Notes\CLI\Attribute\{Option, Command};
use Psr\Http\Message\{ServerRequestInterface, ResponseInterface};
use Lean\Console\{Lib, };
# https://www.asciiart.eu/text-to-ascii-art
#[Command(description: PHP_EOL . <<<CLI
#[color:gray, bg: black]╔═════════════════════════╗[#]
#[color:gray, bg: black]║ _ ║[#]
#[color:gray, bg: black]║ | | ___ __ _ _ __ ║[#]
#[color:gray, bg: black]║ | | / _ \/ _` | '_ \ ║[#]
#[color:gray, bg: black]║ | |__| __/ (_| | | | | ║[#]
#[color:gray, bg: black]║ |_____\___|\__,_|_| |_| ║[#]
#[color:gray, bg: black]║ ║[#]
#[color:gray, bg: black]║ STORAGE ║[#]
#[color:gray, bg: black]╚═════════════════════════╝[#]
Try #[color:gray, bg: black]'lean console storage --help'[#] for more information.
CLI
, command: 'console storage')]
#[Option(toggle: ['-h', '--help'], description: "Display help for the given command. When no command is given display help for the list command")]
#[Option(toggle: ['-q', '--quiet'], description: "Do not output any message")]
#[Option(toggle: ['-n', '--no-interaction'], description: "Run script without user interaction")]
#[Option(toggle: ['-v', '-vv', '-vvv', '--verbose'], description: "Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug", argument: Option::ARGUMENT_OPTIONAL)]
class Storage
{
use Lib\ConsoleControllerTrait;
#[Command(description: "Generate entities based on an existing connection", command: "entity:generate")]
#[Option(toggle: ['-l', '--list'], description: "")]
public function generate_entity(ServerRequestInterface $request, array $arguments): ResponseInterface
{
dump($arguments);
return $this->renderCLI($request, ":)");
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace Lean\Console\Controller;
use League\Route\Router;
use Picea\{FileFetcher, Picea, Caching\Opcache, Extension\UrlExtension, Ui\Method\FormHandler};
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Lean\Console\{ Form, Lib };
use Notes\Tell\Attribute\Language, Notes\Route\Attribute\Method\Route;
class Caching extends Console {
use Lib\ConsoleControllerTrait;
#[Route(route: "/caching/picea", name: "lean.console:caching")]
public function picea(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
$list = [];
if ( isset($this->picea) ) {
new FormHandler($request, new Form\Caching\Picea($this->picea, $list), $this->pushContext(new Lib\FormContext($request, "caching.picea")));
}
return $this->renderView("lean-console/page/caching/picea", get_defined_vars());
}
}
+15 -11
View File
@@ -2,28 +2,32 @@
namespace Lean\Console\Controller;
use Picea\Ui\Method\FormHandler;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Notes\Route\Annotation\Object\Route as RouteParam,
Notes\Route\Annotation\Method\Route,
Notes\Security\Annotation\Security,
Notes\Tell\Annotation\Language;
use Notes\Tell\Attribute\Language, Notes\Route\Attribute\Method\Route;
use \Lean\Console\Lib;
use \Lean\Console\{ Lib, Form };
/**
* @Language("lean.console")
*/
class Console {
use Lib\ConsoleControllerTrait;
/**
* @Route("/", "name" => "lean.console:home")
*/
#[Route(route: "/", name: "lean.console:home")]
public function home(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
return $this->renderView("lean-console/page/dashboard/index", [
]);
}
#[Route(route: "/update", name: "lean.console:update")]
public function update(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
new FormHandler($request, $git = new Form\Update\Git(getenv('PROJECT_PATH')));
$status = iterator_to_array($git->run("/usr/bin/git status -s"));
$diff = iterator_to_array($git->run("/usr/bin/git diff"));
return $this->renderView("lean-console/page/update/index", get_defined_vars());
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace Lean\Console\Controller;
use League\Route\Router;
use Picea\{FileFetcher, Picea, Caching\Opcache, Extension\UrlExtension, Ui\Method\FormHandler};
use Lean\File;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Lean\Console\{ Form, Lib };
use Notes\Tell\Attribute\Language, Notes\Route\Attribute\Method\Route;
class Debugging extends Console {
use Lib\ConsoleControllerTrait;
#[Route(route: "/debugging/logs", name: "lean.console:debugging-logs")]
public function logs(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
$list = [];
new FormHandler($request, new Form\Debugging\Logs(), $this->pushContext(new Lib\FormContext($request, "debugging.logs")));
$path = getenv('LOGS_PATH');
$files = array_map(fn($e) => basename($e), glob("$path/*"));
$default = basename(ini_get('error_log'));
$open = end($files);
$content = File::tail($path . DIRECTORY_SEPARATOR . $open, 100);
return $this->renderView("lean-console/page/debugging/logs", get_defined_vars());
}
#[Route(route: "/debugging/phpinfo", name: "lean.console:debugging-phpinfo")]
public function phpinfo(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
ob_start() ;
phpinfo() ;
$phpinfo = ob_get_contents() ;
ob_end_clean() ;
return $this->renderView("lean-console/page/debugging/phpinfo", get_defined_vars());
}
}
-28
View File
@@ -1,28 +0,0 @@
<?php
namespace Lean\Console\Controller;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Notes\Route\Annotation\Object\Route as RouteParam,
Notes\Route\Annotation\Method\Route,
Notes\Security\Annotation\Security,
Notes\Tell\Annotation\Language;
use \Lean\Console\Lib;
/**
* @Language("lean.dev")
*/
class Dev {
use Lib\ConsoleControllerTrait;
/**
* @Route("/phpinfo", "name" => "lean.dev:phpinfo")
*/
public function home(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
phpinfo();
die();
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Lean\Console\Controller;
class Firewall
{
}
+13 -19
View File
@@ -3,39 +3,33 @@
namespace Lean\Console\Controller;
use League\Route\Router;
use Lean\Routing;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Notes\Route\Annotation\Object\Route as RouteParam,
Notes\Route\Annotation\Method\Route,
Notes\Security\Annotation\Security,
Notes\Tell\Annotation\Language;
use Notes\Tell\Attribute\Language, Notes\Route\Attribute\Method\Route;
use \Lean\Console\Lib;
use Picea\Extension\UrlExtension;
/**
* @Language("lean.request")
*/
class Request extends Console {
use Lib\ConsoleControllerTrait;
/**
* @Route("/request/routes", "name" => "lean.console:request.route")
* @param ServerRequestInterface $request
* @param array $arguments
* @return ResponseInterface
*/
#[Route(route: "/request/routes", name: "lean.console:request.route")]
public function routes(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
$routes = $this->container->has(UrlExtension::class) ? $this->container->get(UrlExtension::class)->getRouteList(true) : false;
$routing = $this->container->has(Routing::class) ? $this->container->get(Routing::class) : false;
uksort($routes, function($a, $b) {
return $a <=> $b;
if ( $routing === false ) {
throw new \Exception("Lean's routing library do not seems to be integrated into your container definition...");
}
$routes = $routing->fetchRoutesAttributes();
uasort($routes, function($a, $b) {
return ( $a->class . $a->name ) <=> ( $b->class . $b->name );
});
return $this->renderView("lean-console/page/request/route", [
'routes' => $routes
]);
return $this->renderView("lean-console/page/request/route", get_defined_vars());
}
}
+42 -20
View File
@@ -7,10 +7,7 @@ use League\Route\Router;
use Picea\Ui\Method\FormHandler;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Notes\Route\Annotation\Object\Route as RouteParam,
Notes\Route\Annotation\Method\Route,
Notes\Security\Annotation\Security,
Notes\Tell\Annotation\Language;
use Notes\Tell\Attribute\Language, Notes\Route\Attribute\Method\Route;
use \Lean\Console\Lib,
\Lean\Console\Form;
@@ -20,36 +17,61 @@ use Picea\Extension\UrlExtension;
use Ulmus\Annotation\Classes\Table,
Ulmus\Container\AdapterProxy;
/**
* @Language("lean.storage")
*/
class Storage extends Console {
use Lib\ConsoleControllerTrait;
/**
* @Route("/storage/database", "name" => "lean.console:request.route")
* @param ServerRequestInterface $request
* @param array $arguments
* @return ResponseInterface
*/
#[Route(route: "/storage/database", name: "lean.console:storage.database")]
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;
$context = (new FormHandler($request, new Form\Storage\Database\Migrate($migrations)))->context;
return $this->renderView("lean-console/page/storage/database", get_defined_vars());
}
public function createTable() : void
#[Route(route: "/storage/database/import", name: "lean.console:storage.database_import")]
public function database_import(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
foreach($migrations->entities as $table) {
// $repository = $table
// $entity::repository()->createTable();
$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 Form\Storage\Database\Import($migrations, $connections);
$context = (new FormHandler($request, $form, $this->pushContext(new Lib\FormContext($request, "database.import"))))->context;
return $this->renderView("lean-console/page/storage/database_import", get_defined_vars());
}
#[Route(route: "/storage/session", name: "lean.console:storage.session")] # migrated from: "/storage/session", "name" => "lean.console:storage.session"
public function session(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
$path = ini_get("session.save_path");
$sessions = preg_grep("/^sess_/", scandir($path));
return $this->renderView("lean-console/page/storage/session", get_defined_vars());
}
#[Route(route: "/storage/session/content/{hash}", name: "lean.console:storage.session_content")] # migrated from: "/storage/session/content/{hash}", "name" => "lean.console:storage.session_content"
public function sessionContent(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
$sess = session_encode();
session_decode(file_get_contents($this->sessionPath() . $arguments['hash']));
$data = array_combine(array_keys($_SESSION), array_values($_SESSION));
session_decode($sess);
return $this->renderJson($data);
}
protected function sessionPath() : string
{
return rtrim(ini_get("session.save_path"), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace Lean\Console\Controller;
use League\Route\Router;
use Picea\FileFetcher;
use Picea\Picea;
use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface };
use Notes\Tell\Attribute\Language, Notes\Route\Attribute\Method\Route;
use \Lean\Console\Lib;
use Picea\Extension\UrlExtension;
class Templating extends Console {
use Lib\ConsoleControllerTrait;
#[Route(route: "/templating/picea", name: "lean.console:templating.picea")]
public function picea(ServerRequestInterface $request, array $arguments) : ResponseInterface
{
$picea = $this->container->has(Picea::class) ? $this->container->get(Picea::class) : false;
$list = $picea->fileFetcher->getFileList();
return $this->renderView("lean-console/page/templating/picea", get_defined_vars());
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace Lean\Console\Entity\Mysql;
use Ulmus\Common\EntityField;
use Ulmus\Entity\Field\Datetime,
Ulmus\Entity\InformationSchema;
use Ulmus\EntityCollection;
use Ulmus\Migration\FieldDefinition;
use Ulmus\Attribute\Obj\Table;
#[Table(name: "columns", database: "information_schema")] # migrated from: 'name' => "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 [
];
}
};
}
*/
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace Lean\Console\Entity\Mysql;
use Ulmus\Common\EntityField;
use Ulmus\Entity\Field\Datetime,
Ulmus\Entity\Sqlite;
use Ulmus\EntityCollection;
use Ulmus\Migration\FieldDefinition;
use Ulmus\Attribute\Obj\Table;
#[Table(name: "columns", database: "information_schema")]
class Column extends Sqlite
{
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 [
];
}
};
}
*/
}
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace Lean\Console\Form\Caching;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\Lib;
use Picea\{Caching\Opcache, Compiler\Context };
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\Common\EntityResolver;
use \Ulmus\Entity\InformationSchema\Table;
use RecursiveIteratorIterator, RecursiveDirectoryIterator;
class Picea implements FormInterface
{
public \Picea\Picea $picea;
public array $folders;
public function __construct(\Picea\Picea $picea, array &$folders)
{
$this->folders = &$folders;
$this->picea = $picea;
}
public function initialize(FormContextInterface $context) : void
{
if ($this->picea->cache instanceof Opcache) {
$path = $this->picea->cache->cachePath() . "/";
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);
foreach ($iterator as $file) {
if ($file->isFile() && in_array($file->getExtension(), [ 'php' ])) {
$this->folders[$path][] = $file;
}
}
}
}
public function validate(FormContextInterface $context) : bool
{
return $context->valid();
}
public function execute(FormContextInterface $context) : void
{
$deleted = $failed = 0;
foreach($this->folders as $path => $files) {
foreach($files as $file)
{
unlink($file->getPathname()) ? $deleted++ : $failed++;
}
}
if ($deleted) {
# $context->pushMessage();
}
if ($failed) {
# $context->pushMessage();
}
}
}
-122
View File
@@ -1,122 +0,0 @@
<?php
namespace Lean\Console\Form;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\Lib;
use Picea\Compiler\Context;
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\Common\EntityResolver;
use \Ulmus\Entity\InformationSchema\Table;
class Database implements FormInterface
{
protected ? Lib\DatabaseMigrations $migration;
public function __construct(Lib\DatabaseMigrations $migration)
{
$this->migration = $migration;
}
public function initialize(FormContextInterface $context) : void
{
$context->tableExist = [];
foreach($this->migration->entities as $entity => $table) {
$adapter = $entity::resolveEntity()->sqlAdapter()->adapter();
$tableName = $table->tableName();
$databaseName = $table->databaseName();
if ( ! $tableName || ! $databaseName ) {
continue;
}
#<<<<<<< HEAD
$tableEntity = $adapter->schemaTable($databaseName, $tableName);
if ( $tableEntity ) {
#$fields = $entiy::resolveEntity()->fieldList();
foreach($tableEntity->columns as $col) {
//dump( $entity::field($col->name) );
#=======
# $table = Table::repository()
# ->where(Table::field('name'), $table->tableName())
# ->where(Table::field('schema'), $table->databaseName())
# ->loadOne();
# if ( $table ) {
# $fields = $entity::resolveEntity()->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
# $alter = [];
# foreach($fields as $field => $definition) {
# if ( $table->columns->filtersCollection(fn($e) => $e->name === $field)->count() === 0 ) {
# $alter[$field] = $definition;
# }
#>>>>>>> 7194a33bec884d745e838c8ac2693b353e95a3ce
}
if ( $alter ) {
$context->status[$entity] = [
'msg' => "alter",
"query" => $entity::repository()->alterSqlQuery($alter)->getSqlQuery(true),
];
}
else {
# 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
{
if ( $context->create ?? false ) {
$context->create::repository()->createTable();
}
elseif ( $context->createAll ?? false ) {
foreach(explode(',', $context->createAll) as $entity) {
$entity::repository()->createTable();
}
}
elseif ( $context->alter ?? false ) {
}
$this->initialize($context);
}
public function getContext(ServerRequestInterface $request) : FormContextInterface
{
return new class($request) extends FormContext {
public array $status = [];
public array $actions = [];
};
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace Lean\Console\Form\Debugging;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\Lib;
use Picea\{Caching\Opcache, Compiler\Context };
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\Common\EntityResolver;
use \Ulmus\Entity\InformationSchema\Table;
use RecursiveIteratorIterator, RecursiveDirectoryIterator;
class Logs implements FormInterface
{
public function __construct()
{
}
public function initialize(FormContextInterface $context) : void
{
}
public function validate(FormContextInterface $context) : bool
{
return $context->valid();
}
public function execute(FormContextInterface $context) : void
{
}
}
@@ -0,0 +1,34 @@
<?php
namespace Lean\Console\Form\Storage\Database;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\{ Lib, Entity };
use Picea\Compiler\Context;
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\{ EntityCollection };
class GenerateEntity implements FormInterface
{
public function __construct()
{
}
public function initialize(FormContextInterface $context) : void
{
}
public function validate(FormContextInterface $context) : bool
{
return $context->valid();
}
public function execute(FormContextInterface $context) : void
{
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
namespace Lean\Console\Form\Storage\Database;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\{ Lib, Entity };
use Picea\Compiler\Context;
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\{ EntityCollection };
class Import implements FormInterface
{
protected ? Lib\DatabaseMigrations $migration;
protected array $connections;
public function __construct(Lib\DatabaseMigrations $migration, array $connections)
{
$this->migration = $migration;
$this->connections = $connections;
}
public function initialize(FormContextInterface $context) : void
{
$context->sourceTables ??= new EntityCollection();
$context->destinationTables ??= new EntityCollection();
}
public function validate(FormContextInterface $context) : bool
{
if ($context->source) {
$filtered = array_filter($this->migration->entities, fn($e, $key) => $key::repository()->adapter->name === $context->source, ARRAY_FILTER_USE_BOTH);
$context->sourceTables->replaceWith($filtered);
}
return $context->valid();
}
public function execute(FormContextInterface $context) : void
{
if ($context->copy) {
foreach (array_filter($context->copy) as $dest => $source) {
foreach($source::repository()->yield() as $src) {
$dest::repository()->save( $src->toArray(), null, true );
}
}
}
}
public static function getContext(ServerRequestInterface $request, ? string $formName = null) : FormContextInterface
{
return new class($request, $formName) extends FormContext {
public EntityCollection $sourceTables;
public EntityCollection $destinationTables;
};
}
}
+163
View File
@@ -0,0 +1,163 @@
<?php
namespace Lean\Console\Form\Storage\Database;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\Lib;
use Picea\Compiler\Context;
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\Common\EntityResolver;
use \Ulmus\Entity\InformationSchema\Table;
class Migrate implements FormInterface
{
public function __construct(
protected ? Lib\DatabaseMigrations $migration,
protected null|Lib\Database\DefinitionCollection $definition = null,
)
{
$this->definition ??= new Lib\Database\DefinitionCollection();
}
public function initialize(FormContextInterface $context) : void
{
foreach($this->migration->entities as $entity => $table) {
$previous = null;
$connection = $entity::resolveEntity()->sqlAdapter();
$adapter = $connection->adapter();
$tableName = $table->tableName();
$databaseName = $table->databaseName();
if ( ! $tableName || ! $databaseName ) {
continue;
}
# Query current table's columns
$tableEntity = $adapter->schemaTable($connection, $databaseName, $tableName);
$this->definition[$entity]['table'] = $tableDefinition = new Lib\Database\Definition(
entity: $entity,
modifier: new Lib\Database\Modifier( type: Lib\Database\ModifierTypeEnum::None, ),
);
if ( $tableEntity ) {
$this->definition[$entity]['columns'] = new Lib\Database\DefinitionCollection();
foreach($table->fieldList(EntityResolver::KEY_COLUMN_NAME, true) as $field => $definition) {
$this->definition[$entity]['columns'][$field] = $def = new Lib\Database\Definition(
entity: $entity,
field: $field,
definition: $definition,
modifier: new Lib\Database\Modifier( type: Lib\Database\ModifierTypeEnum::None, ),
previous: $def ?? null,
);
$column = $tableEntity->columns->filtersOne(fn($e) => strtolower($e->name) === $field);
# Column do not exists
if ( $column === null ) {
$def->action = "add";
$def->modifier = new Lib\Database\Modifier(
type: Lib\Database\ModifierTypeEnum::Alter,
query: $entity::repository()
->alterSqlQuery([ $def->toArray() ])
->getSqlQuery(true)
);
}
elseif ( ! $column->matchFieldDefinition($definition) ) {
$def->action = "change";
$def->modifier = new Lib\Database\Modifier(
type: Lib\Database\ModifierTypeEnum::Alter,
query: $entity::repository()
->alterSqlQuery([ $def->toArray() ])
->getSqlQuery(true)
);
}
}
# ALTER TABLE `ajustements` CHANGE `annee` `annee` INT(11) NULL;
$alter = $this->definition[$entity]['columns']->filterAlter();
if ( $alter->count() ) {
if ( $adapter->splitAlterQuery() ) {
$query = $alter->map(fn(Lib\Database\Definition $map) => $entity::repository()
->alterSqlQuery([ $map->toArray() ])
->getSqlQuery(true));
}
else {
$query = $entity::repository()
->alterSqlQuery($alter->map(fn(Lib\Database\Definition $map) => $map->toArray()))
->getSqlQuery(true);
}
$tableDefinition->modifier = new Lib\Database\Modifier(
type: Lib\Database\ModifierTypeEnum::Alter,
query: $query,
);
}
}
else {
$tableDefinition->modifier = new Lib\Database\Modifier(
type: Lib\Database\ModifierTypeEnum::Create,
query: $entity::repository()
->createSqlQuery()
->getSqlQuery(true)
);
}
}
$context->definition = $this->definition;
}
public function validate(FormContextInterface $context) : bool
{
return $context->valid();
}
public function execute(FormContextInterface $context) : void
{
$create = $context->createAll ? explode(',', $context->createAll) : [ $context->create ];
foreach(array_filter($create) as $entity) {
if ($this->definition[$entity]['table']->modifier->type === Lib\Database\ModifierTypeEnum::Create) {
$entity::repository()->createTable();
}
}
$alter = $context->alterAll ? explode(',', $context->alterAll) : [ $context->alter ];
foreach(array_filter($alter) as $entity) {
if ($this->definition[$entity]['table']->modifier->type === Lib\Database\ModifierTypeEnum::Alter) {
$adapter = $entity::resolveEntity()->sqlAdapter()->adapter();
$def = $this->definition[$entity]['columns']->filterAlter();
if ( $adapter->splitAlterQuery() ) {
$def->walk(fn(Lib\Database\Definition $definition) =>
$entity::repository()->alterTable([ $definition->toArray() ])
);
}
else {
$entity::repository()->alterTable($def->map( fn(Lib\Database\Definition $e) => $e->toArray() ));
}
}
}
$this->initialize($context);
}
public static function getContext(ServerRequestInterface $request, ? string $formName = null) : FormContextInterface
{
return new class($request, $formName) extends FormContext {
public array $status = [];
public array $actions = [];
};
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace Lean\Console\Form\Update;
use Picea\Ui\Method\{ FormInterface, FormContext, FormContextInterface };
use \Lean\Console\{ Lib, Entity };
use Picea\Compiler\Context;
use Psr\Http\Message\ServerRequestInterface;
use Ulmus\{ EntityCollection };
class Git implements FormInterface
{
public function __construct(
public string $projectPath = "",
)
{
}
public function initialize(FormContextInterface $context) : void
{
}
public function validate(FormContextInterface $context) : bool
{
return $context->valid();
}
public function execute(FormContextInterface $context) : void
{
}
public function run(string $command) : \Generator
{
$command = escapeshellcmd($command);
$handle = popen("$command", 'r');
while ( false !== $output = fgets($handle, 1024) ){
yield trim($output);
}
pclose($handle);
}
}
+2
View File
@@ -4,8 +4,10 @@ namespace Lean\Console;
use Psr\Container\ContainerInterface;
#[\Deprecated]
abstract class Lean
{
#[\Deprecated]
public static function definitions() : array
{
return require(dirname(__DIR__) . "/meta/definitions/software.php");
+21 -6
View File
@@ -2,27 +2,42 @@
namespace Lean\Console\Lib;
use Notes\Attribute\Ignore;
use Psr\Container\ContainerInterface;
use Storage\Session;
use Lean\Console\Form;
use Notes\Security\Attribute\{ Security, Taxus };
use Picea;
/**
* @Language("lean.route")
* @RouteParam("methods" => [ 'GET', 'POST', 'DELETE' ], "base" => "/~")
* @Security('locked' => true)
* @Taxus("admin")
*/
#[Security(locked: false)]
#[Taxus("dev")]
#[\Notes\Route\Attribute\Object\Route(method: [ 'GET', 'POST' ] , base: "/~")]
trait ConsoleControllerTrait
{
use \Lean\ControllerTrait;
protected ContainerInterface $container;
#[Ignore]
public function __construct(? Picea\Picea $picea, Session $session, ContainerInterface $container) {
$this->picea = $picea;
$this->session = $session;
$this->container = $container;
}
#[Ignore]
public function version() : string
{
$version = iterator_to_array(
(new Form\Update\Git(getenv('PROJECT_PATH')))->run("/usr/bin/git describe --tags")
);
# dump($version);
return "1.5.0";
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace Lean\Console\Lib\Database;
use Notes\Common\ReflectedProperty;
class Definition
{
public function __construct(
public string $entity,
public string|null $field = null,
public array|null|ReflectedProperty $definition = null,
public null|Modifier|array $modifier = null,
public null|Definition $previous = null,
public null|string $action = null,
) {}
public function toArray() : array
{
return array_filter(get_object_vars($this));
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace Lean\Console\Lib\Database;
class DefinitionCollection extends \Ulmus\EntityCollection
{
public function filterType(ModifierTypeEnum $type) : self
{
return $this->filtersCollection(fn(Definition $e) => $e->modifier->type === $type);
}
public function filterCreate() : self
{
return $this->filterType(ModifierTypeEnum::Create);
}
public function filterAlter() : self
{
return $this->filterType(ModifierTypeEnum::Alter);
}
public function filterDelete() : self
{
return $this->filterType(ModifierTypeEnum::Delete);
}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace Lean\Console\Lib\Database;
class Modifier
{
public function __construct(
public ModifierTypeEnum $type,
public null|array|string $query = null,
) {}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace Lean\Console\Lib\Database;
enum ModifierTypeEnum: string
{
case Alter = 'alter';
case Create = 'create';
case Delete = 'delete';
case None = 'none';
}
+10 -2
View File
@@ -2,6 +2,8 @@
namespace Lean\Console\Lib;
use Ulmus\Adapter\SqlAdapterInterface;
class DatabaseMigrations
{
public array $folderList;
@@ -20,14 +22,20 @@ class DatabaseMigrations
foreach($this->folderList as $namespace => $folder) {
foreach(static::files($folder) as $file) {
$name = $file->getBasename("." . $file->getExtension());
$subNs = substr($file->getPath(), strlen($folder));
$subNs = str_replace('/', '\\', substr($file->getPath(), strlen($folder)));
$entity = rtrim($namespace, "\\") . ( $subNs ? "\\$subNs" : "" ) . "\\{$name}";
if ( ! method_exists($entity, 'resolveEntity') ) {
continue;
}
$this->entities[$entity] = $entity::resolveEntity();
$resolve = $entity::resolveEntity();
if ( $resolve->sqlAdapter()->adapter() instanceof SqlAdapterInterface) {
$this->entities[$entity] = $resolve;
}
else {
}
}
}
+5
View File
@@ -0,0 +1,5 @@
<?php
namespace Lean\Console\Lib;
class FormContext extends \Picea\Ui\Method\FormContext { }
+9
View File
@@ -0,0 +1,9 @@
<?php
class Triggers
{
public function onUpdateCurrentTimestamp(string $table) : string
{
}
}
+17 -6
View File
@@ -1,28 +1,39 @@
<nav id="main-nav">
<div class="app-title">LEAN {{ $this->version() }}</div>
<label>{% lang "lean.nav.lean.label" %}</label>
<ul>
<li><a href="{{ url('~') }}">{% lang "lean.nav.lean.dashboard" %}</a></li>
<li><a href="{% route 'lean.console:home' %}">{% lang "lean.nav.lean.dashboard" %}</a></li>
<li><a href="{% route 'lean.console:update' %}">{% lang "lean.nav.lean.update" %}</a></li>
</ul>
<label>{% lang "lean.nav.request.label" %}</label>
<ul>
<li><a href="{{ url('~/request/routes') }}">{% lang "lean.nav.request.routes" %}</a></li>
<li><a href="{% route 'lean.console:request.route' %}">{% lang "lean.nav.request.routes" %}</a></li>
</ul>
<label>{% lang "lean.nav.storage.label" %}</label>
<ul>
{#<li><a href="{{ url('~/storage') }}">{% lang "lean.nav.storage.summary" %}</a></li>#}
<li><a href="{{ url('~/storage/database') }}">{% lang "lean.nav.storage.database" %}</a></li>
<li><a href="{{ url('~/storage/session') }}">{% lang "lean.nav.storage.session" %}</a></li>
<li><a href="{% route 'lean.console:storage.database' %}">{% lang "lean.nav.storage.database" %}</a></li>
<li><a href="{% route 'lean.console:storage.session' %}">{% lang "lean.nav.storage.session" %}</a></li>
</ul>
<label>{% lang "lean.nav.templating.label" %}</label>
<ul>
<li><a href="{{ url('~/templating/picea') }}">{% lang "lean.nav.templating.picea" %}</a></li>
<li><a href="{% route 'lean.console:templating.picea' %}">{% lang "lean.nav.templating.picea" %}</a></li>
</ul>
<label>{% lang "lean.nav.caching.label" %}</label>
<ul>
<li><a href="{{ url('~/storage') }}">{% lang "lean.nav.templating.picea" %}</a></li>
<li><a href="{% route 'lean.console:caching' %}">{% lang "lean.nav.templating.picea" %}</a></li>
</ul>
<label>{% lang "lean.nav.debugging.label" %}</label>
<ul>
<li><a href="{% route 'lean.console:debugging-logs' %}">{% lang "lean.nav.debugging.logs" %}</a></li>
</ul>
<ul>
<li><a href="{% route 'lean.console:debugging-phpinfo' %}">{% lang "lean.nav.debugging.phpinfo" %}</a></li>
</ul>
</nav>
+25 -12
View File
@@ -10,35 +10,48 @@
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Ctext%20x='0'%20y='14'%3E🔳%3C/text%3E%3C/svg%3E" type="image/svg+xml" />
<link rel="stylesheet" href='{% asset:path "lean-console/lean-console-bw.css" %}'>
<title>{{ title() }}</title>
<style>
{% include "lean-console/base/asset/lean.css" %}
</style>
{% section "head" %}{% endsection %}
</head>
<body>
<header id="body-header">
{% section "header" %}{% endsection %}
</header>
<main id="body-main">
<main id="body-main">
{% section "nav" %}
{% view "lean-console/base/console/main-nav" %}
{% endsection %}
<div id="right-panel">
<header id="body-header">
{% section "header" %}
<div class="flex align-items-center justify-content-end">
<a class="btn-blue" href="{% url %}">⇠ Return</a>
</div>
{% endsection %}
</header>
<div id="subheader">
<h1>{% section "subheader" %}{% _ "page-title" %}{% endsection %}</h1>
{% section "breadcrumb" %}
<ul class="breadcrumb">
<li class="breadcrumb-item">Console</li>
{% section "breadcrumb-items" %}{% endsection %}
</ul>
{% endsection %}
</div>
<section id="main-content">
{% section "content" %}{% endsection %}
</section>
</main>
</div>
</main>
<footer id="body-footer">
<footer id="body-footer">
{% section "footer" %}
&copy; {{ date('Y') }} - LEAN
{% endsection %}
</footer>
</footer>
</body>
</html>
@@ -0,0 +1,50 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.caching" %}
{% title _("title") %}
{% section "breadcrumb-items" %}
<li class="breadcrumb-item">{% _ 'breadcrumb' %}</li>
{% endsection %}
{% section "content" %}
{% foreach $list as $path => $folder %}
<section>
<header>
<h2>{{ $path }}</h2>
{% ui:form.post "caching.picea" %}
<button class="btn-red" type="submit">{% _ 'clear' %}</button>
{% ui:endform %}
</header>
<article class="picea">
{% foreach $folder as $file %}
{% php $import = include($file) %}
<div class="grid">
<strong class="col route-name">{{ substr($file, strlen($path)) }}</strong>
<div class="col">
{{ $import['namespace'] }}
</div>
<div class="col">
{{ $import['view'] }}
</div>
</div>
{% endforeach %}
</article>
</section>
{% endforeach %}
<style>
section > header {display:flex;justify-content: space-between}
.picea h5 {font-size:1.5em; line-height:2em; font-weight:bold;text-decoration:underline}
.picea strong.grid {background: #242528;color: #fff;}
.picea .grid {padding:0.66rem 0.3rem;align-items:center}
.picea .grid strong {color:#444}
.picea .grid:nth-child(even) {background: #e3e3e3 }
</style>
{% endsection %}
+13 -4
View File
@@ -4,10 +4,19 @@
{% title _("title") %}
{% section "header" %}
<div class="page-title">{% _ "page-title" %}</div>
{% endsection %}
{% section "content" %}
<section>
<article>Welcome into your Lean Console section. Select the appropriate menu item from the sidebar.</article>
</section>
<section style="margin-top:1rem;">
<article>
<div>Firewall</div>
<br>
<b>@todo</b>
<u>latest 50 connections</u>
<u>banned users / IP !</u>
<u>fail2ban integration</u>
</article>
</section>
{% endsection %}
@@ -0,0 +1,32 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.debugging" %}
{% title _("title") %}
{% section "content" %}
<section>
<header>
<h2>{{ $path }}</h2>
{% ui:form.get current_url() %}
{% ui:select 'logfile', array_combine($files, $files), get('file') ?? $open %}
{% ui:endform %}
</header>
<article class="logs">
<div class="log-item">
{% foreach array_reverse($content) as $line %}
<div class="line">{{ $line }}</div>
{% endforeach %}
</div>
</article>
</section>
<style>
section > header {display:flex;justify-content: space-between}
.log-item {max-height: 60vh; overflow-y:auto}
.log-item .line {padding:0.5rem}
.log-item .line {background: #efefef}
.log-item .line:nth-child(even) {background: #ccc}
</style>
{% endsection %}
@@ -0,0 +1,22 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.debugging" %}
{% title _("title") %}
{% section "header" %}
<div class="page-title">{% _ "page-title" %}</div>
{% endsection %}
{% section "breadcrumb-items" %}
<li class="breadcrumb-item">{% _ 'phpinfo.breadcrumb' %}</li>
{% endsection %}
{% section "content" %}
<section>
<iframe src="data:text/html;base64,{{ base64_encode($phpinfo) }}" style="width:100%; height: calc(100vh - 112px - 8vh)">
</iframe>
</section>
{% endsection %}
+24 -12
View File
@@ -4,14 +4,25 @@
{% title _("title") %}
{% section "header" %}
<div class="page-title">{% _ "page-title" %}</div>
{% section "breadcrumb-items" %}
<li class="breadcrumb-item">{% _ 'route.breadcrumb' %}</li>
{% endsection %}
{% function routeHtml($route) %}
<div class="grid">
<strong class="col route-name">{{ $route->name }}</strong>
<div class="col route-uri">{{ $route->getRoute() }}</div>
<div class="col route-methods">{{ implode(', ', (array) ( $route->method ?? $route->methods )) }}</div>
<div class="col controller-method">
<span class="class">{{ $route->class }}</span>::<span>{{ $route->classMethod }}</span>
</div>
</div>
{% endfunction %}
{% section "content" %}
<section>
<header>
<h1>{% _ 'route.header' %}</h1>
<h2>{% _ 'route.header' %}</h2>
</header>
<article class="routes">
@@ -23,15 +34,16 @@
<div class="col controller-method">{% _ 'route.target' %}</div>
</strong>
{% foreach $routes as $name => $route %}
<div class="grid">
<strong class="col route-name">{{ $name }}</strong>
<div class="col route-uri">{{ $route['route'] }}</div>
<div class="col route-methods">{{ implode(', ', $route['routeMethods']) }}</div>
<div class="col controller-method">
<span class="class">{{ $route['class'] }}</span>::<span>{{ $route['classMethod'] }}</span>
</div>
{% foreach $routes as $route %}
{{ routeHtml($route) }}
{% if $overridden = $routing->findOverriddenRoute($route) %}
<div style="background:rgba(255,0,0,0.2); text-decoration:line-through">
{% foreach $routing->findOverriddenRoute($route) as $overridden %}
{{ routeHtml($overridden) }}
{% endforeach %}
</div>
{% endif %}
{% endforeach %}
{% else %}
{% _ 'routeless' %}
@@ -40,7 +52,7 @@
</section>
<style>
.routes strong.grid {background:#172842;color:#eeffee}
.routes strong.grid {background: #242528;color: #fff;}
.routes .grid {padding:0.66rem 0.3rem}
.routes .grid strong {color:#444}
.routes .grid:nth-child(even) {background: #e3e3e3 }
+36 -32
View File
@@ -1,21 +1,22 @@
{% use Lean\Console\Lib\Database\ModifierTypeEnum %}
{% extends "lean-console/base/layout" %}
{% language.set "lean.storage" %}
{% title _("title") %}
{% section "header" %}
<div class="page-title">{% _ "page-title" %}</div>
{% section "breadcrumb-items" %}
<li class="breadcrumb-item">{% _ 'database.breadcrumb' %}</li>
{% endsection %}
{% section "content" %}
<section>
<header>
<h1>{% _ 'database.header' %}</h1>
</header>
<article class="databases">
{% if $connections %}
{% foreach $connections as $connection %}
<section>
{% php $conf = $connection->getConfiguration(); %}
<article class="databases">
<strong class="grid db-grid">
<div class="col db-connection">{% _ 'database.connection' %}</div>
<div class="col db-adapter">{% _ 'database.adapter' %}</div>
@@ -24,15 +25,12 @@
<div class="col db-username">{% _ 'database.username' %}</div>
</strong>
{% foreach $connections as $connection %}
{% php $conf = $connection->getConfiguration(); %}
<div class="grid db-grid">
<div class="col db-connection">{{ $connection->name }}</div>
<div class="col db-adapter">{{ $conf['adapter'] }}</div>
<div class="col db-host">{{ $conf['host'] }}:{{ $conf['port'] }}</div>
<div class="col db-name">{{ $conf['database'] }}</div>
<div class="col db-username">{{ $conf['username'] }}</div>
<div class="col db-adapter">{{ $connection->adapter()::class }}</div>
<div class="col db-host">{{ $connection->adapter()->hostname ?? '-' }}:{{ $connection->adapter()->port ?? '-' }}</div>
<div class="col db-name">{{ $connection->adapter()->database ?? $connection->adapter()->path ?? '-' }}</div>
<div class="col db-username">{{ $connection->adapter()->username ?? '-' }}</div>
</div>
<div class="tables">
@@ -43,34 +41,34 @@
<div class="col text-right">{% _ 'database.table.actions' %}</div>
</strong>
{% ui.form.post "database" %}
{% ui:form.post "database" %}
{% foreach array_filter($migrations->entities, fn($e) => $e->databaseAdapter() === $connection) as $entity => $item %}
<div class="grid table-item align-items-center">
<div class="col"><span>📄</span> <span>{{ $item->tableName() }}</span></div>
<div class="col">{% _ "database.table.fields", [ 'count' => count( $item->fieldList() ) ] %}</div>
<div class="col col-grow-2">
{% if $context->status[$entity]['query'] %}
<code>{{ $context->status[$entity]['query'] }}</code>
{% if $context->definition[$entity]['table']->modifier->query ?? false %}
<code>{{= implode('<br><br>',(array) $context->definition[$entity]['table']->modifier->query) }}</code>
{% else %}
<div>🗸 This table is up-to-date</div>
<div style="color:#abecab">&#x2713 {% _ 'database.table.uptodate' %}</div>
{% endif %}
</div>
<div class="col">
{% switch $context->status[$entity]['msg'] %}
{% case 'unexisting' %}
{% switch $context->definition[$entity]['table']->modifier->type ?? false %}
{% case ModifierTypeEnum::Create %}
{% php $createAll[] = $entity %}
<div class="text-right">
<button name="create" value="{{$entity}}" class="btn-blue">🗸 {% _ 'database.table.create' %}</button>
<button name="create" value="{{$entity}}" class="btn-blue">&#x2713; {% _ 'database.table.create' %}</button>
</div>
{% break %}
{% case 'altering' %}
{% php $alter[] = $entity %}
{% case ModifierTypeEnum::Alter %}
{% php $alterAll[] = $entity %}
<div class="text-right">
<button name="create" value="{{$entity}}" class="btn-blue">🗸 {% _ 'database.table.alter' %}</button>
<button name="alter" value="{{$entity}}" class="btn-blue">&#x2713; {% _ 'database.table.alter' %}</button>
</div>
{% break %}
{% endswitch %}
@@ -80,29 +78,35 @@
{% if ($createAll ?? 0) > 1 %}
<div class="text-right" style="padding:0.5rem 0">
<button name="createAll" value="{{ implode(',', $createAll) }}" class="btn-red">🗸 {% _ 'database.table.createAll' %}</button>
<button name="createAll" value="{{ implode(',', $createAll) }}" class="btn-red">&#x2713; {% _ 'database.table.createAll' %}</button>
</div>
{% endif %}
{% ui.endform %}
</div>
{% endforeach %}
{% if ($alterAll ?? 0) > 1 %}
<div class="text-right" style="padding:0.5rem 0">
<button name="alterAll" value="{{ implode(',', $alterAll) }}" class="btn-red">&#x2713; {% _ 'database.table.alterAll' %}</button>
</div>
{% endif %}
{% ui:endform %}
</div>
</article>
</section>
{% endforeach %}
{% endif %}
<style>
.databases strong.grid {background:#172842;color:#fff}
.databases strong.grid {background: #242528;color:#fff}
.databases .db-grid {padding:0.66rem 0.3rem}
.databases .db-grid strong {color:#444}
.databases .db-grid:nth-child(even) {background: #e3e3e3 }
.databases .db-grid:nth-child(even) {background: #e3e3e3;line-height: 1.5em;font-size: 1.3em;}
.databases .tables .table-item {padding:0.33rem 0;background:rgba(255,255,255,0.1)}
.databases .tables .table-item {padding:0.33rem 0;background:rgba(255,255,255,0.1);line-height: 1.8em;}
.databases .tables .table-item:nth-child(even) {background:rgba(255,255,255,0.2)}
.databases summary {background: #172841;color:#fff;margin: 0 -8px 0 -8px;padding:7px 10px}
.tables {background: #172841;margin: 0 -8px 0 -8px;color: #fff;padding: 4px 12px;}
.tables {background: #2d3137;margin: 0 -8px 0 -8px;color: #fff;padding: 2px 10px;}
.tables label {padding:10px 5px;display:block}
section + section { margin-top:15px; }
</style>
{% endsection %}
@@ -0,0 +1,67 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.storage" %}
{% title _("title") %}
{% section "content" %}
{% if $connections %}
{% ui:form.post "database.import" %}
<section>
<header>Import data from a connection into another</header>
<article class="databases">
{% if ! $context->source %}
{% php $select = array_combine(array_column($connections, 'name'), array_column($connections, 'name')) %}
<div class="db-grid">
Source connection: {% ui:select "source", $select %}
</div>
<div class="db-grid">
Destination connection: {% ui:select "destination", $select %}
</div>
{% else %}
{% ui:hidden 'source', $context->source %}
{% ui:hidden 'destination', $context->destination %}
<div class="db-grid">
COPY DATA FROM → TO:
{% php $dest = array_filter($migrations->entities, fn($e, $key) => $key::repository()->adapter->name === $context->destination, ARRAY_FILTER_USE_BOTH); %}
{% foreach $dest as $key => $value %}
<div class="db-grid">
<span>{% ui:select "copy[$key]", [ null => '' ] + $context->sourceTables->buildArray('entityClass', 'entityClass') %}</span>
<span>→</span>
<span>{{ sprintf('%s (%s)', $key, $value->tableName()) }}</span>
</div>
{% endforeach %}
</div>
{% endif %}
</article>
<footer class="text-center">
<button type="submit" class="btn-blue">Copy</button>
<a href="{% route 'lean.console:storage.database' %}" class="btn-red">Cancel</a>
</footer>
</section>
{% ui:endform %}
{% else %}
No connection found
{% endif %}
<style>
.databases strong.grid {background:#181818;color:#fff}
.databases .db-grid {padding:0.66rem 0.3rem}
.databases .db-grid strong {color:#444}
.databases .db-grid:nth-child(even) {background: #eaeaea }
.databases .tables .table-item {padding:0.33rem 0;background:rgba(255,255,255,0.1);line-height: 1.8em;}
.databases .tables .table-item:nth-child(even) {background:rgba(255,255,255,0.2)}
.databases summary {background: #172841;color:#fff;margin: 0 -8px 0 -8px;padding:7px 10px}
.tables {background: #2d3137;margin: 0 -8px 0 -8px;color: #fff;padding: 2px 10px;}
.tables label {padding:10px 5px;display:block}
section + section { margin-top:15px; }
</style>
{% endsection %}
@@ -0,0 +1,42 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.storage" %}
{% title _("title") %}
{% section "breadcrumb-items" %}
<li class="breadcrumb-item">{% _ 'session.breadcrumb' %}</li>
{% endsection %}
{% section "content" %}
<section>
<header>
<h2>{% _ 'session.header' %}</h2>
</header>
<article class="sessions">
<strong class="grid">
<div class="col route-name">{% _ 'session.count', [ 'count' => count($sessions) ] %}</div>
</strong>
{% foreach $sessions as $session %}
<div class="grid">
<strong class="col route-name">{{ $session }}</strong>
<div class="col">{{ date('Y-m-d H:i:s', filemtime(realpath($path . DIRECTORY_SEPARATOR . $session))) }}</div>
<div class="col text-right">
<a target="_blank" class="btn-red" href="{% route 'lean.console:storage.session_content', [ 'hash' => $session ] %}">
Voir
</a>
</div>
</div>
{% endforeach %}
</article>
</section>
<style>
.sessions strong.grid {background: #242528;color: #fff;}
.sessions .grid {padding:0.66rem 0.3rem;align-items:center;justify-content:space-between;}
.sessions .grid strong {color:#444}
.sessions .grid:nth-child(even) {background: #e3e3e3 }
</style>
{% endsection %}
@@ -0,0 +1,41 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.templating" %}
{% title _("title") %}
{% section "breadcrumb-items" %}
<li class="breadcrumb-item">{% _ 'breadcrumb' %}</li>
{% endsection %}
{% section "content" %}
{% foreach $list as $path => $folder %}
<section>
<header>
<h2>{{ $path }}</h2>
</header>
<article class="picea">
{% foreach $folder as $file %}
<div class="grid">
<strong class="col route-name">{{ substr($file, strlen($path)) }}</strong>
<div>
{#<a target="_blank" class="btn-red" href="">
Voir
</a>#}
</div>
</div>
{% endforeach %}
</article>
</section>
{% endforeach %}
<style>
.picea h5 {font-size:1.5em; line-height:2em; font-weight:bold;text-decoration:underline}
.picea strong.grid {background: #242528;color: #fff;}
.picea .grid {padding:0.66rem 0.3rem;align-items:center}
.picea .grid strong {color:#444}
.picea .grid:nth-child(even) {background: #e3e3e3 }
section + section {margin-top:1.2rem}
</style>
{% endsection %}
+43
View File
@@ -0,0 +1,43 @@
{% extends "lean-console/base/layout" %}
{% language.set "lean.update" %}
{% title _("title") %}
{% section "content" %}
<section>
<header>
<h1>{% _ 'git.header' %}</h1>
</header>
<article class="updates">
<div class="git-status">
<strong style="display:block;margin-bottom:7px">'git status' output</strong>
<code style="white-space:normal;font-size:120%">
{% foreach $status as $line %}
<div>
{% if $line %}
{{ $line }}
{% endif %}
</div>
{% endforeach %}
</code>
</div>
<div class="git-diff" style="margin-top:2rem">
<strong style="display:block;margin-bottom:7px">'git diff' output</strong>
<code style="white-space:normal;font-size:120%">
{% foreach $diff as $line %}
<div>
{% if $line %}
{{ $line }}
{% endif %}
</div>
{% endforeach %}
</code>
</div>
</article>
</section>
{% endsection %}