diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index 08354b1878..571ee3d0a8 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -1035,7 +1035,7 @@ HTML // Add extra data for markup generation // - Attribute code and AttributeDef. class $val['attcode'] = $sAttCode; - $val['atttype'] = $sAttDefClass; + $val['atttype'] = $oAttDef->GetType(); $val['attlabel'] = $sAttLabel; $val['attflags'] = ($bEditMode) ? $this->GetFormAttributeFlags($sAttCode) : OPT_ATT_READONLY; @@ -4495,7 +4495,7 @@ HTML; $oDivField = FieldUIBlockFactory::MakeLarge(""); // UIContentBlockUIBlockFactory::MakeStandard(null,["field_container field_large"]); - $oDivField->AddDataAttribute("attribute-type", $sAttDefClass); + $oDivField->AddDataAttribute("attribute-type", $oAttDef->GetType()); $oDivField->AddDataAttribute("attribute-label", $sAttMetaDataLabel); $oDivField->AddDataAttribute("attribute-flag-hidden", false); $oDivField->AddDataAttribute("attribute-flag-read-only", false); diff --git a/css/backoffice/pages/_datamodel-viewer.scss b/css/backoffice/pages/_datamodel-viewer.scss index 99c296bc7f..c614c78772 100644 --- a/css/backoffice/pages/_datamodel-viewer.scss +++ b/css/backoffice/pages/_datamodel-viewer.scss @@ -3,9 +3,29 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ +$ibo-datamodel-viewer--viewer-empty--width: max(20%, #{$ibo-size-700}) !default; + $ibo-datamodel-viewer--parent--spacer--padding-y: $ibo-spacing-0 !default; $ibo-datamodel-viewer--parent--spacer--padding-x: $ibo-spacing-300 !default; +$ibo-datamodel-viewer--breadcrumb--margin: $ibo-spacing-200 0 !default; + +$ibo-datamodel-viewer--classname--font-family: monospace !default; +$ibo-datamodel-viewer--classname--color: $ibo-color-blue-grey-600 !default; + +$ibo-datamodel-viewer--tag--category--color: $ibo-color-blue-grey-800 !default; +$ibo-datamodel-viewer--tag--category--icon--color: $ibo-color-blue-grey-600 !default; + +$ibo-datamodel-viewer--abstract-class-icon--margin-right: $ibo-spacing-300 !default; +$ibo-datamodel-viewer--abstract-class-icon--after--content: 'A' !default; +$ibo-datamodel-viewer--abstract-class-icon--after--width: 15px !default; +$ibo-datamodel-viewer--abstract-class-icon--after--height: 15px !default; +$ibo-datamodel-viewer--abstract-class-icon--after--line-height: 14px !default; +$ibo-datamodel-viewer--abstract-class-icon--after--border-radius: 50% !default; +$ibo-datamodel-viewer--abstract-class-icon--after--border: 1px solid $ibo-color-cyan-500 !default; +$ibo-datamodel-viewer--abstract-class-icon--after--color: $ibo-color-white-100 !default; +$ibo-datamodel-viewer--abstract-class-icon--after--background-color: $ibo-color-cyan-500 !default; + $ibo-datamodel-viewer--classes-list--selectize-input--background-color: $ibo-color-white-100 !default; $ibo-datamodel-viewer--classes-list--selectize-input--color: $ibo-color-grey-800 !default; $ibo-datamodel-viewer--classes-list--selectize-input--border-color: $ibo-color-grey-500 !default; @@ -16,8 +36,9 @@ $ibo-datamodel-viewer--origin-cell--diameter: 8px !default; $ibo-datamodel-viewer--origin-cell--border-radius: $ibo-border-radius-full !default; $ibo-datamodel-viewer--classes-list--height: 100% !default; -$ibo-datamodel-viewer--classes-list--width: 350px !default; +$ibo-datamodel-viewer--classes-list--width: $ibo-size-700 !default; $ibo-datamodel-viewer--classes-list--padding-left: $ibo-spacing-600 !default; +$ibo-datamodel-viewer--classes-list--padding-top: $ibo-spacing-300 !default; $ibo-datamodel-viewer--lifecycle--code--color: $ibo-color-grey-700 !default; $ibo-datamodel-viewer--lifecycle--stimuli--color: $ibo-color-blue-900 !default; @@ -45,6 +66,56 @@ $ibo-datamodel-viewer--lifecycle-image--margin-bottom: $ibo-spacing-500 !default .ibo-panel--subtitle{ @extend %ibo-font-ral-nor-150; } + .ibo-datamodel-viewer--empty{ + display: flex; + flex-direction: column; + align-items: center; + svg{ + width: $ibo-datamodel-viewer--viewer-empty--width; + } + } +} + +.ibo-datamodel-viewer--empty--text { + @extend %ibo-font-ral-med-400 +} + +.ibo-datamodel-viewer--breadcrumb{ + @extend %ibo-font-ral-med-150; + margin: $ibo-datamodel-viewer--breadcrumb--margin; + .ibo-button{ + text-transform: none; // unset uppercase + } +} + +.ibo-datamodel-viewer--classname{ + color: $ibo-datamodel-viewer--classname--color; + @extend %ibo-font-code-100; +} + +.ibo-datamodel-viewer--tag--category{ + color: $ibo-datamodel-viewer--tag--category--color; + .ibo-object-details--tag-icon{ + color:$ibo-datamodel-viewer--tag--category--icon--color; + } +} + +.ibo-datamodel-viewer--icon--abstract{ + &:after{ + content: $ibo-datamodel-viewer--abstract-class-icon--after--content; + display: inline-flex; + justify-content: center; + align-items: center; + width: $ibo-datamodel-viewer--abstract-class-icon--after--width; + height: $ibo-datamodel-viewer--abstract-class-icon--after--height; + line-height: $ibo-datamodel-viewer--abstract-class-icon--after--line-height; + border-radius: $ibo-datamodel-viewer--abstract-class-icon--after--border-radius; + border: $ibo-datamodel-viewer--abstract-class-icon--after--border; + color: $ibo-datamodel-viewer--abstract-class-icon--after--color; + background-color: $ibo-datamodel-viewer--abstract-class-icon--after--background-color; + + @extend %ibo-font-ral-bol-50; + } } .ibo-datamodel-viewer--parent--spacer{ @@ -80,6 +151,7 @@ $ibo-datamodel-viewer--lifecycle-image--margin-bottom: $ibo-spacing-500 !default height: $ibo-datamodel-viewer--classes-list--height; width: $ibo-datamodel-viewer--classes-list--width; padding-left: $ibo-datamodel-viewer--classes-list--padding-left; + padding-top: $ibo-datamodel-viewer--classes-list--padding-top; overflow-y: scroll; } diff --git a/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php b/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php index 58bac2008c..02c23595fc 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Controller/ManageBrickController.php @@ -689,6 +689,7 @@ class ManageBrickController extends BrickController $sValue = $oAttDef->GetAsHTML($oCurrentRow->Get($sItemAttr)); $sSortValue = $oCurrentRow->Get($sItemAttr); } + $sAttType = $oAttDef->GetType(); unset($oAttDef); // For simple fields, we get the raw (stored) value as well @@ -705,7 +706,7 @@ class ManageBrickController extends BrickController 'object_class' => $sCurrentObjectClass, 'object_id' => $sCurrentObjectId, 'attribute_code' => $sItemAttr, - 'attribute_type' => $sAttDefClass, + 'attribute_type' => $sAttType, 'value_raw' => $attValueRaw, 'value_html' => $sValue, 'sort_value' => $sSortValue, diff --git a/datamodels/2.x/itop-portal-base/portal/src/Controller/ObjectController.php b/datamodels/2.x/itop-portal-base/portal/src/Controller/ObjectController.php index 5ccf29f7a2..07627b9e56 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Controller/ObjectController.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Controller/ObjectController.php @@ -1385,7 +1385,7 @@ class ObjectController extends BrickController 'object_id' => $oNewLink->GetKey(), 'prefix' => 'lnk__', 'attribute_code' => $sAttCode, - 'attribute_type' => get_class($oAttDef), + 'attribute_type' => $oAttDef->GetType(), 'value_html' => $sValue, ]; @@ -1442,7 +1442,7 @@ class ObjectController extends BrickController 'object_class' => $sObjectClass, 'object_id' => $oObject->GetKey(), 'attribute_code' => $oAttDef->GetCode(), - 'attribute_type' => get_class($oAttDef), + 'attribute_type' => $oAttDef->GetType(), ]; // - Value raw diff --git a/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php b/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php index 3b176bd308..95e69c7e7d 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php @@ -324,7 +324,7 @@ class BrowseBrickHelper 'object_class' => $sCurrentObjectClass, 'object_id' => $sCurrentObjectId, 'attribute_code' => $sNameAttCode, - 'attribute_type' => $sNameAttDefClass, + 'attribute_type' => $sNameAttDef->GetType(), 'value_raw' => $value->Get($sNameAttCode), ], ]; @@ -415,7 +415,7 @@ class BrowseBrickHelper 'object_class' => $sCurrentObjectClass, 'object_id' => $sCurrentObjectId, 'attribute_code' => $aField['code'], - 'attribute_type' => $sAttDefClass, + 'attribute_type' => $oAttDef->GetType(), 'value_raw' => $attValueRaw, 'value_html' => $sHtmlForFieldValue, ]; diff --git a/dictionaries/cs.dictionary.itop.ui.php b/dictionaries/cs.dictionary.itop.ui.php index 235f38ab21..3a614f86b2 100755 --- a/dictionaries/cs.dictionary.itop.ui.php +++ b/dictionaries/cs.dictionary.itop.ui.php @@ -729,6 +729,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [ 'UI:Query:UrlV1' => 'Nebyl specifikován seznam sloupců k exportu. Bez této informace nemůže stránka export-V2.php provést export. Pro export všech polí použijte stránku export.php. Pokud však chcete udržet konzistenci v delším časovém horzontu, použijte stávající stránku a specifikujte paramter "fields".', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' schéma objektů', 'UI:Schema:TitleForClass' => '%1$s schéma', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Kategorie %1$s', 'UI:Schema:Relationships' => 'Vztahy', 'UI:Schema:AbstractClass' => 'Abstraktní třída: instance objektu této třídy nemůže být vytvořena.', diff --git a/dictionaries/de.dictionary.itop.ui.php b/dictionaries/de.dictionary.itop.ui.php index 1f6bff387f..dc9374d16c 100644 --- a/dictionaries/de.dictionary.itop.ui.php +++ b/dictionaries/de.dictionary.itop.ui.php @@ -728,6 +728,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', [ 'UI:Query:UrlV1' => 'Die Liste der Felder wurde nicht spezifiziert. Die Seite export-V2.php kann ohne diese Angabe nicht verarbeitet werden. Deswegen, zeigt die nachstehende URL zu der Legacy-Page: export.php. Diese Legacy-Version des Exports hat folgende Limitierungen: Die Liste exportierter Felder kann, abhängig vom Output-Format und vom Datenmodell von '.ITOP_APPLICATION_SHORT.', variieren. Möchten Sie garantieren, dass die Liste aller exportierten Spalten stabil bleibt, müssen Sie einen Wert für das Attribut Feld angeben und die Seite export-V2.php nutzen.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' Objekte-Schema', 'UI:Schema:TitleForClass' => '%1$s Schema', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Kategorie %1$s', 'UI:Schema:Relationships' => 'Wechselseite Beziehungen', 'UI:Schema:AbstractClass' => 'Abstrakte Klasse: ein Objekt dieser Klasse kann nicht instanziiert werden.', diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 1f0e3101ae..7ea6170e9e 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -760,6 +760,7 @@ Dict::Add('EN US', 'English', 'English', [ 'UI:Query:UrlV1' => 'The list of fields has been left unspecified. The page export-V2.php cannot be invoked without this information. Therefore, the URL suggested here below points to the legacy page: export.php. This legacy version of the export has the following limitation: the list of exported fields may vary depending on the output format and the data model of '.ITOP_APPLICATION_SHORT.'.
Should you want to guarantee that the list of exported columns will remain stable on the long run, then you must specify a value for the attribute "Fields" and use the page export-V2.php.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' objects schema', 'UI:Schema:TitleForClass' => '%1$s schema', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one', 'UI:Schema:CategoryMenuItem' => 'Category %1$s', 'UI:Schema:Relationships' => 'Relationships', 'UI:Schema:AbstractClass' => 'Abstract class: no object from this class can be instantiated.', diff --git a/dictionaries/en_gb.dictionary.itop.ui.php b/dictionaries/en_gb.dictionary.itop.ui.php index 231cca9d04..f2acc848f8 100644 --- a/dictionaries/en_gb.dictionary.itop.ui.php +++ b/dictionaries/en_gb.dictionary.itop.ui.php @@ -757,6 +757,7 @@ Dict::Add('EN GB', 'British English', 'British English', [ 'UI:Query:UrlV1' => 'The list of fields has been left unspecified. The page export-V2.php cannot be invoked without this information. Therefore, the URL suggested here below points to the legacy page: export.php. This legacy version of the export has the following limitation: the list of exported fields may vary depending on the output format and the data model of '.ITOP_APPLICATION_SHORT.'.
Should you want to guarantee that the list of exported columns will remain stable on the long run, then you must specify a value for the attribute "Fields" and use the page export-V2.php.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' objects schema', 'UI:Schema:TitleForClass' => '%1$s schema', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one', 'UI:Schema:CategoryMenuItem' => 'Category %1$s', 'UI:Schema:Relationships' => 'Relationships', 'UI:Schema:AbstractClass' => 'Abstract class: no object from this class can be instantiated.', diff --git a/dictionaries/es_cr.dictionary.itop.ui.php b/dictionaries/es_cr.dictionary.itop.ui.php index f692144ec4..2ccc8d0b0b 100644 --- a/dictionaries/es_cr.dictionary.itop.ui.php +++ b/dictionaries/es_cr.dictionary.itop.ui.php @@ -726,6 +726,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [ 'UI:Query:UrlForExcel' => 'URL para usarse en consultas web de MS-Excel', 'UI:Query:UrlV1' => 'La lista de campos se ha dejado sin especificación. La página export-V2.php no puede ser invocada sin está información. Por lo tanto, el URL sugerido abajo apunta a la página legada: export.php. Esta versión legada de exportación tiene la siguiente limitación: la lista de campos exportados puede variar, dependiendo del formato de salida y el modelo de datos de '.ITOP_APPLICATION_SHORT.'.Desea garantizar que la lista de columnas exportadas permanenzcan estables durante la ejecución, entonces debe especificar un valor para el atributo "Campos" y utilice la página export-V2.php.', 'UI:Schema:Title' => 'Esquema de Objetos en '.ITOP_APPLICATION_SHORT, 'UI:Schema:TitleForClass' => 'Esquema de %1$s', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Categoria %1$s', 'UI:Schema:Relationships' => 'Relaciones', 'UI:Schema:AbstractClass' => 'Clase Abstracta: Ningún objeto de esta clase puede ser representado.', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index 69487d97f0..83dafedba1 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -786,6 +786,7 @@ Nous espérons que vous aimerez cette version autant que nous avons eu du plaisi 'UI:Query:UrlForExcel' => 'Lien à copier-coller dans Excel, pour déclarer une source de données à partir du web', 'UI:Query:UrlV1' => 'La liste des champs à exporter n\'a pas été spécifiée. La page export-V2.php ne peut pas fonctionner sans cette information. Par conséquent, le lien fourni ci-dessous pointe sur l\'ancienne page: export.php. Cette ancienne version de l\'export présente la limitation suivante : la liste des champs exportés varie en fonction du format de l\'export et du modèle de données.
Si vous devez garantir la stabilité du format de l\'export (liste des colonnes) sur le long terme, alors vous devrez renseigner l\'attribut "Champs" et utiliser la page export-V2.php.', 'UI:Schema:Title' => 'Modèle de données '.ITOP_APPLICATION_SHORT, 'UI:Schema:TitleForClass' => 'Modèle de données de %1$s', + 'UI:Schema:NoClassSelected' => 'Aucune classe sélectionnée, veuillez en choisir une', 'UI:Schema:CategoryMenuItem' => 'Catégorie %1$s', 'UI:Schema:Relationships' => 'Relations', 'UI:Schema:AbstractClass' => 'Classe abstraite : les objets de cette classe ne peuvent pas être instanciés.', diff --git a/dictionaries/hu.dictionary.itop.ui.php b/dictionaries/hu.dictionary.itop.ui.php index af27ebd5cd..2f06902352 100755 --- a/dictionaries/hu.dictionary.itop.ui.php +++ b/dictionaries/hu.dictionary.itop.ui.php @@ -731,6 +731,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [ 'UI:Query:UrlV1' => 'A mezők listája nem került meghatározásra. Az export-V2.php oldal nem hívható meg ezen információ nélkül. Ezért az alábbiakban javasolt URL az örökölt oldalra mutat: export.php. Az exportálásnak ez a régi változata a következő korlátozással rendelkezik: az exportált mezők listája a kimeneti formátumtól és a '.ITOP_APPLICATION_SHORT.' adatmodelltől függően változhat. Ha garantálni szeretné, hogy az exportált oszlopok listája hosszú távon stabil maradjon, akkor meg kell adnia a "Fields" attribútum értékét, és használnia kell a export-V2.php oldalt.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' objektum séma', 'UI:Schema:TitleForClass' => '%1$s séma', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => '%1$s kategória', 'UI:Schema:Relationships' => 'Kapcsolatok', 'UI:Schema:AbstractClass' => 'Absztrakt osztály: nem példányosítható belőle objektum.', diff --git a/dictionaries/it.dictionary.itop.ui.php b/dictionaries/it.dictionary.itop.ui.php index b6f5e6fa07..49166a199a 100644 --- a/dictionaries/it.dictionary.itop.ui.php +++ b/dictionaries/it.dictionary.itop.ui.php @@ -775,6 +775,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [ 'UI:Query:UrlV1' => 'L\'elenco dei campi è stato lasciato non specificato. La pagina export-V2.php non può essere invocata senza queste informazioni. Pertanto, l\'URL suggerito di seguito punta alla pagina legacy: export.php. Questa versione legacy dell\'esportazione ha il seguente limite: l\'elenco dei campi esportati può variare a seconda del formato di output e del modello di dati di '.ITOP_APPLICATION_SHORT.'. Se vuoi garantire che l\'elenco delle colonne esportate rimanga stabile nel lungo periodo, devi specificare un valore per l\'attributo "Campi" e utilizzare la pagina export-V2.php.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' schema degli oggetti', 'UI:Schema:TitleForClass' => '%1$s schema', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Categoria %1$s', 'UI:Schema:Relationships' => 'Relazioni', 'UI:Schema:AbstractClass' => 'Classe astratta: nessun oggetto di questa classe può essere istanziato.', diff --git a/dictionaries/ja.dictionary.itop.ui.php b/dictionaries/ja.dictionary.itop.ui.php index aa603d6e71..914b0123b6 100644 --- a/dictionaries/ja.dictionary.itop.ui.php +++ b/dictionaries/ja.dictionary.itop.ui.php @@ -732,6 +732,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [ 'UI:Query:UrlV1' => 'The list of fields has been left unspecified. The page export-V2.php cannot be invoked without this information. Therefore, the URL suggested here below points to the legacy page: export.php. This legacy version of the export has the following limitation: the list of exported fields may vary depending on the output format and the data model of '.ITOP_APPLICATION_SHORT.'.
Should you want to guarantee that the list of exported columns will remain stable on the long run, then you must specify a value for the attribute "Fields" and use the page export-V2.php.~~', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' オブジェクトスキーマ', 'UI:Schema:TitleForClass' => '%1$s schema~~', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'カテゴリ %1$s', 'UI:Schema:Relationships' => '関係', 'UI:Schema:AbstractClass' => '抽象クラス:このクラスのインスタンスを作成することはできません。', diff --git a/dictionaries/nl.dictionary.itop.ui.php b/dictionaries/nl.dictionary.itop.ui.php index aef5eb85e8..6a2d72a6b7 100644 --- a/dictionaries/nl.dictionary.itop.ui.php +++ b/dictionaries/nl.dictionary.itop.ui.php @@ -730,6 +730,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [ 'UI:Query:UrlV1' => 'De lijst van velden is leeg gelaten. De pagina export-V2.php kan niet aangeroepen worden zonder deze informatie.Daarom verwijst de onderstaande link naar de oude export-pagina: export.php. Deze verouderde versie heeft enkele beperkingen: de lijst van geëxporteerde velden kan verschillen afhankelijk van het gekozen export-formaat en het datamodel van '.ITOP_APPLICATION_SHORT.'.Als je wil dat de lijst van geëxporteerde kolommen hetzelfde blijft over lange tijd, dan moet je een waarde opgeven voor het attribuut "Velden" en de pagina export-V2.php gebruiken.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' objecten-schema', 'UI:Schema:TitleForClass' => '%1$s schema', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Categorie %1$s', 'UI:Schema:Relationships' => 'Relaties', 'UI:Schema:AbstractClass' => 'Abstracte klasse: objecten van deze klasse kunnen niet worden geïnstantieerd.', diff --git a/dictionaries/pl.dictionary.itop.ui.php b/dictionaries/pl.dictionary.itop.ui.php index cd3489a8c0..5cf45afbcb 100644 --- a/dictionaries/pl.dictionary.itop.ui.php +++ b/dictionaries/pl.dictionary.itop.ui.php @@ -743,6 +743,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [ 'UI:Query:UrlV1' => 'Lista pól pozostała nieokreślona. Strona export-V2.php nie może zostać wywołana bez tych informacji. Dlatego sugerowany poniżej adres URL wskazuje na starszą stronę: export.php. Ta starsza wersja eksportu ma następujące ograniczenie: lista eksportowanych pól może się różnić w zależności od formatu wyjściowego i modelu danych '.ITOP_APPLICATION_SHORT.'.
Jeśli chcesz zagwarantować, że lista eksportowanych kolumn pozostanie stabilna w dłuższej perspektywie, musisz określić wartość dla atrybutu "Pola" i użyć strony export-V2.php.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' schemat obiektów', 'UI:Schema:TitleForClass' => 'Schemat %1$s', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Kategoria %1$s', 'UI:Schema:Relationships' => 'Relacje', 'UI:Schema:AbstractClass' => 'Klasa abstrakcyjna: nie można utworzyć instancji obiektu z tej klasy.', diff --git a/dictionaries/pt_br.dictionary.itop.ui.php b/dictionaries/pt_br.dictionary.itop.ui.php index 529f1a64f6..ec7b72b8ee 100644 --- a/dictionaries/pt_br.dictionary.itop.ui.php +++ b/dictionaries/pt_br.dictionary.itop.ui.php @@ -774,6 +774,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [ 'UI:Query:UrlV1' => 'A lista de campos não foi especificada. A página export-V2.php não pode ser chamada sem essa informação. Portanto, o URL sugerido abaixo aponta para a página herdada: export.php. Essa versão herdada da exportação tem a seguinte limitação: a lista de campos exportados pode variar dependendo do formato de saída e do modelo de dados do '.ITOP_APPLICATION_SHORT.'.Se você quiser garantir que a lista de colunas exportadas permaneça estável a longo prazo, então você deve especificar um valor para o atributo "Fields" e usar a página export-V2.php', 'UI:Schema:Title' => 'Esquema de objetos', 'UI:Schema:TitleForClass' => 'Esquema de %1$s', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Categoria %1$s', 'UI:Schema:Relationships' => 'Relações', 'UI:Schema:AbstractClass' => 'Classe abstrata: nenhum objeto desta classe pode ser instanciado', diff --git a/dictionaries/ru.dictionary.itop.ui.php b/dictionaries/ru.dictionary.itop.ui.php index 0a024ff48b..056a36ed6a 100644 --- a/dictionaries/ru.dictionary.itop.ui.php +++ b/dictionaries/ru.dictionary.itop.ui.php @@ -732,6 +732,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [ 'UI:Query:UrlV1' => 'Список полей был оставлен неопределенным. Страница export-V2.php не может быть вызван без этой информации. Поэтому URL-адрес, предложенный здесь ниже, указывает на устаревшую страницу: export.php. Эта устаревшая версия экспорта имеет следующее ограничение: список экспортируемых полей может варьироваться в зависимости от формата вывода и модели данных '.ITOP_APPLICATION_SHORT.'. Если вы хотите гарантировать, что список экспортируемых столбцов будет оставаться стабильным в долгосрочной перспективе, то вы должны указать значение атрибута "Экспорт. поля" и использовать страницу export-V2.php.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' схема объектов', 'UI:Schema:TitleForClass' => '%1$s schema~~', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Категория %1$s', 'UI:Schema:Relationships' => 'Отношения', 'UI:Schema:AbstractClass' => 'Абстрактный класс: используется для наследования свойств, объекты этого класса не создаются.', diff --git a/dictionaries/sk.dictionary.itop.ui.php b/dictionaries/sk.dictionary.itop.ui.php index 35c8ed9244..539d06bbab 100644 --- a/dictionaries/sk.dictionary.itop.ui.php +++ b/dictionaries/sk.dictionary.itop.ui.php @@ -734,6 +734,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [ 'UI:Query:UrlV1' => 'The list of fields has been left unspecified. The page export-V2.php cannot be invoked without this information. Therefore, the URL suggested here below points to the legacy page: export.php. This legacy version of the export has the following limitation: the list of exported fields may vary depending on the output format and the data model of '.ITOP_APPLICATION_SHORT.'.
Should you want to guarantee that the list of exported columns will remain stable on the long run, then you must specify a value for the attribute "Fields" and use the page export-V2.php.~~', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.' objektová schéma', 'UI:Schema:TitleForClass' => '%1$s schema~~', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Kategória %1$s', 'UI:Schema:Relationships' => 'Vzťahy', 'UI:Schema:AbstractClass' => 'Abstraktná trieda: žiadny objekt z tejto triedy nemôže byť inštancovaný.', diff --git a/dictionaries/tr.dictionary.itop.ui.php b/dictionaries/tr.dictionary.itop.ui.php index b74e3f264b..8e5907c968 100644 --- a/dictionaries/tr.dictionary.itop.ui.php +++ b/dictionaries/tr.dictionary.itop.ui.php @@ -732,6 +732,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [ 'UI:Query:UrlV1' => 'Alanların listesi belirtilmeden bırakılmıştır. export-V2.php sayfası bu bilgi olmadan çağrılamaz. Bu nedenle, aşağıda önerilen URL eski sayfaya işaret etmektedir: export.php. Dışa aktarmanın bu eski sürümü aşağıdaki sınırlamaya sahiptir: dışa aktarılan alanların listesi, '.ITOP_APPLICATION_SHORT.'\'un çıktı biçimine ve veri modeline bağlı olarak değişebilir. Dışa aktarılan sütunların listesinin uzun vadede sabit kalacağını garanti etmek istiyorsanız, "Alanlar" özelliği için bir değer belirtmeli ve export-V2.php sayfasını kullanmalısınız.', 'UI:Schema:Title' => 'iTop objects schema', 'UI:Schema:TitleForClass' => '%1$s schema~~', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => 'Kategori %1$s', 'UI:Schema:Relationships' => 'İlişkiler', 'UI:Schema:AbstractClass' => 'Soyut sınıf: bu sınıftan nesne türetilemez.', diff --git a/dictionaries/zh_cn.dictionary.itop.ui.php b/dictionaries/zh_cn.dictionary.itop.ui.php index ffd02dd33f..bfbfbcf33f 100644 --- a/dictionaries/zh_cn.dictionary.itop.ui.php +++ b/dictionaries/zh_cn.dictionary.itop.ui.php @@ -731,6 +731,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [ 'UI:Query:UrlV1' => '没有定义字段列表. 没有这个信息页面export-V2.php无法调用. 因此, 建议的以下 URL 指向传统页面: export.php. 该传统版本导出具有以下限制: 导出的字段列表很大程度依赖于导出格式和'.ITOP_APPLICATION_SHORT.'数据模型.
如果您需要确保导出的列保持长期稳定, 则必须为属性 "Fields" 指定值并使用页面export-V2.php.', 'UI:Schema:Title' => ITOP_APPLICATION_SHORT.'对象模型', 'UI:Schema:TitleForClass' => '%1$s 模式', + 'UI:Schema:NoClassSelected' => 'No class selected, please choose one~~', 'UI:Schema:CategoryMenuItem' => '类别 %1$s', 'UI:Schema:Relationships' => '关联', 'UI:Schema:AbstractClass' => '抽象类型: 此类型不能实例化对象.', diff --git a/pages/schema.php b/pages/schema.php index bde481ac81..9767dd64c0 100644 --- a/pages/schema.php +++ b/pages/schema.php @@ -6,8 +6,10 @@ */ use Combodo\iTop\Application\Helper\WebResourcesHelper; +use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Component\Html\HtmlFactory; use Combodo\iTop\Application\UI\Base\Component\Input\Select\Select; use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectOptionUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory; @@ -27,15 +29,235 @@ LoginWebPage::DoLogin(); // Check user rights and prompt if needed ApplicationMenu::CheckMenuIdEnabled('DataModelMenu'); /** - * Helper for this page -> link to a class + * Get a short or full class label. + * + * Short: Class Label + * Full: Class Label (ClassName) + * + * Short: UserRequest + * Full: User Request (UserRequest) + * + * @param string $sClass + * + * @return string + * @throws CoreException + * @throws DictExceptionMissingString + * @throws ReflectionException */ -function MakeClassHLink($sClass, $sContext) +function GetClassLabel(string $sClass): string { + $sName = MetaModel::GetName($sClass); + + $oClass = new ReflectionClass($sClass); + + $sAbstract = ''; + if ($oClass->isAbstract()) { + $sAbstract = ''; + } + + return "$sAbstract $sName $sClass"; +} + +/** + * Get class hierarchy as breadcrumb. + * + * @param string $sClass + * @param string $sContext + * + * @return string + * @throws CoreException + * @throws ReflectionException + */ +function GetClassHierarchy(string $sClass, string $sContext): string +{ + $sClassSpacer = ''; + $aParentClasses = []; + foreach (MetaModel::EnumParentClasses($sClass) as $sParentClass) { + $aParentClasses[] = MakeClassHLink($sParentClass, $sContext, "ibo-button ibo-button ibo-block ibo-is-alternative ibo-is-neutral", true); + } + + if (count($aParentClasses) > 0) { + $sParents = $sClassSpacer.implode($sClassSpacer, $aParentClasses); + } else { + $sParents = ''; + } + + return "
".Dict::S('UI:Schema:AllClasses')." $sParents".$sClassSpacer.MakeClassHLink($sClass, $sContext, "ibo-button ibo-button ibo-block ibo-is-alternative ibo-is-neutral", true)."
"; +} + +/** + * Make a class link. + * + * @param string $sClass + * @param string $sContext + * @param string $sCssClasses + * + * @return string + * @throws CoreException + * @throws DictExceptionMissingString + * @throws ReflectionException + */ +function MakeClassHLink(string $sClass, string $sContext, string $sCssClasses = ''): string +{ + $sLabel = GetClassLabel($sClass); + return "".MetaModel::GetName($sClass)." (".$sClass.")"; + )."\" class=\"$sCssClasses\">$sLabel"; +} + +/** + * Display class information. + * + * @param string $sClass + * @param string $sContext + * + * @return array + * @throws CoreException + * @throws DictExceptionMissingString + * @throws ReflectionException + */ +function GetClassInformation(string $sClass, string $sContext): array +{ + // List the attributes of the object + $aForwardChangeTracking = MetaModel::GetTrackForwardExternalKeys($sClass); + $aDetails = []; + + $aOrigins = []; + foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { + if ($oAttDef->IsExternalKey()) { + $sValue = Dict::Format('UI:Schema:ExternalKey_To', MakeClassHLink($oAttDef->GetTargetClass(), $sContext)); + if (array_key_exists($sAttCode, $aForwardChangeTracking)) { + $oLinkSet = $aForwardChangeTracking[$sAttCode]; + $sRemoteClass = $oLinkSet->GetHostClass(); + $sValue = $sValue."*"; + } + } elseif ($oAttDef->IsLinkSet()) { + $sValue = MakeClassHLink($oAttDef->GetLinkedClass(), $sContext); + } else { + $sValue = $oAttDef->GetDescription(); + } + + [$classShortName, $label, $description] = array_values($oAttDef->GetTypeInformation()); + + $sOrigin = MetaModel::GetAttributeOrigin($sClass, $sAttCode); + $aOrigins[$sOrigin] = true; + $sMoreInfo = ""; + $sDefaultNullValue = ''; + if (call_user_func([get_class($oAttDef), 'IsBasedOnDBColumns'])) { + + $aMoreInfo = []; + if ($oAttDef->IsNullAllowed()) { + $aMoreInfo[] = Dict::S('UI:Schema:NullAllowed'); + $sDefaultNullValue = (!is_null($oAttDef->GetNullValue()) ? $oAttDef->GetNullValue() : null); + if (!is_null($sDefaultNullValue) && !is_string($sDefaultNullValue)) { + $sDefaultNullValue = json_encode($sDefaultNullValue); + } + $sDefaultNullValue = (!is_null($sDefaultNullValue) ? Dict::Format( + 'UI:Schema:DefaultNullValue', + $sDefaultNullValue + ) : ''); + } else { + $aMoreInfo[] = Dict::S('UI:Schema:NullNotAllowed'); + } + if ($oAttDef->GetDefaultValue()) { + $sDefaultValue = $oAttDef->GetDefaultValue(); + if (!is_string($sDefaultValue)) { + $sDefaultValue = json_encode($sDefaultValue); + } + $aMoreInfo[] = Dict::Format("UI:Schema:Default_Description", $sDefaultValue); + } + $sMoreInfo .= implode(', ', $aMoreInfo); + } + $sAttrCode = $oAttDef->GetCode(); + + if ($oAttDef instanceof AttributeEnum) { + // Display localized values for the enum (which depend on the localization provided by the class) + $aLocalizedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, []); + $aDescription = []; + foreach ($aLocalizedValues as $val => $sDisplay) { + $aDescription[] = $sDisplay." (".$val.")"; + } + $sAllowedValues = implode(', ', $aDescription); + } elseif (is_object($oAllowedValuesDef = $oAttDef->GetValuesDef())) { + $sAllowedValues = str_replace("Filter: ", "", $oAllowedValuesDef->GetValuesDescription()); + $sAllowedValuesEscpd = utils::HtmlEntities($sAllowedValues); + + $sFilterURL = urlencode($sAllowedValues); + $sAllowedValues = ' '.Dict::S('UI:Schema:Attribute/Filter').""; + } else { + $sAllowedValues = ''; + } + $sAttrValueEscpd = utils::HtmlEntities($sValue); + $sAttrTypeDescEscpd = utils::HtmlEntities($description); + $sAttrOriginEscpd = utils::HtmlEntities($sOrigin); + $sDefaultNullValueEscpd = utils::HtmlEntities($sDefaultNullValue); + + $aDetails[] = [ + 'code' => ''.$oAttDef->GetLabel().' ('.$oAttDef->GetCode().')', + 'type' => ''.$label.' ('.$classShortName.')', + 'origincolor' => '
', + 'origin' => "$sOrigin", + 'values' => $sAllowedValues, + 'moreinfo' => ''.$sMoreInfo.'', + ]; + + } + + return [ + 'details' => $aDetails, + 'origins' => $aOrigins, + ]; +} + +/** + * Display class attributes. + * + * @param iTopWebPage $oPage + * @param string $sClass + * @param string $sContext + * + * @return void + */ +function DisplayClassAttributes(iTopWebPage $oPage, string $sClass, string $sContext): void +{ + $aClassInformation = GetClassInformation($sClass, $sContext); + + $aConfig = [ + 'origincolor' => ['label' => "", 'description' => ""], + 'code' => ['label' => Dict::S('UI:Schema:AttributeCode'), 'description' => Dict::S('UI:Schema:AttributeCode+')], + 'type' => ['label' => Dict::S('UI:Schema:Type'), 'description' => Dict::S('UI:Schema:Type+')], + 'values' => ['label' => Dict::S('UI:Schema:AllowedValues'), 'description' => Dict::S('UI:Schema:AllowedValues+')], + 'moreinfo' => ['label' => Dict::S('UI:Schema:MoreInfo'), 'description' => Dict::S('UI:Schema:MoreInfo+')], + 'origin' => ['label' => Dict::S('UI:Schema:Origin'), 'description' => Dict::S('UI:Schema:Origin+')], + ]; + $oTablePanel = PanelUIBlockFactory::MakeForClass($sClass, ''); + $oTablePanel->AddCSSClass('ibo-datatable-panel'); + + $oAttributesTable = DataTableUIBlockFactory::MakeForStaticData('', $aConfig, $aClassInformation['details'], 'ibo-datamodel-viewer--attributes-table', [], "", ['pageLength' => -1]); + $oTablePanel->AddSubBlock($oAttributesTable); + $oPage->AddUiBlock($oTablePanel); + $sOrigins = json_encode(array_keys($aClassInformation['origins'])); + + //color calculation in order to keep 1 color for 1 extended class. Colors are interpolated and will be used for + // graph scheme color too + $oPage->add_ready_script( + <<< EOF + var aOrigins = $sOrigins; + var aColors = d3.scale.linear().domain([1,aOrigins.length]) + .interpolate(d3.interpolateHcl) + .range([d3.rgb("#007AFF"), d3.rgb('#FFF500')]); + $.each(aOrigins,function(idx, origin){ + $('.originColor'+origin).css('background-color',aColors(aOrigins.indexOf(origin))); + }); + Array.prototype.forEach.call($(".listResults").find('td:nth-child(1),th:nth-child(1)'), function(e){ + $(e).removeClass("header").addClass("ibo-datamodel-viewer--origin-cell"); + }); + +EOF + ); } /** @@ -222,11 +444,18 @@ JS /** * Helper for the trigger */ -function DisplayTriggers($oPage, $sClass) +function DisplayTriggers(iTopWebPage $oPage, string $sClass) { $sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)); $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObject WHERE target_class IN ('$sClassList')")); - cmdbAbstractObject::DisplaySet($oPage, $oSet, ['block_id' => 'triggers']); + try { + cmdbAbstractObject::DisplaySet($oPage, $oSet, ['block_id' => 'triggers']); + } catch (Exception $e) { + $oPage->AddUiBlock(AlertUIBlockFactory::MakeForFailure('Unable to load current class triggers.')); + IssueLog::Error('Unable to load current class triggers.', null, [ + 'root_cause' => $e->getMessage(), + ]); + } } function DisplayEvents(WebPage $oPage, $sClass) @@ -333,7 +562,7 @@ function DisplayClassesList($oPage, $oLayout, $sContext) $oLayout->AddSideHtml("
"); $oListSearch = new Select("ibo-datamodel-viewer--class-search"); - $oListSearch->SetName('aa'); + $oListSearch->SetName('datamodel_class_select'); // Get all the "root" classes for display $aRootClasses = []; $aClassLabelAndCodeAsJSON = []; @@ -897,156 +1126,38 @@ JS * @param string $sClass * @param string $sContext * - * @throws \CoreException + * @throws CoreException|ReflectionException */ function DisplayClassDetails($oPage, $sClass, $sContext) { - $aParentClasses = []; - foreach (MetaModel::EnumParentClasses($sClass) as $sParentClass) { - $aParentClasses[] = MakeClassHLink($sParentClass, $sContext); - } - if (count($aParentClasses) > 0) { - $sParents = implode(' ', $aParentClasses).' '.MetaModel::GetName($sClass).'('.$sClass.')'; - } else { - $sParents = ''; - } - $sClassHierarchy = ("[".Dict::S('UI:Schema:AllClasses')."] $sParents"); + // Hierarchy + $sClassHierarchy = GetClassHierarchy($sClass, $sContext); + $oPage->AddUiBlock(HtmlFactory::MakeRaw($sClassHierarchy)); - $oPanel = PanelUIBlockFactory::MakeForClass($sClass, MetaModel::GetName($sClass).' ('.$sClass.')') - ->SetIcon(MetaModel::GetClassIcon($sClass, false)); - $sClassDescritpion = MetaModel::GetClassDescription($sClass); + // Class Title + $oPanel = PanelUIBlockFactory::MakeForClass($sClass, MetaModel::GetName($sClass).' ('.$sClass.')')->SetIcon(MetaModel::GetClassIcon($sClass, false)); $oEnhancedPanelSubtitle = $oPanel->GetSubTitleBlock(); - $sEnhancedPanelSubtitle = $sClassHierarchy.($sClassDescritpion == "" ? "" : ' - '.$sClassDescritpion); - if (MetaModel::IsAbstract($sClass)) { - $sEnhancedPanelSubtitle .= ' - '; + $sClassDescription = MetaModel::GetClassDescription($sClass); + $sTags = ''; + if (utils::IsNotNullOrEmptyString($sClassDescription)) { + $sTags .= ''.$sClassDescription.''; } - $oEnhancedPanelSubtitle->AddHtml($sEnhancedPanelSubtitle); + $sTags .= ''.str_replace(',', ' - ', MetaModel::GetCategory($sClass)).''; + if (MetaModel::IsAbstract($sClass)) { + $sTags .= ''.Dict::S('UI:Schema:AbstractClass').''; + } + $oEnhancedPanelSubtitle->AddSubBlock(HtmlFactory::MakeHtmlContent($sTags)); $oPage->AddUiBlock($oPanel); + + // Details container $oPage->AddTabContainer('details', '', $oPanel); $oPage->SetCurrentTabContainer('details'); - // List the attributes of the object - $aForwardChangeTracking = MetaModel::GetTrackForwardExternalKeys($sClass); - $aDetails = []; - $aOrigins = []; - foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { - if ($oAttDef->IsExternalKey()) { - $sValue = Dict::Format('UI:Schema:ExternalKey_To', MakeClassHLink($oAttDef->GetTargetClass(), $sContext)); - if (array_key_exists($sAttCode, $aForwardChangeTracking)) { - $oLinkSet = $aForwardChangeTracking[$sAttCode]; - $sRemoteClass = $oLinkSet->GetHostClass(); - $sValue = $sValue."*"; - } - } elseif ($oAttDef->IsLinkSet()) { - $sValue = MakeClassHLink($oAttDef->GetLinkedClass(), $sContext); - } else { - $sValue = $oAttDef->GetDescription(); - } - $sType = get_class($oAttDef); - $sTypeDict = $oAttDef->GetType(); - $sTypeDesc = $oAttDef->GetTypeDesc(); - - $sOrigin = MetaModel::GetAttributeOrigin($sClass, $sAttCode); - $aOrigins[$sOrigin] = true; - $sAllowedValues = ""; - $sMoreInfo = ""; - $sDefaultNullValue = ''; - if (call_user_func([get_class($oAttDef), 'IsBasedOnDBColumns'])) { - - $aMoreInfo = []; - if ($oAttDef->IsNullAllowed()) { - $aMoreInfo[] = Dict::S('UI:Schema:NullAllowed'); - $sDefaultNullValue = (!is_null($oAttDef->GetNullValue()) ? $oAttDef->GetNullValue() : null); - if (!is_null($sDefaultNullValue) && !is_string($sDefaultNullValue)) { - $sDefaultNullValue = json_encode($sDefaultNullValue); - } - $sDefaultNullValue = (!is_null($sDefaultNullValue) ? Dict::Format( - 'UI:Schema:DefaultNullValue', - $sDefaultNullValue - ) : ''); - } else { - $aMoreInfo[] = Dict::S('UI:Schema:NullNotAllowed'); - } - if ($oAttDef->GetDefaultValue()) { - $sDefaultValue = $oAttDef->GetDefaultValue(); - if (!is_string($sDefaultValue)) { - $sDefaultValue = json_encode($sDefaultValue); - } - $aMoreInfo[] = Dict::Format("UI:Schema:Default_Description", $sDefaultValue); - } - $sMoreInfo .= implode(', ', $aMoreInfo); - } - $sAttrCode = $oAttDef->GetCode(); - $sIsEnumValues = 'false'; - $sAllowedValuesEscpd = '""'; - if ($oAttDef instanceof AttributeEnum) { - // Display localized values for the enum (which depend on the localization provided by the class) - $aLocalizedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, []); - $aDescription = []; - foreach ($aLocalizedValues as $val => $sDisplay) { - $aDescription[] = $sDisplay." (".$val.")"; - } - $sAllowedValues = implode(', ', $aDescription); - $sIsEnumValues = 'true'; - } elseif (is_object($oAllowedValuesDef = $oAttDef->GetValuesDef())) { - $sAllowedValues = str_replace("Filter: ", "", $oAllowedValuesDef->GetValuesDescription()); - $sAllowedValuesEscpd = utils::HtmlEntities($sAllowedValues); - - $sFilterURL = urlencode($sAllowedValues); - $sAllowedValues = ' '.Dict::S('UI:Schema:Attribute/Filter').""; - } else { - $sAllowedValues = ''; - } - $sAttrValueEscpd = utils::HtmlEntities($sValue); - $sAttrTypeDescEscpd = utils::HtmlEntities($sTypeDesc); - $sAttrOriginEscpd = utils::HtmlEntities($sOrigin); - $sDefaultNullValueEscpd = utils::HtmlEntities($sDefaultNullValue); - - $aDetails[] = [ - 'code' => ''.$oAttDef->GetLabel().' ('.$oAttDef->GetCode().')', - 'type' => ''.$sTypeDict.' ('.$sType.')', - 'origincolor' => '
', - 'origin' => "$sOrigin", - 'values' => $sAllowedValues, - 'moreinfo' => ''.$sMoreInfo.'', - ]; - - } + // Attributes $oPage->SetCurrentTab('UI:Schema:Attributes'); - $aConfig = [ - 'origincolor' => ['label' => "", 'description' => ""], - 'code' => ['label' => Dict::S('UI:Schema:AttributeCode'), 'description' => Dict::S('UI:Schema:AttributeCode+')], - 'type' => ['label' => Dict::S('UI:Schema:Type'), 'description' => Dict::S('UI:Schema:Type+')], - 'values' => ['label' => Dict::S('UI:Schema:AllowedValues'), 'description' => Dict::S('UI:Schema:AllowedValues+')], - 'moreinfo' => ['label' => Dict::S('UI:Schema:MoreInfo'), 'description' => Dict::S('UI:Schema:MoreInfo+')], - 'origin' => ['label' => Dict::S('UI:Schema:Origin'), 'description' => Dict::S('UI:Schema:Origin+')], - ]; - $oTablePanel = PanelUIBlockFactory::MakeForClass($sClass, ''); - $oTablePanel->AddCSSClass('ibo-datatable-panel'); - - $oAttributesTable = DataTableUIBlockFactory::MakeForStaticData('', $aConfig, $aDetails, 'ibo-datamodel-viewer--attributes-table', [], "", ['pageLength' => -1]); - $oTablePanel->AddSubBlock($oAttributesTable); - $oPage->AddUiBlock($oTablePanel); - $sOrigins = json_encode(array_keys($aOrigins)); - - //color calculation in order to keep 1 color for 1 extended class. Colors are interpolated and will be used for - // graph scheme color too - $oPage->add_ready_script( - <<< EOF - var aOrigins = $sOrigins; - var aColors = d3.scale.linear().domain([1,aOrigins.length]) - .interpolate(d3.interpolateHcl) - .range([d3.rgb("#007AFF"), d3.rgb('#FFF500')]); - $.each(aOrigins,function(idx, origin){ - $('.originColor'+origin).css('background-color',aColors(aOrigins.indexOf(origin))); - }); - Array.prototype.forEach.call($(".listResults").find('td:nth-child(1),th:nth-child(1)'), function(e){ - $(e).removeClass("header").addClass("ibo-datamodel-viewer--origin-cell"); - }); - -EOF - ); + DisplayClassAttributes($oPage, $sClass, $sContext); + // Related classes $oPage->SetCurrentTab('UI:Schema:RelatedClasses'); DisplayRelatedClassesGraph($oPage, $sClass); @@ -1060,12 +1171,15 @@ EOF $oPage->add_ready_script('$("#ClassHierarchy").treeview({collapsed: false,});'); } + // Lifecycle $oPage->SetCurrentTab('UI:Schema:LifeCycle'); DisplayLifecycle($oPage, $sClass); + // Triggers $oPage->SetCurrentTab('UI:Schema:Triggers'); DisplayTriggers($oPage, $sClass); + // Events $oPage->SetCurrentTab('UI:Schema:Events'); DisplayEvents($oPage, $sClass); @@ -1100,7 +1214,6 @@ $oPage->SetBreadCrumbEntry( ); $oTitle = TitleUIBlockFactory::MakeForPage(Dict::S('UI:Schema:Title')); -$oPage->AddUiBlock($oTitle); $oLayout->AddSideHtml("
"); DisplayClassesList($oPage, $oLayout, $sContext); $oLayout->AddSideHtml("
"); @@ -1118,6 +1231,11 @@ switch ($operation) { } // no break default: + $sSource = APPROOT."images/illustrations/undraw_reading_time.svg"; + $oEmpty = HtmlFactory::MakeRaw("
". + file_get_contents($sSource)."
".Dict::S('UI:Schema:NoClassSelected')."
"); + $oLayout->AddSubBlock($oEmpty); + break; } $oPage->add(""); $oPage->add(""); diff --git a/sources/Application/UI/Base/Component/DataTable/DataTableUIBlockFactory.php b/sources/Application/UI/Base/Component/DataTable/DataTableUIBlockFactory.php index 01e1acab80..f061f841e5 100644 --- a/sources/Application/UI/Base/Component/DataTable/DataTableUIBlockFactory.php +++ b/sources/Application/UI/Base/Component/DataTable/DataTableUIBlockFactory.php @@ -27,9 +27,9 @@ use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory; use Combodo\iTop\Application\UI\Base\iUIBlock; use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock; +use Combodo\iTop\Application\WebPage\WebPage; use Combodo\iTop\Controller\AjaxRenderController; use DBObjectSet; -use DeprecatedCallsLog; use Dict; use DisplayBlock; use IssueLog; @@ -38,7 +38,6 @@ use MenuBlock; use MetaModel; use UserRights; use utils; -use Combodo\iTop\Application\WebPage\WebPage; /** * Class DataTableUIBlockFactory @@ -556,7 +555,7 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory 'object_class' => $sClassName, 'class_alias' => $sClassAlias, 'attribute_code' => $sAttCode, - 'attribute_type' => $sAttDefClass, + 'attribute_type' => $oAttDef->GetType(), 'attribute_label' => $sAttLabel, 'render' => $oAttDef->GetRenderForDataTable($sClassAlias), ]; @@ -738,7 +737,7 @@ JS; 'object_class' => $sClassName, 'class_alias' => $sClassAlias, 'attribute_code' => $sAttCode, - 'attribute_type' => $sAttDefClass, + 'attribute_type' => $oAttDef->GetType(), 'attribute_label' => $sAttLabel, ]; $aColumnDefinition["data"] = $sClassAlias."/".$sAttCode; diff --git a/sources/Core/AttributeDefinition/AttributeBoolean.php b/sources/Core/AttributeDefinition/AttributeBoolean.php index 0be6dafa69..68e720c8ee 100644 --- a/sources/Core/AttributeDefinition/AttributeBoolean.php +++ b/sources/Core/AttributeDefinition/AttributeBoolean.php @@ -11,6 +11,7 @@ use CMDBChangeOpSetAttributeScalar; use Combodo\iTop\Form\Field\SelectField; use DBObject; use Dict; +use ReflectionClass; /** * Map a boolean column to an attribute @@ -80,11 +81,13 @@ class AttributeBoolean extends AttributeInteger public function GetValueLabel($bValue) { + $oClass = new ReflectionClass(get_class($this)); + if (is_null($bValue)) { - $sLabel = Dict::S('Core:'.get_class($this).'/Value:null'); + $sLabel = Dict::S('Core:'.$oClass->getShortName().'/Value:null'); } else { $sValue = $bValue ? 'yes' : 'no'; - $sDefault = Dict::S('Core:'.get_class($this).'/Value:'.$sValue); + $sDefault = Dict::S('Core:'.$oClass->getShortName().'/Value:'.$sValue); $sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sValue, $sDefault, true /*user lang*/); } @@ -93,11 +96,13 @@ class AttributeBoolean extends AttributeInteger public function GetValueDescription($bValue) { + $oClass = new ReflectionClass(get_class($this)); + if (is_null($bValue)) { - $sDescription = Dict::S('Core:'.get_class($this).'/Value:null+'); + $sDescription = Dict::S('Core:'.$oClass->getShortName().'/Value:null+'); } else { $sValue = $bValue ? 'yes' : 'no'; - $sDefault = Dict::S('Core:'.get_class($this).'/Value:'.$sValue.'+'); + $sDefault = Dict::S('Core:'.$oClass->getShortName().'/Value:'.$sValue.'+'); $sDescription = $this->SearchLabel( '/Attribute:'.$this->m_sCode.'/Value:'.$sValue.'+', $sDefault, diff --git a/sources/Core/AttributeDefinition/AttributeDefinition.php b/sources/Core/AttributeDefinition/AttributeDefinition.php index 0d46996370..359d5c7de0 100644 --- a/sources/Core/AttributeDefinition/AttributeDefinition.php +++ b/sources/Core/AttributeDefinition/AttributeDefinition.php @@ -19,6 +19,7 @@ use Exception; use Expression; use FieldExpression; use MetaModel; +use ReflectionClass; use Str; use utils; use VariableExpression; @@ -131,12 +132,30 @@ abstract class AttributeDefinition public function GetType() { - return Dict::S('Core:'.get_class($this)); + $oClass = new ReflectionClass(get_class($this)); + return Dict::S('Core:'.$oClass->getShortName()); } public function GetTypeDesc() { - return Dict::S('Core:'.get_class($this).'+'); + $oClass = new ReflectionClass(get_class($this)); + return Dict::S('Core:'.$oClass->getShortName().'+'); + } + + /** + * Return type information. + * + * @since 3.3 + * @return array + */ + public function GetTypeInformation(): array + { + $oClass = new ReflectionClass(get_class($this)); + return [ + 'classShortName' => $oClass->getShortName(), + 'label' => Dict::S('Core:'.$oClass->getShortName()), + 'description' => Dict::S('Core:'.$oClass->getShortName().'+'), + ]; } abstract public function GetEditClass(); @@ -1076,7 +1095,7 @@ abstract class AttributeDefinition // Metadata $oFormField->AddMetadata('attribute-code', $this->GetCode()); - $oFormField->AddMetadata('attribute-type', get_class($this)); + $oFormField->AddMetadata('attribute-type', $this->GetType()); $oFormField->AddMetadata('attribute-label', $this->GetLabel()); // - Attribute flags $aPossibleAttFlags = MetaModel::EnumPossibleAttributeFlags(); diff --git a/sources/Renderer/Bootstrap/FieldRenderer/BsLinkedSetFieldRenderer.php b/sources/Renderer/Bootstrap/FieldRenderer/BsLinkedSetFieldRenderer.php index 3bc3b39f09..59553b6b60 100644 --- a/sources/Renderer/Bootstrap/FieldRenderer/BsLinkedSetFieldRenderer.php +++ b/sources/Renderer/Bootstrap/FieldRenderer/BsLinkedSetFieldRenderer.php @@ -852,7 +852,7 @@ JS 'object_class' => $sClass, 'object_id' => $oItem->GetKey(), 'attribute_code' => $sAttCode, - 'attribute_type' => get_class($oAttDef), + 'attribute_type' => $oAttDef->GetType(), ]; // - Value raw // For simple fields, we get the raw (stored) value as well