- WIP on lean-api visual

This commit is contained in:
Dave Mc Nicoll 2025-10-06 17:28:08 +00:00
parent c5ec582bd1
commit c9b107809d
6 changed files with 46 additions and 36 deletions

View File

@ -6,6 +6,7 @@ use Lean\Api\Factory\MessageFactoryInterface;
use Lean\LanguageHandler;
use Picea\Ui\Method\FormContextInterface;
use Ulmus\Entity\EntityInterface;
use Ulmus\EntityCollection;
trait FormTrait
{
@ -29,7 +30,7 @@ trait FormTrait
return $this->languageHandler->languageFromKey($key, $variables);
}
public function getEntity() : EntityInterface
public function getEntity() : EntityInterface|EntityCollection
{
if (! isset($this->entity)) {
throw new \InvalidArgumentException($this->lang("lean.api.form.error.entity"));

View File

@ -33,11 +33,11 @@ class ApiRenderer implements MiddlewareInterface {
'data' => [
# 'error_id' => $errorId,
'message' => $ex->getMessage(),
] + (getenv('DEBUG') ? [
'file' => $ex->getFile(),
'line' => $ex->getLine(),
'code' => $ex->getCode(),
'backtrace' => $ex->getTrace(),
]
'backtrace' => $ex->getTrace(), ] : [])
], 500);
}

View File

@ -11,12 +11,11 @@
<div class="entities">
{% foreach $entities as $name => $entity %}
<div class="entity-wrapper" style="padding-left: 15px;border-left: 3px solid #eaa1af;">
<h4 class='entity-name'>{{ $name }}</h4>
<h4 class='entity-name' title="{{ $name }}">{{ $entity['className'] }}</h4>
<div class='description'>{{ $entity['description'] }}</div>
<hr style="margin-top:15px">
<h5>Champs</h5>
<ol class='fields'>
{% foreach $entity['fields'] as $field %}
<li class="odd-even">
@ -37,32 +36,35 @@
</ol>
</div>
<div class="search-request-wrapper">
<h4 class='search-request-name'>{{ $name }}::searchRequest()</h4>
{% if $entity['searchRequestFields'] %}
<div class="search-request-wrapper">
<h4 class='search-request-name' title="{{ $name }}">{{ $entity['className'] }}::searchRequest()</h4>
<h5>Requêtes</h5>
<div class='description' style="margin-bottom:10px">{{ $entity['searchRequestDescription'] }}</div>
{% if $entity['searchRequestDescription'] %}
<div class='description' style="margin-bottom:10px">{{ $entity['searchRequestDescription'] }}</div>
{% endif %}
<ol class='requests'>
{% foreach $entity['searchRequestFields'] as $field %}
<li class="odd-even">
<div class="title">
<div><strong style="font-family:monospace">{{ $field['name'] }}</strong> <span style='margin-left:15px'>{{ $field['description'] }}</span></div>
</div>
<ol class='requests'>
{% foreach $entity['searchRequestFields'] as $field %}
<li class="odd-even">
<div class="title">
<div><strong style="font-family:monospace">{{ $field['name'] }}</strong> <span style='margin-left:15px'>{{ $field['description'] }}</span></div>
</div>
<div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
<div><u>Paramètre de requête (GET)</u> : {{ $field['parameter'] }}</div>
<div><u>Attribut</u> : {{ $field['tag'] }}</div>
<div><u>Type(s)</u> : {{ $field['type'] }}</div>
<div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
{% if $field['default'] !== "" %}
<div><u>Valeur par défault</u> : {{ $this->displayValue($field['default']) }}</div>
{% endif %}
</div>
</li>
{% endforeach %}
</ol>
</div>
<div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
<div><u>Paramètre de requête (GET)</u> : {{ $field['parameter'] }}</div>
<div><u>Attribut</u> : {{ $field['tag'] }}</div>
<div><u>Type(s)</u> : {{ $field['type'] }}</div>
<div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
{% if $field['default'] !== "" %}
<div><u>Valeur par défault</u> : {{ $this->displayValue($field['default']) }}</div>
{% endif %}
</div>
</li>
{% endforeach %}
</ol>
</div>
{% endif %}
{% or %}
<i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
{% endforeach %}

View File

@ -8,7 +8,7 @@
{% foreach $forms as $name => $form %}
<div class="single-form" style="padding-left:15px;border-left: 3px solid #9ccce6;" data-form="{% json.html $form %}">
<h4 class='form-name'>
<span>{{ $name }}</span>
<span title="{{ $name }}">{{ $form['className'] }}</span>
</h4>
<div class='description'>{{ $form['description'] }}</div>
<hr style="margin-top:15px">

View File

@ -10,6 +10,7 @@
<div class="url" style="flex-grow: 1;">
{% ui:text "url" %}
{% ui:text "token", $this->session->jwt %}
<button class="request-btn">Envoyer</button>
</div>
</div>
@ -33,7 +34,9 @@
.request-head {display:flex;padding-top: 4px;border:1px solid #e1e1e1;border-bottom:0}
.request-head .method {width: 90px;text-align: center;line-height: 34px;font-weight: bold;}
.request-head .method select {background:none;border:0;font-size: inherit;text-align: center;color: inherit;font-weight: bold;}
.request-head .url input {width: calc(100% - 94px); border:0;color: #6f6f6f;background: #f9f9f9;font-size: 80%;font-weight: bold;}
.request-head .url input {border:0;color: #6f6f6f;background: #f9f9f9;font-size: 80%;font-weight: bold;}
.request-head .url [name="url"] {width: calc(65% - 80px);}
.request-head .url [name="token"] {width:calc(35% - 10px);font-size:60%}
.request-head .url button {font-size: 80%;width: 80px;border-radius:0;border: 1px solid #ccc;height:26px;padding: 0;background:#f9f9f9;color: #6f6f6f;cursor: pointer;}
.request-head .url button:active {filter:contrast(85%);}
@ -55,6 +58,7 @@
responseResponse = requestDebugger.querySelector(".request-response"),
method = requestHead.querySelector(".method"),
input = requestHead.querySelector("[name='url']"),
token = requestHead.querySelector("[name='token']"),
button = requestHead.querySelector(".request-btn");
// Editor
@ -159,10 +163,10 @@
method: method,
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
credentials: "omit",
headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer {{ $this->session->jwt }}'
'Authorization': `Bearer ${token.value}`
},
redirect: "follow",
referrerPolicy: "no-referrer"

View File

@ -21,7 +21,7 @@
ol{background: #eff4f2;padding-top:20px;padding-bottom:20px;border:1px solid #e3e3ec}
h4{background:#e0f7ed;padding:6px 12px; font-weight: bold!important;font-size:100%;margin-top:0}
h5{text-decoration: underline}
h3 {display: flex;align-items: center;height: 60px;padding: 0 15px 0 15px;font-variant: small-caps;}
h3 {display: flex;align-items: center;padding: 0 15px 0 15px;font-variant: small-caps;border-bottom: 5px solid #ccc;line-height: 60px;}
li.odd-even{border-top:1px solid #ccc;margin:10px 0;padding:15px 15px 10px 5px}
li.odd-even:first-child{border:0}
input, button {padding:5px; font-size:1em;margin:0}
@ -39,7 +39,7 @@
.forms .form-name span {color: #284168;font-size:110%}
.forms .form-name .btn {background:rgba(50,50,50,0.5);padding:0 15px;border: 1px solid rgba(50,50,50,0.8);font-family: 'Déja Vu', 'Courier New', Courier, monospace, serif;font-size: 90%;color: #fff;text-decoration: underline;}
.routes-wrapper {padding:8px}
.routes-wrapper {padding:5px}
.routes-wrapper li {display:flex;border: 1px solid #ccc;align-items: stretch;cursor:pointer}
.routes-wrapper li:hover {filter: contrast(85%)}
.routes-wrapper li + li {margin-top: 5px;}
@ -70,12 +70,15 @@
.routes-wrapper li.method-put .route-method {background:#d7bf3c;}
.routes-wrapper li.method-put .route-link a, .routes-wrapper li.method-put .route-name {color: #aa941c;}
.forms{background: #e8f7ff;padding: 5px;}
.entities {background: #f0e0e0;padding:5px;}
.entity-wrapper .entity-name {background:#eaa1af;color: #682828;font-size:110%}
.entity-wrapper ol {background: #f0ddcd;}
.entity-wrapper ol {background: #e3d0d0;}
.entity-wrapper li {border-color: #ae8585;}
.search-request-name {background: #b6e6ae;color: #395332;font-size:110%}
.search-request-wrapper {padding-left: 15px;border-left: 3px solid #72886a;}
.search-request-wrapper {padding: 15px;margin-top:5px;border-left: 3px solid #72886a;background: #eeffe6;}
.search-request-wrapper ol {background: #d8f0cd;}
.search-request-wrapper li {border-color: #72886a;}
</style>