mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-08 02:24:12 +01:00
Compare commits
48 Commits
feature/re
...
class_extr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c80c93b4f | ||
|
|
efc6e6730b | ||
|
|
3769bc1024 | ||
|
|
e5338f28eb | ||
|
|
5cfe7fa6eb | ||
|
|
27c16a782c | ||
|
|
7c21178e1d | ||
|
|
3a6e148c11 | ||
|
|
4d9e18890a | ||
|
|
50ffaa2b55 | ||
|
|
15c8f5903b | ||
|
|
0bc6f5d56a | ||
|
|
d248524cc8 | ||
|
|
410dc152d7 | ||
|
|
423413e3a0 | ||
|
|
8896c576d7 | ||
|
|
975046da17 | ||
|
|
e4a281c3ff | ||
|
|
90729f84b6 | ||
|
|
c075a5c145 | ||
|
|
cd6d130bcb | ||
|
|
7ca2c56dad | ||
|
|
dd0ac58643 | ||
|
|
df943ec8b5 | ||
|
|
076a6d0495 | ||
|
|
02e59c906b | ||
|
|
49f91961e7 | ||
|
|
441519d71d | ||
|
|
5c75d0ce7c | ||
|
|
2efe80265d | ||
|
|
b58a64e143 | ||
|
|
ff11aec7fe | ||
|
|
f79bb9d51c | ||
|
|
3c365fc103 | ||
|
|
7b193dd737 | ||
|
|
1538596db8 | ||
|
|
9d4fc345bc | ||
|
|
08c9309572 | ||
|
|
d072aa05f1 | ||
|
|
85c1f091e2 | ||
|
|
be6a8abdf4 | ||
|
|
60bcf0c85f | ||
|
|
4a8804b8ac | ||
|
|
b014b9f638 | ||
|
|
1c633c6173 | ||
|
|
cdc95aca7b | ||
|
|
b4460999ef | ||
|
|
a713e1b56e |
@@ -97,77 +97,33 @@ class RestUtils
|
||||
* @throws Exception
|
||||
* @api
|
||||
*/
|
||||
public static function GetFieldList($sClass, $oData, $sParamName, $bFailIfNotFound = true)
|
||||
public static function GetFieldList($sClass, $oData, $sParamName)
|
||||
{
|
||||
$sFields = self::GetOptionalParam($oData, $sParamName, '*');
|
||||
return match($sFields) {
|
||||
'*' => self::GetFieldListForClass($sClass),
|
||||
'*+' => self::GetFieldListForParentClass($sClass),
|
||||
default => self::GetLimitedFieldListForClass($sClass, $sFields, $sParamName, $bFailIfNotFound),
|
||||
};
|
||||
}
|
||||
|
||||
public static function HasRequestedExtendedOutput(string $sFields): bool
|
||||
{
|
||||
return match($sFields) {
|
||||
'*' => false,
|
||||
'*+' => true,
|
||||
default => substr_count($sFields, ':') > 1,
|
||||
};
|
||||
}
|
||||
|
||||
public static function HasRequestedAllOutputFields(string $sFields): bool
|
||||
{
|
||||
return match($sFields) {
|
||||
'*', '*+' => true,
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
||||
protected static function GetFieldListForClass(string $sClass): array
|
||||
{
|
||||
return [$sClass => array_keys(MetaModel::ListAttributeDefs($sClass))];
|
||||
}
|
||||
|
||||
protected static function GetFieldListForParentClass(string $sClass): array
|
||||
{
|
||||
$aFieldList = array();
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) {
|
||||
$aFieldList = array_merge($aFieldList, self::GetFieldListForClass($sRefClass));
|
||||
}
|
||||
return $aFieldList;
|
||||
}
|
||||
|
||||
protected static function GetLimitedFieldListForSingleClass(string $sClass, string $sFields, string $sParamName, bool $bFailIfNotFound = true): array
|
||||
{
|
||||
$aFieldList = [$sClass => []];
|
||||
foreach (explode(',', $sFields) as $sAttCode) {
|
||||
$sAttCode = trim($sAttCode);
|
||||
if (($sAttCode == 'id') || (MetaModel::IsValidAttCode($sClass, $sAttCode))) {
|
||||
$aFieldList[$sClass][] = $sAttCode;
|
||||
} else {
|
||||
if ($bFailIfNotFound) {
|
||||
throw new Exception("$sParamName: invalid attribute code '$sAttCode' for class '$sClass'");
|
||||
$aShowFields = [];
|
||||
if ($sFields == '*') {
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
|
||||
$aShowFields[$sClass][] = $sAttCode;
|
||||
}
|
||||
} elseif ($sFields == '*+') {
|
||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) {
|
||||
foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef) {
|
||||
$aShowFields[$sRefClass][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aFieldList;
|
||||
}
|
||||
|
||||
protected static function GetLimitedFieldListForClass(string $sClass, string $sFields, string $sParamName, bool $bFailIfNotFound = true): array
|
||||
{
|
||||
if (!str_contains($sFields, ':')) {
|
||||
return self::GetLimitedFieldListForSingleClass($sClass, $sFields, $sParamName, $bFailIfNotFound);
|
||||
} else {
|
||||
foreach (explode(',', $sFields) as $sAttCode) {
|
||||
$sAttCode = trim($sAttCode);
|
||||
if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode))) {
|
||||
throw new Exception("$sParamName: invalid attribute code '$sAttCode'");
|
||||
}
|
||||
$aShowFields[$sClass][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
|
||||
$aFieldList = [];
|
||||
$aFieldListParts = explode(';', $sFields);
|
||||
foreach ($aFieldListParts as $sClassFields) {
|
||||
list($sSubClass, $sSubClassFields) = explode(':', $sClassFields);
|
||||
$aFieldList = array_merge($aFieldList, self::GetLimitedFieldListForSingleClass(trim($sSubClass), trim($sSubClassFields), $sParamName, $bFailIfNotFound));
|
||||
}
|
||||
return $aFieldList;
|
||||
return $aShowFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and interpret object search criteria from a Rest/Json structure
|
||||
*
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Dashboard\Layout\DashboardLayoutGrid;
|
||||
use Combodo\iTop\Application\Dashlet\DashletFactory;
|
||||
use Combodo\iTop\Application\Dashlet\Service\DashletService;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu;
|
||||
@@ -12,9 +15,12 @@ use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\DesignDocument;
|
||||
use Combodo\iTop\DesignElement;
|
||||
use Combodo\iTop\PropertyType\PropertyTypeDesign;
|
||||
use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
|
||||
/**
|
||||
@@ -24,7 +30,7 @@ require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
*/
|
||||
abstract class Dashboard
|
||||
{
|
||||
/** @var string $sTitle*/
|
||||
/** @var string $sTitle */
|
||||
protected $sTitle;
|
||||
/** @var bool $bAutoReload */
|
||||
protected $bAutoReload;
|
||||
@@ -34,7 +40,7 @@ abstract class Dashboard
|
||||
protected $sLayoutClass;
|
||||
/** @var array $aWidgetsData */
|
||||
protected $aWidgetsData;
|
||||
/** @var \DOMNode|null $oDOMNode */
|
||||
/** @var DesignElement|null $oDOMNode */
|
||||
protected $oDOMNode;
|
||||
/** @var string $sId */
|
||||
protected $sId;
|
||||
@@ -43,6 +49,11 @@ abstract class Dashboard
|
||||
/** @var \ModelReflection $oMetaModel */
|
||||
protected $oMetaModel;
|
||||
|
||||
/** @var array Array of dashlets with position */
|
||||
protected array $aGridDashlets = [];
|
||||
|
||||
protected $oDashletFactory;
|
||||
|
||||
/**
|
||||
* Dashboard constructor.
|
||||
*
|
||||
@@ -57,6 +68,7 @@ abstract class Dashboard
|
||||
$this->aCells = [];
|
||||
$this->oDOMNode = null;
|
||||
$this->sId = $sId;
|
||||
$this->oDashletFactory = DashletFactory::GetInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,7 +80,7 @@ abstract class Dashboard
|
||||
{
|
||||
$this->aCells = []; // reset the content of the dashboard
|
||||
set_error_handler(['Dashboard', 'ErrorHandler']);
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc = new PropertyTypeDesign();
|
||||
$oDoc->loadXML($sXml);
|
||||
restore_error_handler();
|
||||
$this->FromDOMDocument($oDoc);
|
||||
@@ -77,10 +89,15 @@ abstract class Dashboard
|
||||
/**
|
||||
* @param \DOMDocument $oDoc
|
||||
*/
|
||||
public function FromDOMDocument(DOMDocument $oDoc)
|
||||
public function FromDOMDocument(DesignDocument $oDoc)
|
||||
{
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
if ($this->oDOMNode->getElementsByTagName('cells')->count() === 0) {
|
||||
$this->FromDOMDocumentV2($oDoc);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0)) {
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
} else {
|
||||
@@ -121,7 +138,7 @@ abstract class Dashboard
|
||||
$aDashletOrder = [];
|
||||
/** @var \DOMElement $oDomNode */
|
||||
foreach ($oDashletList as $oDomNode) {
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank) {
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
@@ -147,7 +164,39 @@ abstract class Dashboard
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $oDomNode
|
||||
* @param \DOMDocument $oDoc
|
||||
*/
|
||||
public function FromDOMDocumentV2(DesignDocument $oDoc)
|
||||
{
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
$this->sLayoutClass = DashboardLayoutGrid::class;
|
||||
$this->sTitle = $this->oDOMNode->GetChildText('title', '');
|
||||
|
||||
$iRefresh = intval($this->oDOMNode->GetChildText('refresh', '0'));
|
||||
|
||||
$this->bAutoReload = $iRefresh > 0;
|
||||
$this->iAutoReloadSec = $iRefresh;
|
||||
|
||||
$oDashletsNode = $this->oDOMNode->GetUniqueElement('pos_dashlets');
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('pos_dashlet');
|
||||
foreach ($oDashletList as $oPosDashletNode) {
|
||||
$aGridDashlet = [];
|
||||
$aGridDashlet['position_x'] = intval($oPosDashletNode->GetChildText('position_x', '0'));
|
||||
$aGridDashlet['position_y'] = intval($oPosDashletNode->GetChildText('position_y', '0'));
|
||||
$aGridDashlet['width'] = intval($oPosDashletNode->GetChildText('width', '2'));
|
||||
$aGridDashlet['height'] = intval($oPosDashletNode->GetChildText('height', '1'));
|
||||
$oDashletNode = $oPosDashletNode->GetUniqueElement('dashlet');
|
||||
$sId = $oPosDashletNode->getAttribute('id');
|
||||
$oDashlet = $this->InitDashletFromDOMNode($oDashletNode);
|
||||
$oDashlet->SetID($sId);
|
||||
$aGridDashlet['dashlet'] = $oDashlet;
|
||||
$this->aGridDashlets[] = $aGridDashlet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DesignElement $oDomNode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -160,7 +209,7 @@ abstract class Dashboard
|
||||
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
|
||||
$sClass = static::GetDashletClassFromType($sDashletType);
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet = $this->oDashletFactory->CreateDashlet($sClass, $sId);
|
||||
$oNewDashlet->SetDashletType($sDashletType);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
|
||||
@@ -204,20 +253,33 @@ abstract class Dashboard
|
||||
*/
|
||||
public function ToXml()
|
||||
{
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
|
||||
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
|
||||
|
||||
$oMainNode = $oDoc->createElement('dashboard');
|
||||
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
$oDoc->appendChild($oMainNode);
|
||||
$oMainNode = $this->CreateEmptyDashboard();
|
||||
|
||||
$this->ToDOMNode($oMainNode);
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
$sXml = $oMainNode->ownerDocument->saveXML();
|
||||
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DesignElement
|
||||
* @throws \DOMException
|
||||
*/
|
||||
public function CreateEmptyDashboard(): DesignElement
|
||||
{
|
||||
$oDoc = new DesignDocument();
|
||||
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
|
||||
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
|
||||
|
||||
/** @var DesignElement $oMainNode */
|
||||
$oMainNode = $oDoc->createElement('dashboard');
|
||||
$oMainNode->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$oDoc->appendChild($oMainNode);
|
||||
|
||||
return $oMainNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $oDefinition
|
||||
*/
|
||||
@@ -279,7 +341,7 @@ abstract class Dashboard
|
||||
}
|
||||
$this->sTitle = $aParams['title'];
|
||||
$this->bAutoReload = $aParams['auto_reload'] == 'true';
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$aParams['auto_reload_sec']);
|
||||
|
||||
foreach ($aParams['cells'] as $aCell) {
|
||||
$aCellDashlets = [];
|
||||
@@ -287,7 +349,7 @@ abstract class Dashboard
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
/** @var \Dashlet $oNewDashlet */
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet = $this->oDashletFactory->CreateDashlet($sDashletClass, $sId);
|
||||
if (isset($aDashletParams['dashlet_type'])) {
|
||||
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
|
||||
}
|
||||
@@ -305,7 +367,11 @@ abstract class Dashboard
|
||||
|
||||
public function Save()
|
||||
{
|
||||
}
|
||||
|
||||
public function PersistDashboard(string $sXml): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,7 +569,7 @@ EOF
|
||||
{
|
||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
/** @var \DashboardLayout $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
foreach ($this->aCells as $iCellIdx => $aDashlets) {
|
||||
@@ -513,7 +579,13 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
$oDashboard = $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (count($this->aCells) > 0) {
|
||||
$aDashlets = $this->aCells;
|
||||
} else {
|
||||
$aDashlets = $this->aGridDashlets;
|
||||
}
|
||||
|
||||
$oDashboard = $oLayout->Render($oPage, $aDashlets, $bEditMode, $aExtraParams);
|
||||
$oPage->AddUiBlock($oDashboard);
|
||||
|
||||
$bFromDasboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
|
||||
@@ -603,29 +675,12 @@ JS
|
||||
* Return an array of dashlets available for selection.
|
||||
*
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
* @throws \Combodo\iTop\Application\Dashlet\DashletException
|
||||
* @throws \DOMFormatException
|
||||
*/
|
||||
protected function GetAvailableDashlets()
|
||||
protected function GetAvailableDashlets(): array
|
||||
{
|
||||
$aDashlets = [];
|
||||
|
||||
foreach (get_declared_classes() as $sDashletClass) {
|
||||
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, ['DashletUnknown', 'DashletProxy'])) {
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
$aCallSpec = [$sDashletClass, 'IsVisible'];
|
||||
$bVisible = call_user_func($aCallSpec);
|
||||
if ($bVisible) {
|
||||
$aCallSpec = [$sDashletClass, 'GetInfo'];
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = $aInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aDashlets;
|
||||
return DashletService::GetInstance()->GetAvailableDashlets();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -640,6 +695,7 @@ JS
|
||||
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
||||
}
|
||||
}
|
||||
|
||||
return $iNewId + 1;
|
||||
}
|
||||
|
||||
@@ -674,6 +730,7 @@ JS
|
||||
if (is_subclass_of($sType, 'Dashlet')) {
|
||||
return $sType;
|
||||
}
|
||||
|
||||
return 'DashletUnknown';
|
||||
}
|
||||
|
||||
@@ -726,6 +783,8 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->oMetaModel = new ModelReflectionRuntime();
|
||||
$this->oDashletFactory->SetModelReflectionRuntime($this->oMetaModel);
|
||||
ServiceLocator::GetInstance()->RegisterService('ModelReflection', $this->oMetaModel);
|
||||
$this->bCustomized = false;
|
||||
}
|
||||
|
||||
@@ -740,6 +799,7 @@ class RuntimeDashboard extends Dashboard
|
||||
|
||||
/**
|
||||
* @param bool $bCustomized
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function SetCustomFlag($bCustomized)
|
||||
@@ -764,6 +824,26 @@ class RuntimeDashboard extends Dashboard
|
||||
public function Save()
|
||||
{
|
||||
$sXml = $this->ToXml();
|
||||
|
||||
return $this->PersistDashboard($sXml);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sXml
|
||||
*
|
||||
* @return bool
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function PersistDashboard(string $sXml): bool
|
||||
{
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||
@@ -784,6 +864,7 @@ class RuntimeDashboard extends Dashboard
|
||||
utils::PushArchiveMode(false);
|
||||
$oUserDashboard->DBWrite();
|
||||
utils::PopArchiveMode();
|
||||
|
||||
return $bIsNew;
|
||||
}
|
||||
|
||||
@@ -1077,6 +1158,7 @@ JS
|
||||
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
|
||||
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
|
||||
$sActionEditId = "ibo-dashboard-menu-edit-{$sId}";
|
||||
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
|
||||
$sName = 'UI:Dashboard:Actions';
|
||||
|
||||
@@ -1090,6 +1172,21 @@ JS
|
||||
} else {
|
||||
$oToolbar = $oDashboard->GetToolbar();
|
||||
}
|
||||
|
||||
// TODO 3.3 Check if we need different action for custom dashboard creation / edition
|
||||
$oActionEditButton = ButtonUIBlockFactory::MakeIconAction(
|
||||
'fas fa-pen',
|
||||
$this->HasCustomDashboard() ? Dict::S('UI:Dashboard:EditCustom') : Dict::S('UI:Dashboard:CreateCustom'),
|
||||
$sActionEditId,
|
||||
'',
|
||||
false,
|
||||
$sActionEditId
|
||||
)
|
||||
->AddCSSClass('ibo-top-bar--toolbar-dashboard-edit-button')
|
||||
->AddCSSClass('ibo-action-button');
|
||||
|
||||
$oToolbar->AddSubBlock($oActionEditButton);
|
||||
|
||||
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId)
|
||||
->AddCSSClass('ibo-top-bar--toolbar-dashboard-menu-toggler')
|
||||
->AddCSSClass('ibo-action-button');
|
||||
@@ -1099,8 +1196,8 @@ JS
|
||||
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
if ($this->HasCustomDashboard()) {
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
// $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
// $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
$oRevert = new JSPopupMenuItem(
|
||||
'UI:Dashboard:RevertConfirm',
|
||||
Dict::S('UI:Dashboard:DeleteCustom'),
|
||||
@@ -1108,8 +1205,8 @@ JS
|
||||
);
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
} else {
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
// $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
// $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
}
|
||||
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
@@ -1223,7 +1320,7 @@ EOF
|
||||
$sId = json_encode($this->sId);
|
||||
$sLayoutClass = json_encode($this->sLayoutClass);
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sAutoReloadSec = (string)$this->iAutoReloadSec;
|
||||
$sTitle = json_encode($this->sTitle);
|
||||
$sFile = json_encode($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
@@ -1395,19 +1492,11 @@ JS
|
||||
|
||||
// Get the list of possible dashlets that support a creation from
|
||||
// an OQL
|
||||
$aAllDashlets = DashletService::GetInstance()->GetAvailableDashlets();
|
||||
$aDashlets = [];
|
||||
foreach (get_declared_classes() as $sDashletClass) {
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet')) {
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
$aCallSpec = [$sDashletClass, 'CanCreateFromOQL'];
|
||||
$bShorcutMode = call_user_func($aCallSpec);
|
||||
if ($bShorcutMode) {
|
||||
$aCallSpec = [$sDashletClass, 'GetInfo'];
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']];
|
||||
}
|
||||
}
|
||||
foreach ($aAllDashlets as $sDashletClass => $aInfo) {
|
||||
if ($aInfo['can_create_by_oql']) {
|
||||
$aDashlets[$sDashletClass] = ['label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1417,7 +1506,7 @@ JS
|
||||
$oSubForm = new DesignerForm();
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
/** @var \Dashlet $oDashlet */
|
||||
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
||||
$oDashlet = DashletFactory::GetInstance()->CreateDashlet($sDashletClass, 0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
||||
@@ -1571,7 +1660,7 @@ JS
|
||||
*/
|
||||
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)
|
||||
{
|
||||
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
|
||||
$bIsDashletWithListPref = ($oDashlet instanceof DashletObjectList);
|
||||
if (!$bIsDashletWithListPref) {
|
||||
return;
|
||||
}
|
||||
@@ -1619,6 +1708,7 @@ JS
|
||||
//on error, return default value
|
||||
return null;
|
||||
}
|
||||
|
||||
return DataTableSettings::GetAppUserPreferenceKey($aClassAliases, $sDataTableId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use Combodo\iTop\Application\WebPage\WebPage;
|
||||
*/
|
||||
abstract class DashboardLayout
|
||||
{
|
||||
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
|
||||
abstract public function Render($oPage, $aDashlets, $bEditMode = false, array $aExtraParams = []);
|
||||
|
||||
/**
|
||||
* @param int $iCellIdx
|
||||
@@ -43,8 +43,8 @@ abstract class DashboardLayout
|
||||
public static function GetInfo()
|
||||
{
|
||||
return [
|
||||
'label' => '',
|
||||
'icon' => '',
|
||||
'label' => '',
|
||||
'icon' => '',
|
||||
'description' => '',
|
||||
];
|
||||
}
|
||||
@@ -74,6 +74,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
|
||||
return $aDashlets;
|
||||
}
|
||||
|
||||
@@ -94,6 +95,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
|
||||
return $aCells;
|
||||
|
||||
}
|
||||
@@ -109,7 +111,8 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
$aCells = $this->TrimCellsArray($aCells);
|
||||
|
||||
$oDashboardLayout = new DashboardLayoutUIBlock();
|
||||
// TODO 3.3 Handle dashboard new format, convert old format if needed
|
||||
$oDashboardLayout = new DashboardLayoutUIBlock($aExtraParams['dashboard_div_id']);
|
||||
//$oPage->AddUiBlock($oDashboardLayout);
|
||||
|
||||
$iCellIdx = 0;
|
||||
@@ -117,15 +120,16 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
|
||||
//Js given by each dashlet to reload
|
||||
$sJSReload = "";
|
||||
|
||||
$oDashboardGrid = new \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardGrid();
|
||||
$oDashboardLayout->SetGrid($oDashboardGrid);
|
||||
for ($iRows = 0; $iRows < $iNbRows; $iRows++) {
|
||||
$oDashboardRow = new DashboardRow();
|
||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
//$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
|
||||
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
|
||||
$oDashboardColumn = new DashboardColumn($bEditMode);
|
||||
$oDashboardColumn->SetCellIndex($iCellIdx);
|
||||
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
|
||||
//$oDashboardRow->AddDashboardColumn($oDashboardColumn);
|
||||
|
||||
if (array_key_exists($iCellIdx, $aCells)) {
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
@@ -133,6 +137,18 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach ($aDashlets as $oDashlet) {
|
||||
if ($oDashlet::IsVisible()) {
|
||||
$sDashletId = $oDashlet->GetID();
|
||||
$sDashletClass = get_class($oDashlet);
|
||||
$aDashletDenormalizedProperties = $oDashlet->GetDenormalizedProperties();
|
||||
// $aDashletsInfo = $sDashletClass::GetInfo();
|
||||
//
|
||||
// // TODO 3.3 Gather real position and height/width if any.
|
||||
// // Also set minimal height/width
|
||||
// $iPositionX = null;
|
||||
// $iPositionY = null;
|
||||
// $iWidth = array_key_exists('preferred_width', $aDashletsInfo) ? $aDashletsInfo['preferred_width'] : 1;
|
||||
// $iHeight = array_key_exists('preferred_height', $aDashletsInfo) ? $aDashletsInfo['preferred_height'] : 1;
|
||||
// $oDashboardGrid->AddDashlet($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams), $sDashletId, $sDashletClass, $aDashletDenormalizedProperties, $iPositionX, $iPositionY, $iWidth, $iHeight);
|
||||
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
|
||||
}
|
||||
}
|
||||
@@ -147,6 +163,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$sJSReload .= $oDashboardRow->GetJSRefreshCallback()." ";
|
||||
}
|
||||
|
||||
// TODO 3.3 We can probably do better with the new dashboard
|
||||
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
|
||||
|
||||
if ($bEditMode) { // Add one row for extensibility
|
||||
@@ -168,8 +185,8 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
*/
|
||||
public function GetDashletCoordinates($iCellIdx)
|
||||
{
|
||||
$iColNumber = (int) $iCellIdx % $this->iNbCols;
|
||||
$iRowNumber = (int) floor($iCellIdx / $this->iNbCols);
|
||||
$iColNumber = (int)$iCellIdx % $this->iNbCols;
|
||||
$iRowNumber = (int)floor($iCellIdx / $this->iNbCols);
|
||||
|
||||
return [$iColNumber, $iRowNumber];
|
||||
}
|
||||
@@ -182,11 +199,12 @@ class DashboardLayoutOneCol extends DashboardLayoutMultiCol
|
||||
parent::__construct();
|
||||
$this->iNbCols = 1;
|
||||
}
|
||||
|
||||
public static function GetInfo()
|
||||
{
|
||||
return [
|
||||
'label' => 'One Column',
|
||||
'icon' => 'images/layout_1col.png',
|
||||
'label' => 'One Column',
|
||||
'icon' => 'images/layout_1col.png',
|
||||
'description' => '',
|
||||
];
|
||||
}
|
||||
@@ -199,11 +217,12 @@ class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
|
||||
parent::__construct();
|
||||
$this->iNbCols = 2;
|
||||
}
|
||||
|
||||
public static function GetInfo()
|
||||
{
|
||||
return [
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_2col.png',
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_2col.png',
|
||||
'description' => '',
|
||||
];
|
||||
}
|
||||
@@ -216,11 +235,12 @@ class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
|
||||
parent::__construct();
|
||||
$this->iNbCols = 3;
|
||||
}
|
||||
|
||||
public static function GetInfo()
|
||||
{
|
||||
return [
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_3col.png',
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_3col.png',
|
||||
'description' => '',
|
||||
];
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
<class id="AbstractResource" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */</comment>
|
||||
<comment>/* Resource access control abstraction. Can be inherited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */</comment>
|
||||
<abstract>true</abstract>
|
||||
</properties>
|
||||
<presentation/>
|
||||
@@ -851,9 +851,295 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
|
||||
</methods>
|
||||
</class>
|
||||
</classes>
|
||||
<dashlets>
|
||||
<dashlet id="DashletGroupByTable" _delta="define">
|
||||
<label>UI:DashletGroupByTable:Label</label>
|
||||
<icon>images/dashlets/icons8-transaction-list-48.png</icon>
|
||||
<description>UI:DashletGroupByTable:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>2</min_height>
|
||||
<preferred_width>3</preferred_width>
|
||||
<preferred_height>3</preferred_height>
|
||||
<can_create_by_oql>true</can_create_by_oql>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletGroupByBars" _delta="define">
|
||||
<label>UI:DashletGroupByBars:Label</label>
|
||||
<icon>images/dashlets/icons8-bar-chart-48.png</icon>
|
||||
<description>UI:DashletGroupByBars:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>2</min_height>
|
||||
<preferred_width>3</preferred_width>
|
||||
<preferred_height>3</preferred_height>
|
||||
<can_create_by_oql>true</can_create_by_oql>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletGroupByPie" _delta="define">
|
||||
<label>UI:DashletGroupByPie:Label</label>
|
||||
<icon>images/dashlets/icons8-pie-chart-48.png</icon>
|
||||
<description>UI:DashletGroupByPie:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>2</min_height>
|
||||
<preferred_width>3</preferred_width>
|
||||
<preferred_height>3</preferred_height>
|
||||
<can_create_by_oql>true</can_create_by_oql>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletBadge" _delta="define">
|
||||
<label>UI:DashletBadge:Label</label>
|
||||
<icon>images/dashlets/icons8-badge-48.png</icon>
|
||||
<description>UI:DashletBadge:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>1</min_height>
|
||||
<preferred_width>2</preferred_width>
|
||||
<preferred_height>1</preferred_height>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletHeaderDynamic" _delta="define">
|
||||
<label>UI:DashletHeaderDynamic:Label</label>
|
||||
<icon>images/dashlets/icons8-header-altered-48.png</icon>
|
||||
<description>UI:DashletHeaderDynamic:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>1</min_height>
|
||||
<preferred_width>4</preferred_width>
|
||||
<preferred_height>3</preferred_height>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletHeaderStatic" _delta="define">
|
||||
<label>UI:DashletHeaderStatic:Label</label>
|
||||
<icon>images/dashlets/icons8-header-48.png</icon>
|
||||
<description>UI:DashletHeaderStatic:Description</description>
|
||||
<min_width>4</min_width>
|
||||
<min_height>1</min_height>
|
||||
<preferred_width>4</preferred_width>
|
||||
<preferred_height>1</preferred_height>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletObjectList" _delta="define">
|
||||
<label>UI:DashletObjectList:Label</label>
|
||||
<icon>images/dashlets/icons8-list-48.png</icon>
|
||||
<description>UI:DashletObjectList:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>1</min_height>
|
||||
<preferred_width>4</preferred_width>
|
||||
<preferred_height>3</preferred_height>
|
||||
<can_create_by_oql>true</can_create_by_oql>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
<dashlet id="DashletPlainText" _delta="define">
|
||||
<label>UI:DashletPlainText:Label</label>
|
||||
<icon>images/dashlets/icons8-text-box-48.png</icon>
|
||||
<description>UI:DashletPlainText:Description</description>
|
||||
<min_width>2</min_width>
|
||||
<min_height>1</min_height>
|
||||
<preferred_width>2</preferred_width>
|
||||
<preferred_height>1</preferred_height>
|
||||
<configuration/>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
<property_types _delta="define">
|
||||
<property_type id="Dashboard" xsi:type="Combodo-AbstractPropertyType"/>
|
||||
<property_type id="DashboardGrid" xsi:type="Combodo-PropertyType">
|
||||
<extends>Dashboard</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<label>Dashboard</label>
|
||||
<nodes>
|
||||
<node id="title" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:DashboardEdit:DashboardTitle</label>
|
||||
</node>
|
||||
<node id="refresh" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
|
||||
<label>UI:DashboardEdit:AutoReload</label>
|
||||
<values>
|
||||
<value id="0">
|
||||
<label>No auto-refresh</label>
|
||||
</value>
|
||||
<value id="30">
|
||||
<label>Every 30 seconds</label>
|
||||
</value>
|
||||
<value id="60">
|
||||
<label>Every 1 minute</label>
|
||||
</value>
|
||||
<value id="300">
|
||||
<label>Every 5 minutes</label>
|
||||
</value>
|
||||
<value id="600">
|
||||
<label>Every 10 minutes</label>
|
||||
</value>
|
||||
<value id="1800">
|
||||
<label>Every 30 minutes</label>
|
||||
</value>
|
||||
<value id="3600">
|
||||
<label>Every 1 hour</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
<node id="pos_dashlets" xsi:type="Combodo-ValueType-Collection">
|
||||
<label>Dashlet List</label>
|
||||
<xml-format xsi:type="Combodo-XMLFormat-CollectionWithId">
|
||||
<tag-name>pos_dashlet</tag-name>
|
||||
</xml-format>
|
||||
<prototype>
|
||||
<node id="position_x" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>X</label>
|
||||
</node>
|
||||
<node id="position_y" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>Y</label>
|
||||
</node>
|
||||
<node id="width" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>W</label>
|
||||
</node>
|
||||
<node id="height" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>H</label>
|
||||
</node>
|
||||
<node id="dashlet" xsi:type="Combodo-ValueType-Polymorphic">
|
||||
<label>Dashlet</label>
|
||||
<allowed-types>
|
||||
<allowed-type>Dashlet</allowed-type>
|
||||
</allowed-types>
|
||||
</node>
|
||||
</prototype>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
<property_type id="Dashlet" xsi:type="Combodo-AbstractPropertyType"/>
|
||||
<property_type id="DashletGroupBy" xsi:type="Combodo-PropertyType">
|
||||
<property_type id="DashletGroupByTable" xsi:type="Combodo-PropertyType">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<label>UI:DashletGroupBy:Title</label>
|
||||
<nodes>
|
||||
<node id="title" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:DashletGroupBy:Prop-Title</label>
|
||||
</node>
|
||||
<node id="query" xsi:type="Combodo-ValueType-OQL">
|
||||
<label>UI:DashletGroupBy:Prop-Query</label>
|
||||
</node>
|
||||
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
|
||||
<label>UI:DashletGroupBy:Prop-GroupBy</label>
|
||||
<class>{{query.selected_class}}</class>
|
||||
</node>
|
||||
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
|
||||
<label>UI:DashletGroupBy:Prop-Style</label>
|
||||
<values>
|
||||
<value id="bars">
|
||||
<label>UI:DashletGroupByBars:Label</label>
|
||||
</value>
|
||||
<value id="pie">
|
||||
<label>UI:DashletGroupByPie:Label</label>
|
||||
</value>
|
||||
<value id="table">
|
||||
<label>UI:DashletGroupByTable:Label</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
|
||||
<label>UI:DashletGroupBy:Prop-Function</label>
|
||||
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
|
||||
</node>
|
||||
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
|
||||
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
|
||||
<class>{{query.selected_class}}</class>
|
||||
<category>numeric</category>
|
||||
</node>
|
||||
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
|
||||
<label>UI:DashletGroupBy:Prop-OrderField</label>
|
||||
<values>
|
||||
<value id="attribute">
|
||||
<label>{{aggregation_attribute.label}}</label>
|
||||
</value>
|
||||
<value id="function">
|
||||
<label>{{aggregation_function.label}}</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
<node id="limit" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>UI:DashletGroupBy:Prop-Limit</label>
|
||||
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
|
||||
</node>
|
||||
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
|
||||
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
|
||||
<values>
|
||||
<value id="asc">
|
||||
<label>UI:DashletGroupBy:Order:asc</label>
|
||||
</value>
|
||||
<value id="desc">
|
||||
<label>UI:DashletGroupBy:Order:desc</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
<property_type id="DashletGroupByBars" xsi:type="Combodo-PropertyType">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<label>UI:DashletGroupBy:Title</label>
|
||||
<nodes>
|
||||
<node id="title" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:DashletGroupBy:Prop-Title</label>
|
||||
</node>
|
||||
<node id="query" xsi:type="Combodo-ValueType-OQL">
|
||||
<label>UI:DashletGroupBy:Prop-Query</label>
|
||||
</node>
|
||||
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
|
||||
<label>UI:DashletGroupBy:Prop-GroupBy</label>
|
||||
<class>{{query.selected_class}}</class>
|
||||
</node>
|
||||
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
|
||||
<label>UI:DashletGroupBy:Prop-Style</label>
|
||||
<values>
|
||||
<value id="bars">
|
||||
<label>UI:DashletGroupByBars:Label</label>
|
||||
</value>
|
||||
<value id="pie">
|
||||
<label>UI:DashletGroupByPie:Label</label>
|
||||
</value>
|
||||
<value id="table">
|
||||
<label>UI:DashletGroupByTable:Label</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
|
||||
<label>UI:DashletGroupBy:Prop-Function</label>
|
||||
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
|
||||
</node>
|
||||
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
|
||||
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
|
||||
<class>{{query.selected_class}}</class>
|
||||
<category>numeric</category>
|
||||
</node>
|
||||
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
|
||||
<label>UI:DashletGroupBy:Prop-OrderField</label>
|
||||
<values>
|
||||
<value id="attribute">
|
||||
<label>{{aggregation_attribute.label}}</label>
|
||||
</value>
|
||||
<value id="function">
|
||||
<label>{{aggregation_function.label}}</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
<node id="limit" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>UI:DashletGroupBy:Prop-Limit</label>
|
||||
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
|
||||
</node>
|
||||
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
|
||||
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
|
||||
<values>
|
||||
<value id="asc">
|
||||
<label>UI:DashletGroupBy:Order:asc</label>
|
||||
</value>
|
||||
<value id="desc">
|
||||
<label>UI:DashletGroupBy:Order:desc</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
<property_type id="DashletGroupByPie" xsi:type="Combodo-PropertyType">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<label>UI:DashletGroupBy:Title</label>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
@@ -1279,13 +1280,14 @@ class DashboardMenuNode extends MenuNode
|
||||
if ($oDashboard != null) {
|
||||
WebResourcesHelper::EnableC3JSToWebPage($oPage);
|
||||
|
||||
// TODO 3.3 this works for dashboard menu, what about other places ?
|
||||
$oPageLayout = PageContentFactory::MakeForDashboard();
|
||||
$oPage->SetContentLayout($oPageLayout, $oPage);
|
||||
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
|
||||
$oPage->add('<div id="'.$sDivId.'" class="ibo-dashboard" data-role="ibo-dashboard">');
|
||||
$aExtraParams['dashboard_div_id'] = $sDivId;
|
||||
$aExtraParams['from_dashboard_page'] = true;
|
||||
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$bEdit = utils::ReadParam('edit', false);
|
||||
if ($bEdit) {
|
||||
|
||||
@@ -1954,6 +1954,11 @@ class Config
|
||||
*/
|
||||
protected $m_sDefaultLanguage;
|
||||
|
||||
/**
|
||||
* @var string Type of login process allowed: form|basic|url|external
|
||||
*/
|
||||
protected $m_sAllowedLoginTypes;
|
||||
|
||||
/**
|
||||
* @var string Name of the PHP variable in which external authentication information is passed by the web server
|
||||
*/
|
||||
@@ -2027,6 +2032,7 @@ class Config
|
||||
$this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL;
|
||||
$this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED;
|
||||
$this->m_sDefaultLanguage = 'EN US';
|
||||
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
|
||||
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
|
||||
$this->m_aCharsets = [];
|
||||
$this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED;
|
||||
@@ -2173,6 +2179,7 @@ class Config
|
||||
$this->m_aModuleSettings = isset($MyModuleSettings) ? $MyModuleSettings : [];
|
||||
|
||||
$this->m_sDefaultLanguage = isset($MySettings['default_language']) ? trim($MySettings['default_language']) : 'EN US';
|
||||
$this->m_sAllowedLoginTypes = isset($MySettings['allowed_login_types']) ? trim($MySettings['allowed_login_types']) : DEFAULT_ALLOWED_LOGIN_TYPES;
|
||||
$this->m_sExtAuthVariable = isset($MySettings['ext_auth_variable']) ? trim($MySettings['ext_auth_variable']) : DEFAULT_EXT_AUTH_VARIABLE;
|
||||
$this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : $this->m_sEncryptionKey;
|
||||
$this->m_sEncryptionLibrary = isset($MySettings['encryption_library']) ? trim($MySettings['encryption_library']) : $this->m_sEncryptionLibrary;
|
||||
@@ -2332,7 +2339,7 @@ class Config
|
||||
|
||||
public function GetAllowedLoginTypes()
|
||||
{
|
||||
return explode('|', $this->m_aSettings['allowed_login_types']['value']);
|
||||
return explode('|', $this->m_sAllowedLoginTypes);
|
||||
}
|
||||
|
||||
public function GetExternalAuthenticationVariable()
|
||||
@@ -2410,6 +2417,7 @@ class Config
|
||||
|
||||
public function SetAllowedLoginTypes($aAllowedLoginTypes)
|
||||
{
|
||||
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
|
||||
$this->Set('allowed_login_types', implode('|', $aAllowedLoginTypes));
|
||||
}
|
||||
|
||||
@@ -2487,6 +2495,7 @@ class Config
|
||||
$aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval;
|
||||
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
|
||||
$aSettings['default_language'] = $this->m_sDefaultLanguage;
|
||||
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
|
||||
$aSettings['ext_auth_variable'] = $this->m_sExtAuthVariable;
|
||||
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
|
||||
$aSettings['encryption_library'] = $this->m_sEncryptionLibrary;
|
||||
@@ -2590,6 +2599,7 @@ class Config
|
||||
// Old fashioned remaining values
|
||||
$aOtherValues = [
|
||||
'default_language' => $this->m_sDefaultLanguage,
|
||||
'allowed_login_types' => $this->m_sAllowedLoginTypes,
|
||||
'ext_auth_variable' => $this->m_sExtAuthVariable,
|
||||
'encryption_key' => $this->m_sEncryptionKey,
|
||||
'encryption_library' => $this->m_sEncryptionLibrary,
|
||||
|
||||
@@ -389,7 +389,7 @@ JS
|
||||
* Resize an image so that it fits the maximum width/height defined in the config file
|
||||
* @param ormDocument $oImage The original image stored as an array (content / mimetype / filename)
|
||||
* @return ormDocument The resampled image (or the original one if it already fit)
|
||||
* @deprecated since 3.3.0 Replaced by ormDocument::ResizeImageToFit
|
||||
* @deprecated Replaced by ormDocument::ResizeImageToFit
|
||||
*/
|
||||
public static function ResizeImageToFit(ormDocument $oImage, &$aDimensions = null)
|
||||
{
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\EventRegister\ApplicationEvents;
|
||||
use Combodo\iTop\Core\Kpi\KpiLogData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
use Combodo\iTop\Service\Events\iEventServiceSetup;
|
||||
use Combodo\iTop\Service\Module\ModuleService;
|
||||
|
||||
/**
|
||||
* Measures operations duration, memory usage, etc. (and some other KPIs)
|
||||
*/
|
||||
class ExecutionKPI implements iEventServiceSetup
|
||||
|
||||
class ExecutionKPI
|
||||
{
|
||||
protected static $m_bEnabled_Duration = false;
|
||||
protected static $m_bEnabled_Memory = false;
|
||||
@@ -25,18 +23,15 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
|
||||
protected static $m_aStats = []; // Recurrent operations
|
||||
protected static $m_aExecData = []; // One shot operations
|
||||
/** @var true */
|
||||
private static bool $bMetamodelStarted = false;
|
||||
/**
|
||||
* @var array[ExecutionKPI]
|
||||
*/
|
||||
protected static $m_aExecutionStack = []; // embedded execution stats
|
||||
|
||||
private static ?float $fLastReportTime = null;
|
||||
private static ?float $iLastReportMemory = null;
|
||||
|
||||
// For stats
|
||||
protected $m_fStarted = null;
|
||||
protected $m_fChildrenDuration = 0; // Count embedded
|
||||
protected $m_iInitialMemory = null;
|
||||
|
||||
private static array $aBootstrapOperations = [];
|
||||
|
||||
public static function EnableDuration($iLevel)
|
||||
{
|
||||
if ($iLevel > 0) {
|
||||
@@ -76,7 +71,6 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -103,7 +97,7 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
|
||||
$sSlowQueries = '';
|
||||
if (self::$m_fSlowQueries > 0) {
|
||||
$sSlowQueries = '. Slow Queries: '.self::$m_fSlowQueries.'s';
|
||||
$sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s";
|
||||
}
|
||||
|
||||
$aExtensions = [];
|
||||
@@ -133,7 +127,7 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$sRequest .= ' operation: '.$_POST['operation'];
|
||||
}
|
||||
|
||||
$fStop = microtime(true);
|
||||
$fStop = MyHelpers::getmicrotime();
|
||||
if (($fStop - $fItopStarted) > self::$m_fSlowQueries) {
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
@@ -157,17 +151,17 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
|
||||
$sTableStyle = 'background-color: #ccc; margin: 10px;';
|
||||
|
||||
$sHtml = '<hr/>';
|
||||
$sHtml = "<hr/>";
|
||||
$sHtml .= "<div style=\"background-color: grey; padding: 10px;\">";
|
||||
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>";
|
||||
$oStarted = DateTime::createFromFormat('U.u', $fItopStarted);
|
||||
$sHtml .= '<p>'.$oStarted->format('Y-m-d H:i:s.u').'</p>';
|
||||
$sHtml .= '<p>log_kpi_user_id: '.UserRights::GetUserId().'</p>';
|
||||
$sHtml .= '<div>';
|
||||
$sHtml .= "<p>log_kpi_user_id: ".UserRights::GetUserId()."</p>";
|
||||
$sHtml .= "<div>";
|
||||
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
|
||||
$sHtml .= '<thead>';
|
||||
$sHtml .= ' <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>';
|
||||
$sHtml .= '</thead>';
|
||||
$sHtml .= "<thead>";
|
||||
$sHtml .= " <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>";
|
||||
$sHtml .= "</thead>";
|
||||
foreach (self::$m_aExecData as $aOpStats) {
|
||||
$sOperation = $aOpStats['op'];
|
||||
$sBegin = round($aOpStats['time_begin'], 3);
|
||||
@@ -186,12 +180,12 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
}
|
||||
}
|
||||
|
||||
$sHtml .= '<tr>';
|
||||
$sHtml .= "<tr>";
|
||||
$sHtml .= " <td>$sOperation</td><td>$sBegin</td><td>$sEnd</td><td>$sDuration</td><td>$sMemBegin</td><td>$sMemEnd</td><td>$sMemPeak</td>";
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= "</tr>";
|
||||
}
|
||||
$sHtml .= '</table>';
|
||||
$sHtml .= '</div>';
|
||||
$sHtml .= "</table>";
|
||||
$sHtml .= "</div>";
|
||||
|
||||
$aConsolidatedStats = [];
|
||||
foreach (self::$m_aStats as $sOperation => $aOpStats) {
|
||||
@@ -214,20 +208,20 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
}
|
||||
}
|
||||
$aConsolidatedStats[$sOperation] = [
|
||||
'count' => $iTotalOp,
|
||||
'count' => $iTotalOp,
|
||||
'duration' => $fTotalOp,
|
||||
'min' => $fMinOp,
|
||||
'max' => $fMaxOp,
|
||||
'avg' => $fTotalOp / $iTotalOp,
|
||||
'min' => $fMinOp,
|
||||
'max' => $fMaxOp,
|
||||
'avg' => $fTotalOp / $iTotalOp,
|
||||
'max_args' => $sMaxOpArguments,
|
||||
];
|
||||
}
|
||||
|
||||
$sHtml .= '<div>';
|
||||
$sHtml .= "<div>";
|
||||
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
|
||||
$sHtml .= '<thead>';
|
||||
$sHtml .= ' <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>';
|
||||
$sHtml .= '</thead>';
|
||||
$sHtml .= "<thead>";
|
||||
$sHtml .= " <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>";
|
||||
$sHtml .= "</thead>";
|
||||
foreach ($aConsolidatedStats as $sOperation => $aOpStats) {
|
||||
$sOperation = '<a href="#'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
$sCount = $aOpStats['count'];
|
||||
@@ -236,14 +230,14 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$sMax = '<a href="#'.md5($sExecId.$aOpStats['max_args']).'">'.round($aOpStats['max'], 3).'</a>';
|
||||
$sAvg = round($aOpStats['avg'], 3);
|
||||
|
||||
$sHtml .= '<tr>';
|
||||
$sHtml .= "<tr>";
|
||||
$sHtml .= " <td>$sOperation</td><td>$sCount</td><td>$sDuration</td><td>$sMin</td><td>$sMax</td><td>$sAvg</td>";
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= "</tr>";
|
||||
}
|
||||
$sHtml .= '</table>';
|
||||
$sHtml .= '</div>';
|
||||
$sHtml .= "</table>";
|
||||
$sHtml .= "</div>";
|
||||
|
||||
$sHtml .= '</div>';
|
||||
$sHtml .= "</div>";
|
||||
|
||||
$sHtml .= "<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>";
|
||||
|
||||
@@ -293,18 +287,18 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
$sHtml .= "<h4>$sOperationHtml</h4>";
|
||||
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
|
||||
$sHtml .= '<thead>';
|
||||
$sHtml .= ' <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>';
|
||||
$sHtml .= '</thead>';
|
||||
$sHtml .= "<thead>";
|
||||
$sHtml .= " <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>";
|
||||
$sHtml .= "</thead>";
|
||||
$bDisplayHeader = false;
|
||||
}
|
||||
$sHtml .= '<tr>';
|
||||
$sHtml .= "<tr>";
|
||||
$sHtml .= " <td>$sHtmlArguments</td><td>$iCountInter</td><td>$sTotalInter</td><td>$sMinInter</td><td>$sMaxInter</td>";
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= "</tr>";
|
||||
}
|
||||
}
|
||||
if (!$bDisplayHeader) {
|
||||
$sHtml .= '</table>';
|
||||
$sHtml .= "</table>";
|
||||
$sHtml .= "<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>";
|
||||
}
|
||||
self::Report($sHtml);
|
||||
@@ -339,50 +333,39 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
|
||||
$aNewEntry = null;
|
||||
|
||||
if (is_null(static::$fLastReportTime)) {
|
||||
static::$fLastReportTime = $fItopStarted;
|
||||
}
|
||||
|
||||
if (is_null(static::$iLastReportMemory)) {
|
||||
global $iItopInitialMemory;
|
||||
static::$iLastReportMemory = $iItopInitialMemory;
|
||||
}
|
||||
|
||||
$fStarted = static::$fLastReportTime;
|
||||
$fStopped = microtime(true);
|
||||
$fStarted = $this->m_fStarted;
|
||||
$fStopped = $this->m_fStarted;
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$aNewEntry = [
|
||||
'op' => $sOperationDesc,
|
||||
'time_begin' => $fStarted - $fItopStarted,
|
||||
'time_begin' => $this->m_fStarted - $fItopStarted,
|
||||
'time_end' => $fStopped - $fItopStarted,
|
||||
];
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_fStarted = $fStopped;
|
||||
}
|
||||
static::$fLastReportTime = $fStopped;
|
||||
|
||||
$iInitialMemory = static::$iLastReportMemory;
|
||||
$iCurrentMemory = $iInitialMemory;
|
||||
$iPeakMemory = $iInitialMemory;
|
||||
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
|
||||
$iCurrentMemory = 0;
|
||||
$iPeakMemory = 0;
|
||||
if (self::$m_bEnabled_Memory) {
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
if (is_null($aNewEntry)) {
|
||||
$aNewEntry = ['op' => $sOperationDesc];
|
||||
}
|
||||
$aNewEntry['mem_begin'] = $iInitialMemory;
|
||||
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
|
||||
$aNewEntry['mem_end'] = $iCurrentMemory;
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
$aNewEntry['mem_peak'] = $iPeakMemory;
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
static::$iLastReportMemory = $iCurrentMemory;
|
||||
$this->m_iInitialMemory = $iCurrentMemory;
|
||||
}
|
||||
|
||||
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) {
|
||||
$aCallstack = ['callstack' => $this->GetCallStack()];
|
||||
if (static::$bMetamodelStarted) {
|
||||
foreach (static::$aBootstrapOperations as $oLog) {
|
||||
$this->LogOperation($oLog);
|
||||
}
|
||||
static::$aBootstrapOperations = [];
|
||||
// Invoke extensions to log the KPI operation
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_REPORT,
|
||||
@@ -393,24 +376,9 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$sExtension,
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory,
|
||||
$aCallstack
|
||||
$iPeakMemory
|
||||
);
|
||||
$this->LogOperation($oKPILogData);
|
||||
} else {
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_REPORT,
|
||||
'Step',
|
||||
$sOperationDesc,
|
||||
$fStarted,
|
||||
$fStopped,
|
||||
'',
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory,
|
||||
$aCallstack
|
||||
);
|
||||
static::$aBootstrapOperations[] = $oKPILogData;
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,21 +388,13 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$this->ResetCounters();
|
||||
}
|
||||
|
||||
private function LogOperation(KpiLogData $oKPILogData): void
|
||||
{
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute statistics for a call to an extension
|
||||
* Note: not working in dev mode (with links to env-production)
|
||||
*
|
||||
* @param object|string $object object called
|
||||
* @param string $sMethod method called on the object
|
||||
* @param string $sMessage additional message
|
||||
* @param string $sMethod method called on the object
|
||||
* @param string $sMessage additional message
|
||||
*
|
||||
* @return bool true if an extension was found for this object::method
|
||||
* @throws \ReflectionException
|
||||
@@ -463,23 +423,21 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
|
||||
$fDuration = 0;
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStopped = microtime(true);
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$fDuration = $fStopped - $this->m_fStarted;
|
||||
$aCallstack = [];
|
||||
if (self::$m_bGenerateLegacyReport) {
|
||||
if (self::$m_bBlameCaller) {
|
||||
$aCallstack = MyHelpers::get_callstack(1);
|
||||
self::$m_aStats[$sOperation][$sArguments][] = [
|
||||
'time' => $fDuration,
|
||||
'callers' => $aCallstack,
|
||||
'time' => $fDuration,
|
||||
'callers' => $aCallstack,
|
||||
];
|
||||
} else {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = [
|
||||
'time' => $fDuration,
|
||||
'time' => $fDuration,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$aCallstack = ['callstack' => $this->GetCallStack()];
|
||||
}
|
||||
|
||||
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
|
||||
@@ -490,45 +448,33 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
}
|
||||
|
||||
if (static::$bMetamodelStarted) {
|
||||
foreach (static::$aBootstrapOperations as $oLog) {
|
||||
$this->LogOperation($oLog);
|
||||
}
|
||||
static::$aBootstrapOperations = [];
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
//$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
|
||||
$sExtension = '';
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_STATS,
|
||||
$sOperation,
|
||||
$sArguments,
|
||||
$this->m_fStarted,
|
||||
$fStopped,
|
||||
'',
|
||||
$sExtension,
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory,
|
||||
$aCallstack
|
||||
);
|
||||
$this->LogOperation($oKPILogData);
|
||||
} else {
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_STATS,
|
||||
$sOperation,
|
||||
$sArguments,
|
||||
$this->m_fStarted,
|
||||
$fStopped,
|
||||
'',
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory,
|
||||
$aCallstack
|
||||
);
|
||||
static::$aBootstrapOperations[] = $oKPILogData;
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function ResetCounters()
|
||||
{
|
||||
$this->m_fStarted = microtime(true);
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$this->m_fStarted = microtime(true);
|
||||
}
|
||||
|
||||
if (self::$m_bEnabled_Memory) {
|
||||
$this->m_iInitialMemory = self::memory_get_usage();
|
||||
@@ -557,33 +503,7 @@ class ExecutionKPI implements iEventServiceSetup
|
||||
if (function_exists('memory_get_peak_usage')) {
|
||||
return memory_get_peak_usage($bRealUsage);
|
||||
}
|
||||
|
||||
// PHP > 5.2.1 - this verb depends on a compilation option
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ModuleHandlerApiInterface methods
|
||||
*/
|
||||
|
||||
public static function OnMetaModelStarted()
|
||||
{
|
||||
static::$bMetamodelStarted = true;
|
||||
}
|
||||
|
||||
public function RegisterEventsAndListeners()
|
||||
{
|
||||
EventService::RegisterListener(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED, [$this, 'OnMetaModelStarted']);
|
||||
}
|
||||
|
||||
private function GetCallStack(): string
|
||||
{
|
||||
$aCallStack = MyHelpers::get_callstack(2);
|
||||
$sCallStack = "Call stack:\n";
|
||||
foreach ($aCallStack as $index => $aLine) {
|
||||
$sCallStack .= "#$index ".$aLine['File'].'('.$aLine['Line'].'): '.$aLine['Function']."\n";
|
||||
}
|
||||
|
||||
return $sCallStack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,9 +89,17 @@ abstract class ModelReflection
|
||||
* @param string $defaultValue
|
||||
*
|
||||
* @return \RunTimeIconSelectionField
|
||||
* @deprecated since 3.3.0 replaced by GetAvailableIcons
|
||||
*/
|
||||
abstract public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '');
|
||||
|
||||
/**
|
||||
* Find available icons for the current context
|
||||
*
|
||||
* @return array of ['value', 'label', 'icon'] where 'value' is the relative path on disk, 'label' the name to display and 'icon' is the URL to get the image
|
||||
*/
|
||||
abstract public function GetAvailableIcons(): array;
|
||||
|
||||
abstract public function GetRootClass($sClass);
|
||||
abstract public function EnumChildClasses($sClass, $iOption = ENUM_CHILD_CLASSES_EXCLUDETOP);
|
||||
}
|
||||
@@ -109,6 +117,8 @@ abstract class QueryReflection
|
||||
|
||||
class ModelReflectionRuntime extends ModelReflection
|
||||
{
|
||||
private static array $aAllIcons = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
@@ -255,6 +265,52 @@ class ModelReflectionRuntime extends ModelReflection
|
||||
return new RunTimeIconSelectionField($sCode, $sLabel, $defaultValue);
|
||||
}
|
||||
|
||||
public function GetAvailableIcons(): array
|
||||
{
|
||||
$aFolderList = [
|
||||
APPROOT.'env-'.utils::GetCurrentEnvironment() => utils::GetAbsoluteUrlModulesRoot(),
|
||||
APPROOT.'images/icons' => utils::GetAbsoluteUrlAppRoot().'images/icons',
|
||||
];
|
||||
if (count(self::$aAllIcons) == 0) {
|
||||
foreach ($aFolderList as $sFolderPath => $sUrlPrefix) {
|
||||
$aIcons = self::FindIconsOnDisk($sFolderPath);
|
||||
ksort($aIcons);
|
||||
|
||||
foreach ($aIcons as $sFilePath) {
|
||||
self::$aAllIcons[] = ['value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => $sUrlPrefix.$sFilePath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$aAllIcons;
|
||||
}
|
||||
|
||||
private static function FindIconsOnDisk(string $sBaseDir, string $sDir = '', array &$aFilesSpecs = []): array
|
||||
{
|
||||
$aResult = [];
|
||||
// Populate automatically the list of icon files
|
||||
if ($hDir = @opendir($sBaseDir.'/'.$sDir)) {
|
||||
while (($sFile = readdir($hDir)) !== false) {
|
||||
$aMatches = [];
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile)) {
|
||||
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
|
||||
$aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath, $aFilesSpecs));
|
||||
}
|
||||
$sSize = filesize($sBaseDir.'/'.$sDir.'/'.$sFile);
|
||||
if (isset($aFilesSpecs[$sFile]) && $aFilesSpecs[$sFile] == $sSize) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/\.(png|jpg|jpeg|gif|svg)$/i', $sFile, $aMatches)) { // png, jp(e)g, gif and svg are considered valid
|
||||
$aResult[$sFile.'_'.$sDir] = $sDir.'/'.$sFile;
|
||||
$aFilesSpecs[$sFile] = $sSize;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function GetRootClass($sClass)
|
||||
{
|
||||
return MetaModel::GetRootClass($sClass);
|
||||
|
||||
@@ -248,45 +248,6 @@ class RestResultWithObjects extends RestResult
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package RESTAPI
|
||||
* @api
|
||||
*/
|
||||
class RestResultWithObjectSets extends RestResultWithObjects
|
||||
{
|
||||
private $current_object = null;
|
||||
|
||||
public function MakeNewObjectSet()
|
||||
{
|
||||
$arr = array();
|
||||
$this->current_object = &$arr;
|
||||
$this->objects[] = &$arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the given object
|
||||
*
|
||||
* @api
|
||||
* @param string $sObjectAlias Name of the subobject, usually the OQL class alias
|
||||
* @param int $iCode An error code (RestResult::OK is no issue has been found)
|
||||
* @param string $sMessage Description of the error if any, an empty string otherwise
|
||||
* @param DBObject $oObject The object being reported
|
||||
* @param array|null $aFieldSpec An array of class => attribute codes (Cf. RestUtils::GetFieldList). List of the attributes to be reported.
|
||||
* @param boolean $bExtendedOutput Output all of the link set attributes ?
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function AppendSubObject($sObjectAlias, $iCode, $sMessage, $oObject, $aFieldSpec = null, $bExtendedOutput = false)
|
||||
{
|
||||
$oObjRes = ObjectResult::FromDBObject($oObject, $aFieldSpec, $bExtendedOutput, $iCode, $sMessage);
|
||||
$this->current_object[$sObjectAlias] = $oObjRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package RESTAPI
|
||||
* @api
|
||||
@@ -539,22 +500,15 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
|
||||
break;
|
||||
|
||||
case 'core/get':
|
||||
$sClassParam = RestUtils::GetMandatoryParam($aParams, 'class');
|
||||
$sClass = RestUtils::GetClass($aParams, 'class');
|
||||
$key = RestUtils::GetMandatoryParam($aParams, 'key');
|
||||
$sShowFields = RestUtils::GetOptionalParam($aParams, 'output_fields', '*');
|
||||
$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
|
||||
$bExtendedOutput = (RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+');
|
||||
$iLimit = (int)RestUtils::GetOptionalParam($aParams, 'limit', 0);
|
||||
$iPage = (int)RestUtils::GetOptionalParam($aParams, 'page', 1);
|
||||
|
||||
// Validate the class(es)
|
||||
$aClass = explode(',', $sClassParam);
|
||||
foreach ($aClass as $sClass) {
|
||||
if (!MetaModel::IsValidClass(trim($sClass))) {
|
||||
throw new Exception("class '$sClass' is not valid");
|
||||
}
|
||||
}
|
||||
|
||||
$oObjectSet = RestUtils::GetObjectSetFromKey($sClassParam, $key, $iLimit, self::getOffsetFromLimitAndPage($iLimit, $iPage));
|
||||
$sTargetClass = $oObjectSet->GetFilter()->GetClass();
|
||||
$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key, $iLimit, self::getOffsetFromLimitAndPage($iLimit, $iPage));
|
||||
$sTargetClass = $oObjectSet->GetFilter()->GetClass();
|
||||
|
||||
if (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ) != UR_ALLOWED_YES) {
|
||||
$oResult->code = RestResult::UNAUTHORIZED;
|
||||
@@ -565,67 +519,19 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
|
||||
} elseif ($iPage < 1) {
|
||||
$oResult->code = RestResult::INVALID_PAGE;
|
||||
$oResult->message = "The request page number is not valid. It must be an integer greater than 0";
|
||||
} elseif (count($oObjectSet->GetSelectedClasses()) > 1) {
|
||||
$oResult = new RestResultWithObjectSets();
|
||||
$aCache = [];
|
||||
$aShowFields = [];
|
||||
foreach ($oObjectSet->GetSelectedClasses() as $sSelectedClass) {
|
||||
$aShowFields = array_merge( $aShowFields, RestUtils::GetFieldList($sSelectedClass, $aParams, 'output_fields', false));
|
||||
}
|
||||
|
||||
while ($oObjects = $oObjectSet->FetchAssoc()) {
|
||||
$oResult->MakeNewObjectSet();
|
||||
|
||||
foreach ($oObjects as $sAlias => $oObject) {
|
||||
if (!$oObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!array_key_exists($sAlias, $aCache)) {
|
||||
$sClass = get_class($oObject);
|
||||
$bExtendedOutput = RestUtils::HasRequestedExtendedOutput($sShowFields);
|
||||
|
||||
if (!RestUtils::HasRequestedAllOutputFields($sShowFields)) {
|
||||
$aFields = $aShowFields[$sClass];
|
||||
//Id is not a valid attribute to optimize
|
||||
if ($aFields && in_array('id', $aFields)) {
|
||||
unset($aFields[array_search('id', $aFields)]);
|
||||
}
|
||||
$aAttToLoad = [$sAlias => $aFields];
|
||||
$oObjectSet->OptimizeColumnLoad($aAttToLoad);
|
||||
}
|
||||
$aCache[$sAlias] = [
|
||||
'aShowFields' => $aShowFields,
|
||||
'bExtendedOutput' => $bExtendedOutput,
|
||||
];
|
||||
} else {
|
||||
$aShowFields = $aCache[$sAlias]['aShowFields'];
|
||||
$bExtendedOutput = $aCache[$sAlias]['bExtendedOutput'];
|
||||
}
|
||||
|
||||
$oResult->AppendSubObject($sAlias, 0, '', $oObject, $aShowFields, $bExtendedOutput);
|
||||
}
|
||||
}
|
||||
$oResult->message = "Found: ".$oObjectSet->Count();
|
||||
} else {
|
||||
$aShowFields =[];
|
||||
foreach ($aClass as $sSelectedClass) {
|
||||
$sSelectedClass = trim($sSelectedClass);
|
||||
$aShowFields = array_merge($aShowFields, RestUtils::GetFieldList($sSelectedClass, $aParams, 'output_fields', false));
|
||||
}
|
||||
|
||||
if (!RestUtils::HasRequestedAllOutputFields($sShowFields) && count($aShowFields) == 1) {
|
||||
$aFields = $aShowFields[$sClass];
|
||||
//Id is not a valid attribute to optimize
|
||||
if (in_array('id', $aFields)) {
|
||||
unset($aFields[array_search('id', $aFields)]);
|
||||
}
|
||||
if (!$bExtendedOutput && RestUtils::GetOptionalParam($aParams, 'output_fields', '*') != '*') {
|
||||
$aFields = $aShowFields[$sClass];
|
||||
//Id is not a valid attribute to optimize
|
||||
if (in_array('id', $aFields)) {
|
||||
unset($aFields[array_search('id', $aFields)]);
|
||||
}
|
||||
$aAttToLoad = [$oObjectSet->GetClassAlias() => $aFields];
|
||||
$oObjectSet->OptimizeColumnLoad($aAttToLoad);
|
||||
}
|
||||
$oObjectSet->OptimizeColumnLoad($aAttToLoad);
|
||||
}
|
||||
|
||||
while ($oObject = $oObjectSet->Fetch()) {
|
||||
$oResult->AddObject(0, '', $oObject, $aShowFields, RestUtils::HasRequestedExtendedOutput($sShowFields));
|
||||
$oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput);
|
||||
}
|
||||
$oResult->message = "Found: ".$oObjectSet->Count();
|
||||
}
|
||||
|
||||
@@ -75,3 +75,26 @@ collection-entry-element {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.ibo-form-compact{
|
||||
|
||||
.ibo-field{
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
label{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@ $ibo-dashlet-blocker--height: 100% !default;
|
||||
.ibo-dashlet {
|
||||
position: relative;
|
||||
width: calc(#{$ibo-dashlet--width} - #{$ibo-dashlet--elements-spacing-x});
|
||||
margin: calc(#{$ibo-dashlet--elements-spacing-y} / 2) calc(#{$ibo-dashlet--elements-spacing-x} / 2);
|
||||
//margin: calc(#{$ibo-dashlet--elements-spacing-y} / 2) calc(#{$ibo-dashlet--elements-spacing-x} / 2);
|
||||
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
|
||||
&.dashlet-selected {
|
||||
position: relative;
|
||||
@@ -38,4 +41,21 @@ $ibo-dashlet-blocker--height: 100% !default;
|
||||
width: $ibo-dashlet-blocker--width;
|
||||
height: $ibo-dashlet-blocker--height;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.ibo-dashlet--actions {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
display: none;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
|
||||
background-color: $ibo-color-white-100;
|
||||
@extend %ibo-elevation-100;
|
||||
}
|
||||
|
||||
ibo-dashlet[data-edit-mode="edit"] {
|
||||
z-index: 3;
|
||||
}
|
||||
@@ -54,3 +54,31 @@ $ibo-input-select-icon--menu--icon--margin-right: 10px !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ts-control > .ibo-input-select-icon--menu--item{
|
||||
|
||||
display: flex;
|
||||
column-gap: 5px;
|
||||
align-items: center;
|
||||
padding: 5px 0;
|
||||
|
||||
> img{
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
&:hover{
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ts-dropdown > .ts-dropdown-content > .ibo-input-select-icon--menu--item{
|
||||
|
||||
display: flex;
|
||||
column-gap: 5px;
|
||||
|
||||
> img{
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
@import "wizard-container/wizard-container";
|
||||
@import "object/all";
|
||||
@import "activity-panel/all";
|
||||
@import "dashlet-panel/all";
|
||||
|
||||
@@ -175,3 +175,73 @@ input:checked + .ibo-dashboard--slider:before {
|
||||
input:checked + .ibo-dashboard--slider:after {
|
||||
content: $ibo-dashboard--slider--before--content;
|
||||
}
|
||||
|
||||
// TODO 3.3 Cleanup variables
|
||||
// TODO 3.3 Move to vendor what's from gridstack
|
||||
|
||||
|
||||
.grid-stack {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ibo-dashboard[data-edit-mode="edit"] .grid-stack{
|
||||
background-size: calc(100% / 12) var(--gs-cell-height);
|
||||
background-color: $ibo-color-white-100;
|
||||
background-image: linear-gradient(to right, $ibo-color-white-200 8px, transparent 8px), linear-gradient(to bottom, $ibo-color-white-200 8px, transparent 8px);
|
||||
--gs-item-margin-top: 8px;
|
||||
--gs-item-margin-bottom: 0;
|
||||
--gs-item-margin-right: 0;
|
||||
--gs-item-margin-left: 8px;
|
||||
}
|
||||
|
||||
ibo-dashboard[data-edit-mode="view"] {
|
||||
.ibo-dashboard--form {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-dashboard--form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
height: 55px;
|
||||
background-color: $ibo-color-blue-200;
|
||||
margin: -16px -36px 24px -36px;
|
||||
padding: 0 36px;
|
||||
}
|
||||
|
||||
.ibo-dashboard--form--inputs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
@extend %common-font-ral-med-250;
|
||||
}
|
||||
|
||||
.ibo-dashboard[data-edit-mode="edit"] ibo-dashlet:not([data-edit-mode="edit"]):hover .ibo-dashlet--actions {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ibo-dashboard[data-edit-mode="error"] .grid-stack{
|
||||
background-image: url($approot-relative + '/images/alpha-fatal-error.gif');
|
||||
}
|
||||
|
||||
// Our edit mode dashboard already has its own header, so we hide the standard one
|
||||
#ibo-page-header:has(+ ibo-dashboard[data-edit-mode="edit"]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ibo-dashboard[data-edit-mode="edit"] .ibo-dashboard--grid:has(ibo-dashboard-grid-slot > ibo-dashlet[data-edit-mode="edit"]) .ibo-dashboard--grid--backdrop {
|
||||
|
||||
position: absolute;
|
||||
height: calc(100% + 24px);
|
||||
// 36px is $ibo-page-container--elements-padding-x, handle variable resolution
|
||||
width: calc(100% + 36px + 36px);
|
||||
margin: -24px -#{36px} 0 -#{36px};
|
||||
background-color: $ibo-color-grey-400;
|
||||
z-index: 2;
|
||||
opacity: 60%;
|
||||
}
|
||||
2
css/backoffice/layout/dashlet-panel/_all.scss
Normal file
2
css/backoffice/layout/dashlet-panel/_all.scss
Normal file
@@ -0,0 +1,2 @@
|
||||
@import "dashlet-entry";
|
||||
@import "dashlet-panel";
|
||||
51
css/backoffice/layout/dashlet-panel/_dashlet-entry.scss
Normal file
51
css/backoffice/layout/dashlet-panel/_dashlet-entry.scss
Normal file
@@ -0,0 +1,51 @@
|
||||
// TODO 3.3 Cleanup variables
|
||||
|
||||
.ibo-dashlet-entry {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
|
||||
|
||||
border: 1px solid $ibo-color-grey-300;
|
||||
border-radius: 5px;
|
||||
padding: 12px;
|
||||
background-color: $ibo-color-grey-100;
|
||||
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
background-color: $ibo-color-grey-200;
|
||||
border-color: $ibo-color-grey-400;
|
||||
}
|
||||
&:active {
|
||||
background-color: $ibo-color-grey-50;
|
||||
border-color: $ibo-color-grey-500;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-dashlet-entry--icon {
|
||||
flex-shrink: 0;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.ibo-dashlet-entry--content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow-x: hidden;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.ibo-dashlet-entry--title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: $ibo-color-grey-900;
|
||||
}
|
||||
|
||||
.ibo-dashlet-entry--description {
|
||||
font-size: 12px;
|
||||
color: $ibo-color-grey-700;
|
||||
|
||||
}
|
||||
66
css/backoffice/layout/dashlet-panel/_dashlet-panel.scss
Normal file
66
css/backoffice/layout/dashlet-panel/_dashlet-panel.scss
Normal file
@@ -0,0 +1,66 @@
|
||||
// TODO 3.3 Cleanup variables
|
||||
|
||||
.ibo-dashlet-panel {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 326px;
|
||||
background-color: $ibo-color-white-100;
|
||||
}
|
||||
|
||||
.ibo-dashlet-panel--title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
height: 55px;
|
||||
background-color: $ibo-color-white-200;
|
||||
padding: 0 16px;
|
||||
flex-grow: 0;
|
||||
@extend %common-font-ral-med-300;
|
||||
}
|
||||
|
||||
.ibo-dashlet-panel--entries, .ibo-dashlet-panel--form-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
|
||||
padding: 16px;
|
||||
gap: 12px;
|
||||
&.ibo-is-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-center-container:has(ibo-dashboard[data-edit-mode="view"]) .ibo-dashlet-panel{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ibo-dashlet-panel--form-container turbo-frame {
|
||||
height: 100%;
|
||||
}
|
||||
.ibo-dashlet-panel--form-container .ibo-form {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
> .form {
|
||||
overflow: auto;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-dashlet-panel--form-container--buttons {
|
||||
display: flex;
|
||||
flex-direction: row !important;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
|
||||
margin: 0 -16px -16px -16px;
|
||||
padding: 0 16px;
|
||||
min-height: 60px;
|
||||
|
||||
background-color: $ibo-color-grey-50;
|
||||
border-top: solid 1px $ibo-color-grey-400;
|
||||
}
|
||||
@@ -5,11 +5,9 @@
|
||||
|
||||
$ibo-multi-column--margin-x: -$ibo-spacing-500 !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */
|
||||
$ibo-multi-column--margin-y: $ibo-spacing-0 !default;
|
||||
$ibo-multi-column--row-gap: $ibo-spacing-800 !default;
|
||||
|
||||
.ibo-multi-column {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: $ibo-multi-column--margin-y $ibo-multi-column--margin-x;
|
||||
row-gap: $ibo-multi-column--row-gap;
|
||||
}
|
||||
@@ -1,205 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<Brand alias="Brand" id="1">
|
||||
<name>Acer</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icon-acer.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmc6c3ZnIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOnN2Zz0iaH
|
||||
R0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgaWQ9ImFjZXIiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iODMiIGhlaWdodD0iODMiIHZpZXdCb3g9IjAgMCA4MyA4MyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgc29kaXBvZGk6ZG9jbmFtZT0iaWNvbi1hY2VyLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c3ZnOmRlZnMgaWQ9ImRlZnMxIi8+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2
|
||||
aWV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iMTAuNDgzMDcxIiBpbmtzY2FwZTpjeD0iNzUuNzg4ODYiIGlua3NjYXBlOmN5PSIzNS
|
||||
42NzY1NjgiIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MCIgaW5rc2NhcGU6d2luZG93LXg9IjAiIGlua3NjYXBlOndpbmRvdy15PSIwIiBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJhY2VyIj48c29kaXBvZGk6Z3VpZGUgcG9zaXRpb249IjQwLjMwNzkxOSw0MS4yMjAyMTQiIG9yaWVudGF0aW9uPSIwLC0xIiBpZD0iZ3VpZGUxIiBpbmtzY2FwZTpsb2NrZWQ9
|
||||
ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+Cjxzdmc6cGF0aCBpZD0iYWNlci1sb2dvIiBzdHlsZT0iZmlsbDojODBjMzQzIiBkPSJtIDgyLjg1LDMyLjc2MDg5MyBjIC0wLjI5LC0wLjQyIC0wLjYyLC0wLjcgLTIuMDQsLTAuODEgLTAuMzcsLTAuMDMgLTEuNiwtMC4wNyAtMy42NiwtMC4wNyAtNS40MiwwIC05LjEsMS42NSAtMTAuOTgsNC45MSAwLjUyLC0zLjI4IC0yLjY3LC00LjkyIC05LjU1LC00LjkyIC04LjA5LDAgLTEzLjE0LDMuMjcgLTE1LjE1LDkuOD
|
||||
EgLTAuNzQsMS45MSAtMC44Miw0LjAyIC0wLjIzLDUuOTggbCAtMS45MSwwLjEzIGMgLTEuNDksMC4xMSAtMy40NiwwLjIyIC00LjY2LDAuMjIgLTIuOTYsMCAtNC44LC0wLjUgLTUuNTEsLTEuNSAtMC42NCwtMC45IC0wLjU3LC0yLjU2IDAuMTcsLTQuOTggMS4yMywtNC4wMiA0LjI5LC01LjgyIDkuMTgsLTUuODIgMi41MywwIDUsMC4yNyA1LDAuMjcgMC4zLC0wLjA1IDAuNTEsLTAuMzMgMC40NiwtMC42NCAwLC0wLjAxIDAsLTAuMDIgLTAuMDEsLTAuMDMgbCAtMC4w
|
||||
NSwtMC4zOCAtMC4xNywtMS4zNSBjIC0wLjExLC0wLjg5IC0wLjc3LC0xLjQxIC0xLjk3LC0xLjU3IC0xLjEsLTAuMDcgLTEuOTEsLTAuMTMgLTMuMTIsLTAuMTMgaCAtMC4wNyBjIC02LjM5LDAuMDEgLTEwLjg0LDIuMTIgLTEzLjM2LDYuMzIgMC45MiwtNC4yMSAtMi4wNCwtNi4zMiAtOC44NywtNi4zMiAtMi43MywtMC4wNSAtNS40NiwwLjA2IC04LjE4LDAuMzMgLTEuMDMsLTAuMDMgLTEuOTYsMC42MSAtMi4zMywxLjU3IGwgLTAuNTQsMS43MyBjIC0wLjEsMC4zMi
|
||||
AwLjA1LDAuNDggMC40NiwwLjQ4IGggMC4wMSBjIDAuMywtMC4wNCAxLjQ2LC0wLjE1IDMuNDQsLTAuMzEgMi42MiwtMC4yMSA0LjU1LC0wLjMyIDUuODMsLTAuMzIgMy43NywwIDUuMzUsMC45NSA0Ljc2LDIuODQgLTAuMTEsMC40IC0wLjQ0LDAuNzEgLTAuODUsMC43OCAtMy41NiwwLjU5IC02LjM5LDEuMDIgLTguNDgsMS4yOCAtNS44OSwwLjc1IC05LjI5LDIuNTkgLTEwLjIsNS41MiAtMS4yNSw0LjAzIDEuODksNi4wNCA5LjQ0LDYuMDQgMy4xNywwLjA0IDYuMzQs
|
||||
LTAuMTggOS40OCwtMC42NSAxLjQ3LC0wLjI1IDIuMjIsLTAuNjMgMi41MSwtMS41OCBsIDEuNDEsLTQuNDkgYyAtMC4xNSw0LjQ5IDIuOTksNi43NSA5LjQxLDYuNzUgMi4yMywwLjA0IDQuNDUsLTAuMDYgNi42NiwtMC4zMSAxLjMyLC0wLjIzIDEuOTUsLTAuNTIgMi4yNCwtMS41MSBsIDAuMjgsLTEuNDEgYyAxLjM3LDIuMTQgNC4zNywzLjIxIDkuMDEsMy4yMSA0Ljg5LDAgNy43NCwtMC4xNCA4LjU1LC0wLjQxIDAuNTcsLTAuMTIgMS4wNCwtMC41MiAxLjI1LC0xLj
|
||||
A2IDAuMDMsLTAuMDkgMC4wNSwtMC4xOSAwLjA2LC0wLjI4IGwgMC41OSwtMS45MSBjIDAuMSwtMC4zMyAtMC4wNSwtMC40OSAtMC40NSwtMC40OCBsIC0zLjEzLDAuMTUgYyAtMi4wOSwwLjEyIC0zLjcyLDAuMTggLTQuOSwwLjE3IC0xLjU0LDAuMDggLTMuMDgsLTAuMDcgLTQuNTgsLTAuNDYgLTEuMiwtMC40MSAtMS45NCwtMS42MSAtMS43NywtMi44NiBsIDkuOTEsLTEuMjcgYyA0LjQ0LC0wLjU3IDcuNDIsLTEuOTQgOC45MiwtNC4xMiBsIC0zLjM3LDExLjczIGMg
|
||||
LTAuMDcsMC4xOCAtMC4wNCwwLjM4IDAuMDcsMC41MyAwLjE4LDAuMTcgMC40MSwwLjI1IDAuNjUsMC4yMiBoIDQuMSBjIDAuNDcsMC4wNyAwLjkzLC0wLjIyIDEuMDYsLTAuNjggbCAzLjYyLC0xMi42NyBjIDAuNDgsLTEuNjcgMiwtMi40OCA0LjY3LC0yLjQ4IDIuNDEsMCA0LjIyLDAuMDIgNS4zOCwwLjA3IDAuMDMsMCAwLjA2LDAgMC4wOSwwIDAuMzksMCAwLjc0LC0wLjI2IDAuODQsLTAuNjMgbCAwLjYzLC0xLjc0IGMgMC4xNSwtMC4zIDAuMTIsLTAuNjMgLTAuMD
|
||||
UsLTAuODkgbSAtNjYuMTIsMTUuMjQgYyAtMS44MywwLjIzIC0zLjY4LDAuMzMgLTUuNTIsMC4zIC00LjE3LDAgLTUuOTksLTAuODQgLTUuNDYsLTIuNTMgMC4zOCwtMS4yMSAxLjQ3LC0xLjk0IDMuMjgsLTIuMTkgbCA5LjQ4LC0xLjI4IHogbSA0My44MywtMTAuMjcgYyAtMC40LDEuMyAtMi4yNSwyLjE5IC01LjU2LDIuNjcgbCAtNy45LDEuMTMgMC4yLC0wLjY1IGMgMC4zOSwtMS43NCAxLjM3LC0zLjI4IDIuNzksLTQuMzcgMS4yLC0wLjc3IDMuMTUsLTEuMTYgNS44NiwtMS4xNiAzLjU2LDAgNS4xLDAuOCA0LjYxLDIuMzgiLz4KPC9zdmc6c3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Acer</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="2">
|
||||
<name>Apple</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-mac-os.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwODgzZDkiIGQ9Ik0zNi4yMzIsMjMuOTg1YzAtNS44NjUsNC43NjYtOC41MSw0Ljk2Ni04LjYzNmMtMi41OTYtMy45OTMtNi43OS00LjQ2Ny
|
||||
04LjM2Mi00LjQ2OCBjLTMuNjQzLDAtNi44NjMsMi4wMjItOC41ODUsMi4wMjJjLTEuNzk3LDAtNC40MTgtMi4xMjEtNy4zNjMtMi4wMjJjLTMuODQzLDAuMDc1LTcuMzYzLDIuMzQ2LTkuMzM0LDUuNjkxIGMtMS4zOTcsMi4zOTYtMS45NDcsNS4yMTctMS44OTYsOC4wODdjMC4wMDIsMC4xMTMsMC4wMTcsMC4yMjgsMC4wMiwwLjM0MUgzNi4zMkMzNi4yNzksMjQuNjcxLDM2LjI0MywyNC4zMzcsMzYuMjMyLDIzLjk4NXoiLz48cGF0aCBmaWxsPSIjMDg4M2Q5IiBkPSJN
|
||||
MzAuNTY1LDcuMDYzQzMyLjI2MSw1LjE5MSwzMy4yMSwyLjYyMSwzMy4wNiwwYy0yLjM0NiwwLTUuMDY2LDEuMzcyLTYuNzg4LDMuMzk0IGMtMS4zNDgsMS42NzItMi43OTUsNC4yOTMtMi4yNzEsNi45MTNDMjYuNDIyLDEwLjYwNywyOS4wNDMsOS4wODUsMzAuNTY1LDcuMDYzeiIvPjxwYXRoIGZpbGw9IiMwMzcwYzgiIGQ9Ik0xNy41MTEsNDVjMi43NzEsMCwzLjc5NC0xLjg0OCw3LjQxMy0xLjg0OGMzLjM3LDAsNC40MTgsMS44NDgsNy4zMzgsMS44NDggYzMuMDcsMCw1LjA5Mi0yLjc5NSw2LjkxMy01LjU2N2MyLjI5NS0zLjIxOCwzLjA3LTYuMjg4LDMuMTY5LTYuNDE0Yy0wLjA5NCwwLTUuMjg3LTIuMTEyLTYuMDI2LTguMDE5SDUuNjc4IGMwLjE1Nyw1LjMxMSwyLjIyOCwxMC43OSw0LjY3MSwxNC4zMDlDMTIuMjcsNDIuMDU1LDE0LjQ0MSw0NSwxNy41MTEsNDV6Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Apple</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="3">
|
||||
<name>Asus</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-asus.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93
|
||||
d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwLDAsMjU2LDI1NiIgd2lkdGg9IjY0cHgiIGhlaWdodD0iNjRweCIgZmlsbC1ydWxlPSJub256ZXJvIiB2ZXJzaW9uPSIxLjEiIGlkPSJzdmcxMyIgc29kaXBvZGk6ZG9jbmFtZT0iaWNvbnM4LWFzdXMgKDEpLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c29kaXBvZGk6bmFtZWR2aWV3IGlkPS
|
||||
JuYW1lZHZpZXcxMyIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgaW5rc2NhcGU6em9vbT0iMTcuMTg3NSIgaW5rc2NhcGU6Y3g9IjMxLjk3MDkwOSIgaW5rc2NhcGU6Y3k9IjMyIiBpbmtzY2FwZTp3
|
||||
aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzEzIi8+PGRlZnMgaWQ9ImRlZnMxMCI+PHJhZGlhbEdyYWRpZW50IGN4PSIzNC42MjUiIGN5PSIzMS44NzUiIHI9IjIzLjIwNiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJjb2xvci0xIj
|
||||
48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmNGU5YzMiIGlkPSJzdG9wMSIvPjxzdG9wIG9mZnNldD0iMC4yMTkiIHN0b3AtY29sb3I9IiNmOGVlY2QiIGlkPSJzdG9wMiIvPjxzdG9wIG9mZnNldD0iMC42NDQiIHN0b3AtY29sb3I9IiNmZGY0ZGMiIGlkPSJzdG9wMyIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ZmZjZlMSIgaWQ9InN0b3A0Ii8+PC9yYWRpYWxHcmFkaWVudD48bGluZWFyR3JhZGllbnQgeDE9IjAuMzY1IiB5MT0iMzIuNSIgeDI9
|
||||
IjY0IiB5Mj0iMzIuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJjb2xvci0yIj48c3RvcCBvZmZzZXQ9IjAuMDUzIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBpZD0ic3RvcDUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDAwMDAiIGlkPSJzdG9wNiIvPjwvbGluZWFyR3JhZGllbnQ+PHJhZGlhbEdyYWRpZW50IGN4PSIzNC42MjUiIGN5PSIzMS44NzUiIHI9IjIzLjIwNiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPS
|
||||
Jjb2xvci0zIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmNGU5YzMiIGlkPSJzdG9wNyIvPjxzdG9wIG9mZnNldD0iMC4yMTkiIHN0b3AtY29sb3I9IiNmOGVlY2QiIGlkPSJzdG9wOCIvPjxzdG9wIG9mZnNldD0iMC42NDQiIHN0b3AtY29sb3I9IiNmZGY0ZGMiIGlkPSJzdG9wOSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ZmZjZlMSIgaWQ9InN0b3AxMCIvPjwvcmFkaWFsR3JhZGllbnQ+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVs
|
||||
ZT0ibm9uemVybyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIGZvbnQtZmFtaWx5PSJub25lIiBmb250LXdlaWdodD0ibm9uZSIgZm9udC1zaXplPSJub25lIiB0ZXh0LWFuY2hvcj0ibm9uZSIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiIGlkPSJnMT
|
||||
MiPjxnIHRyYW5zZm9ybT0ic2NhbGUoNCw0KSIgaWQ9ImcxMiI+PHBhdGggZD0iTTYuMTU2LDI5LjI0M2wtNS43MjMsOS45MTljLTAuMTkyLDAuMzMzIDAuMDQ4LDAuNzUgMC40MzMsMC43NWgyLjc2NGMwLjM1NiwwIDAuNjg2LC0wLjE5IDAuODY1LC0wLjQ5OGw1LjYyOSwtOS43MDF6TTYuMjk5LDI5LjAwNWMwLDAgMC44MTUsLTEuNDg2IDEuNjI1LC0yLjkyYzAuMzU0LC0wLjYyOCAxLjAxOSwtMS4wMTQgMS43NCwtMS4wMTRjMS40MDgsMC4wMDEgMy43NTcsMC4wMDMg
|
||||
NS4wODYsMC4wMDRjMC41NTIsMCAwLjk5NSwwLjQ0OCAwLjk5NSwxLjAwMXYyLjYxYzAsMCAwLjMyMywtMS4zODYgMC44OTEsLTIuMDQzYzAuNTM0LC0wLjYxOSAxLjI0NiwtMS40NzggMi44NzIsLTEuNTkyaDEwLjk2M2MwLjU1MiwwIDEsMC40NDggMSwxdjEuOTU1YzAsMC41NTIgLTAuNDQ4LDEgLTEsMXpNNjQsMjguMDA4di0xLjk1OGMwLC0wLjU1MiAtMC40NDgsLTEgLTEsLTFoLTExLjhjLTEuNjIyLDAuMTE0IC0yLjMzNywwLjk3MiAtMi44NzIsMS41OTJjLTAuNT
|
||||
Y5LDAuNjU3IC0wLjg5LDIuMDQzIC0wLjg5LDIuMDQzdjAuMzE4bDE1LjU2MiwwLjAwNWMwLjU1MiwwIDEsLTAuNDQ4IDEsLTF6TTMzLjA5NSwyNS4wN2gxLjU3OGMwLjU1MiwwIDEsMC40NDggMSwxdjIuOTM1aC0zLjU3OHYtMi45MzVjMCwtMC41NTIgMC40NDgsLTEgMSwtMXpNNDQuODM5LDI1LjA3aDEuNTc0YzAuNTUyLDAgMSwwLjQ0OCAxLDF2Mi45MzVoLTMuNTc0di0yLjkzNWMwLC0wLjU1MiAwLjQ0NywtMSAxLC0xek00Ny40MTMsMzAuNDI1bC0zLjUxNCwtMC4y
|
||||
MzN2NC41NjZjMCwwIC0wLjAxLDEuMzE0IC0xLjE1OCwxLjMxNGMtMS4xMzgsMCAtNi4wMzksMCAtNi4wMzksMGMwLDAgLTEuMDIzLC0wLjA5MyAtMS4wMjMsLTEuMzAzYzAsLTEuMjA3IDAsLTUuMTk2IDAsLTUuMTk2bC0zLjU0OSwtMC4yODV2Ny4wMDFjMC41NzQsMy4zNTkgMy4zMTEsMy42MTcgMy4zMTEsMy42MTdjMCwwIDAuMjc4LDAuMDIyIDAuMzI0LDAuMDI2aDguMTU2YzAsMCAzLjQ5MSwtMC4zMTEgMy40OTEsLTQuMDIzYzAuMDAxLC0zLjcxMyAwLjAwMSwtNS
|
||||
40ODQgMC4wMDEsLTUuNDg0ek0xMy4xMTEsMzkuOTE0aDE1LjczYzIuOTE0LC0wLjY0NyAzLjIxOCwtMy41NzcgMy4yMTgsLTMuNTc3YzAuMTM2LC0wLjg3MSAwLjA1NywtMS41NzQgMC4wNTcsLTEuNTc0Yy0wLjA4OCwtMC41ODggLTEuMDk0LC0zLjE3OCAtMy4yODEsLTMuNDA1Yy0xLjMwNCwtMC4xMzQgLTEyLjkxLC0xLjE1NSAtMTIuOTEsLTEuMTU1YzAuMjI1LDEuMjg4IDAuNzQ4LDEuOTM4IDEuMDk0LDIuMzExYzAuODA1LDAuODU3IDIuMDg3LDEuMDk5IDIuMDg3
|
||||
LDEuMDk5YzAuMzA5LDAuMDMzIDguOTQ1LDAuODI0IDguOTQ1LDAuODI0YzAuMjc0LDAuMDE3IDAuNzk3LDAuMDkzIDAuNzksMC44NDljMCwwLjA5MSAtMC4wNzUsMC43NTcgLTAuNzM4LDAuNzU3aC0xMi4wMTRjLTAuMjc2LDAgLTAuNSwtMC4yMjQgLTAuNSwtMC41di01LjM3M2wtMy40NzgsLTAuMjgxdjkuMDI3YzAsMC41NSAwLjQ0OCwwLjk5OCAxLDAuOTk4ek00Ny40NDQsMzcuMDE3YzAuMDAxLC0wLjU1MiAwLjQ0OCwtMC45OTggMSwtMC45OThoMTEuNDI5YzAuMj
|
||||
g2LDAgMC41OTUsLTAuMTg3IDAuNTk1LC0wLjE4N2MwLjEzLC0wLjEyOSAwLjIzNSwtMC4zNjQgMC4yMzUsLTAuNTkxYzAsLTAuNzUzIC0wLjU2MSwtMC43ODYgLTAuODQzLC0wLjgwM2MwLDAgLTguNzMyLC0wLjgwOCAtOS4wMzYsLTAuODM0YzAsMCAtMS4yMTEsLTAuMjA3IC0yLjAxNywtMS4wNjhjLTAuMzUxLC0wLjM2OSAtMC44MTUsLTAuNzcxIC0xLjE2MSwtMi4wOTljMCwwIDExLjY3MSwwLjc2MyAxMi45NjgsMC44OTdjMi4xODksMC4yMzIgMy4yMTUsMi42MzIgMy4zMDgsMy40M2MwLDAgMC4wOTMsMC43MjIgLTAuMDIsMS42MDdjMCwwIC0wLjQ1NCwzLjM3NCAtMy42NjQsMy41NzloLTExLjc5N2MtMC41NTMsMCAtMS4wMDEsLTAuNDQ5IC0xLC0xLjAwMnoiIGZpbGw9InVybCgjY29sb3ItMikiIGlkPSJwYXRoMTEiLz48L2c+PC9nPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Asus</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="4">
|
||||
<name>Cisco</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icon-cisco.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93d
|
||||
3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgd2lkdGg9IjEwOCIgaGVpZ2h0PSIxMDgiIHZpZXdCb3g9IjAgMCAxMDggMTA4IiByb2xlPSJpbWciIHZlcnNpb24
|
||||
9IjEuMSIgaWQ9InN2ZzExIiBzb2RpcG9kaTpkb2NuYW1lPSJpY29uLWNpc2NvLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c29kaXBvZGk6bmFtZWR2aWV3IGlkPSJuYW1lZHZpZXcxMSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlO
|
||||
nBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iNi44MjI5NjAyIiBpbmtzY2FwZTpjeD0iNDguODc5MDc4IiBpbmtzY2FwZTpjeT0iNTEuNzM3MDc1IiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGl
|
||||
taXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMTEiPjxzb2RpcG9kaTpndWlkZSBwb3NpdGlvbj0iMTYuOTM5NTg3LDUzLjM3NjMwMyIgb3JpZW50YXRpb249IjAsLTEiIGlkPSJndWlkZTExIiBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+PHRpdGxlIGlkPSJmdy1jLWhlYWRlcl9fbG9nby10aXRsZSI+Q2lzY28uY29tIEZyYW5jZTwvdGl0bGU+PGRlZnMgaWQ9ImRlZnMxIj48cGF0aCBkPSJtIDAsMjIuNzY5IGEgM
|
||||
i4zNDgsMi4zNDggMCAwIDAgMy45MzUsMS41NDUgYyAwLjQzNCwtMC40MDMgMC43LC0wLjk1NSAwLjc0NCwtMS41NDUgdiAtNS4yIGEgMi4zNCwyLjM0IDAgMCAwIC00LjY3OSwwIHYgNS4yIiBpZD0iYmFyX3Nob3J0IiBjbGFzcz0iYmFyIi8+PHBhdGggZD0ibSAxMi45NSwyMi43NjkgYSAyLjM0OSwyLjM0OSAwIDAgMCAyLjM0LDIuMTcxIDIuMzQ2LDIuMzQ2IDAgMCAwIDIuMzM5LC0yLjE3MSBWIDExLjExMiBhIDIuMzQxLDIuMzQxIDAgMCAwIC00LjY3OSwwIFYgMjI
|
||||
uNzciIGlkPSJiYXJfdGFsbCIgY2xhc3M9ImJhciIvPjxwYXRoIGQ9Im0gMjUuODMyLDI3LjQ2NCBhIDIuMzQ1LDIuMzQ1IDAgMCAwIDQuNjc4LDAgViAyLjI0OSBhIDIuMzQyLDIuMzQyIDAgMCAwIC00LjY3OCwwIHYgMjUuMjE1IiBpZD0iYmFyX2dyYW5kZSIgY2xhc3M9ImJhciIvPjxwYXRoIGQ9Im0gMjQuMDI2LDU2LjI3NyB2IC01LjAwMiBsIC0wLjA5OCwwLjA0MyBhIDkuMjUzLDkuMjUzIDAgMCAxIC0zLjYwNSwwLjkxNSA1LjMwMyw1LjMwMyAwIDAgMSAtMy42M
|
||||
ywtMS4wNyA0LjY0NCw0LjY0NCAwIDAgMSAtMS41OCwtMi4yNDQgNS4zOTUsNS4zOTUgMCAwIDEgLTAuMTA2LC0zIDQuNiw0LjYgMCAwIDEgMS42MDksLTIuNTY2IDQuODIzLDQuODIzIDAgMCAxIDIuNTI4LC0xLjA5IDguMzMyLDguMzMyIDAgMCAxIDQuNzc0LDAuODk1IGwgMC4xMDgsMC4wNTYgdiAtNS4wMyBsIC0wLjIyOCwtMC4wNjEgYSAxMi43OCwxMi43OCAwIDAgMCAtNC41NTIsLTAuNTk2IDEwLjUzNCwxMC41MzQgMCAwIDAgLTQuMDY1LDAuOTMgOS4yOSw5LjI
|
||||
5IDAgMCAwIC0zLjMyOSwyLjU3MiAxMC4wMTQsMTAuMDE0IDAgMCAwIC0wLjE4MiwxMi4xOCA5LjU0Niw5LjU0NiAwIDAgMCA1LjI5MiwzLjQwMyBjIDIuMjExLDAuNTM4IDQuNTI4LDAuNDU2IDYuNjk3LC0wLjIzNCBsIDAuMzY3LC0wLjEwMSIgaWQ9ImNpc2NvX2MiLz48L2RlZnM+PGcgZmlsbD0iIzAyYzhmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iZzExIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC4wOTQ2Njg1OSwyNi4yMzQ5NDYpIj48dXNlIGhyZWY9IiNja
|
||||
XNjb19jIiBpZD0idXNlMSIvPjx1c2UgaHJlZj0iI2Npc2NvX2MiIHg9IjQ5LjUiIGlkPSJ1c2UyIi8+PHBhdGggZD0ibSA0MS42OSw1Mi4xMjUgLTAuMDE5LDQuMzA4IDAuMzE1LDAuMDU0IGMgMC45ODksMC4xODUgMS45ODcsMC4zMTMgMi45OSwwLjM4NSBhIDE4LjEsMTguMSAwIDAgMCAyLjY0MiwwLjA1MSBjIDAuODQyLC0wLjA2IDEuNjc1LC0wLjIxOCAyLjQ4LC0wLjQ2OCBhIDYuODYyLDYuODYyIDAgMCAwIDIuNTczLC0xLjM3MSA1LjE5LDUuMTkgMCAwIDAgMS4
|
||||
0OTgsLTIuMTQ4IDUuOTEyLDUuOTEyIDAgMCAwIC0wLjAzLC00LjMyNCA0Ljg1Miw0Ljg1MiAwIDAgMCAtMS4zNDMsLTEuODYyIDUuNTY4LDUuNTY4IDAgMCAwIC0xLjk3LC0xLjE0NyBsIC0zLjI1LC0xLjIwNiBhIDEuNzQyLDEuNzQyIDAgMCAxIC0wLjg4NywtMC44NDUgMS4xMDcsMS4xMDcgMCAwIDEgMC4wMzYsLTAuOTg2IDEuMjksMS4yOSAwIDAgMSAwLjIxNywtMC4yOTEgMS43NSwxLjc1IDAgMCAxIDAuNDgsLTAuMzQ3IGMgMC4zNjMsLTAuMTggMC43NTUsLTAuM
|
||||
jkzIDEuMTU4LC0wLjMzNyBhIDYuNzYsNi43NiAwIDAgMSAyLjA3MiwwLjAyMiBjIDAuODEsMC4wODggMS42MTMsMC4yMzEgMi40MDIsMC40MyBsIDAuMTY4LDAuMDM3IHYgLTMuOTc0IGwgLTAuMzEsLTAuMDY3IGEgMjEuMTQsMjEuMTQgMCAwIDAgLTIuNDQ0LC0wLjQzNSAxMi41NDUsMTIuNTQ1IDAgMCAwIC0zLjIxMywtMC4wMTQgNi45NDUsNi45NDUgMCAwIDAgLTMuNjk5LDEuNDg4IDQuOTA4LDQuOTA4IDAgMCAwIC0xLjU4LDIuMTc4IDUuOTg0LDUuOTg0IDAgMCA
|
||||
wIC0wLjAwMyw0LjA1IGMgMC4yNDIsMC42NSAwLjYzLDEuMjM3IDEuMTM2LDEuNzE0IDAuNDM3LDAuNDIyIDAuOTMyLDAuNzggMS40NywxLjA2NSAwLjcwOCwwLjM4IDEuNDU4LDAuNjc1IDIuMjM1LDAuODc4IDAuMjU3LDAuMDc3IDAuNTEyLDAuMTU4IDAuNzY2LDAuMjQzIGwgMC4zODUsMC4xNDEgMC4xMSwwLjA0NSBjIDAuMzgsMC4xMzYgMC43MjYsMC4zNSAxLjAxOCwwLjYyOCAwLjIwMiwwLjE5IDAuMzU4LDAuNDIzIDAuNDU1LDAuNjgzIDAuMDYsMC4yMzcgMC4wN
|
||||
jEsMC40ODUgMC4wMDMsMC43MjMgYSAxLjUzNiwxLjUzNiAwIDAgMSAtMC43NDQsMC44OTIgMy42OTEsMy42OTEgMCAwIDEgLTEuMjM5LDAuMzg3IDksOSAwIDAgMSAtMS45MiwwLjA5NyAyMS45NzMsMjEuOTczIDAgMCAxIC0yLjUwNywtMC4zMzQgYyAtMC40MzMsLTAuMDkgLTAuODY0LC0wLjE5IC0xLjI5MSwtMC4zMDMgeiBtIC0xMS4xNDQsNC40ODIgaCA0LjczIFYgMzcuODQ2IGggLTQuNzMgeiBNIDg1LjMwNSw0My4zODYgYSA0LjkzNCw0LjkzNCAwIDEgMSA2LjE
|
||||
1Nyw3LjcxMSA0LjkzNCw0LjkzNCAwIDAgMSAtNi4xNTcsLTcuNzEgbSAtNi44NjcsMy44NDggYSA5Ljg3LDkuODcgMCAwIDAgMTIuMDAyLDkuNDg1IDkuNjI5LDkuNjI5IDAgMCAwIDMuMTU3LC0xNy43MjkgOS45MzQsOS45MzQgMCAwIDAgLTE1LjE2LDguMjQ0IiBpZD0icGF0aDIiLz48dXNlIGhyZWY9IiNiYXJfc2hvcnQiIHg9IjAiIGlkPSJ1c2UzIi8+PHVzZSBocmVmPSIjYmFyX3RhbGwiIHg9IjAiIGlkPSJ1c2U0Ii8+PHVzZSBocmVmPSIjYmFyX2dyYW5kZSIge
|
||||
D0iMCIgaWQ9InVzZTUiLz48dXNlIGhyZWY9IiNiYXJfdGFsbCIgeD0iMjUuODc1IiBpZD0idXNlNiIvPjx1c2UgaHJlZj0iI2Jhcl9zaG9ydCIgeD0iNTEuNzUiIGlkPSJ1c2U3Ii8+PHVzZSBocmVmPSIjYmFyX3RhbGwiIHg9IjUxLjc1IiBpZD0idXNlOCIvPjx1c2UgaHJlZj0iI2Jhcl9ncmFuZGUiIHg9IjUxLjc1IiBpZD0idXNlOSIvPjx1c2UgaHJlZj0iI2Jhcl90YWxsIiB4PSI3Ny42MjUiIGlkPSJ1c2UxMCIvPjx1c2UgaHJlZj0iI2Jhcl9zaG9ydCIgeD0iMTAzLjM3NSIgaWQ9InVzZTExIi8+PC9nPjxtZXRhZGF0YSBpZD0ibWV0YWRhdGExMSI+PHJkZjpSREY+PGNjOldvcmsgcmRmOmFib3V0PSIiPjxkYzp0aXRsZT5DaXNjby5jb20gRnJhbmNlPC9kYzp0aXRsZT48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Cisco</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="5">
|
||||
<name>Dell</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-dell.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwMjg4ZDEiIGQ9Ik0yNCw0QzEyLjk1Niw0LDQsMTIuOTU2LDQsMjRzOC45NTYsMjAsMjAsMjBzMjAtOC45NTYsMjAtMjBTMzUuMDQ0LDQsMjQs
|
||||
NHogTTI0LDQxYy05LjM5MSwwLTE3LTcuNjA5LTE3LTE3UzE0LjYwOSw3LDI0LDdzMTcsNy42MDksMTcsMTdTMzMuMzkxLDQxLDI0LDQxeiIvPjxwYXRoIGZpbGw9IiMwMjg4ZDEiIGQ9Ik0zNS42NDEsMjUuNTYzbDIuODQsMC4wMDRsLTAuMDA0LDIuMzk1bC01LjY5MS0wLjAxMmwwLjAxMi04LjE3MmwyLjg1NSwwLjAwNEwzNS42NDEsMjUuNTYzeiBNMjYuMzQsMjUuMTAybC00LjY5OSwzLjY4NGwtNC4yODUtMy4zNzljLTAuNjIxLDEuNDg0LTIuMTA5LDIuNTItMy44Mz
|
||||
YsMi41MTZsLTMuNjY0LTAuMDA0bDAuMDA4LTguMTcybDMuNjY4LDAuMDA0YzEuOTI2LDAuMDA0LDMuMzA5LDEuMjIzLDMuODI4LDIuNTMxbDQuMjk3LTMuMzY3bDEuNTg2LDEuMjVsLTMuOTM0LDMuMDg2bDAuNzU0LDAuNTk0bDMuOTM0LTMuMDg2bDEuNTksMS4yNTRsLTMuOTM0LDMuMDgybDAuNzUsMC41OTRsMy45NDEtMy4wODJsMC4wMDQtMi44MzZsMi44NTIsMC4wMDRsLTAuMDA4LDUuNzgxbDIuODQsMC4wMDRsLTAuMDA0LDIuMzkxbC01LjY5MS0wLjAwOEwyNi4zNCwyNS4xMDJ6IE0xNS4wMTIsMjMuODRjMC0xLjExMy0wLjczLTEuNzQyLTEuNzctMS43NDJoLTAuNjM3bC0wLjAwNCwzLjQ3N2gwLjYyMUMxNC4xODQsMjUuNTc0LDE1LjAxMiwyNS4wNTEsMTUuMDEyLDIzLjg0Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Dell</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="6">
|
||||
<name>HP Inc</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-hp.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0yNCA0QTIwIDIwIDAgMSAwIDI0IDQ0QTIwIDIwIDAgMSAwIDI0IDRaIi8+PHBhdGggZmlsbD0iIzE5NzZkMiIgZD0iTTI0LDQzLj
|
||||
k5N2MtMC4xOTksMC0wLjY1MiwwLjAwNi0wLjg1LDBsNC0xMC45OTloNS42MjVjMC45ODcsMCwyLjA3MS0wLjc1OSwyLjQwOS0xLjY4Nmw0Ljc0OC0xMi42ODdjMC43MjUtMS45OTUtMC40MTctMy42MjYtMi41MzktMy42MjZoLTcuODA0bC02LjUxOCwxOC4yNTdoLTAuMDAybC0zLjcxMiwxMC4xOThDMTAuNTUsNDEuMzYxLDQsMzMuNDQ1LDQsMjMuOTk5YzAtOS4xNzQsNi4xNzgtMTYuOTA1LDE0LjYtMTkuMjYxbC0zLjgzLDEwLjUyNmgtMC4wMDFMOC4xNSwzMi45OTho
|
||||
NC4yMzlsNS41NzYtMTQuOTk5aDMuMTg1bC01LjU3NiwxNC45OTlsMy45MTksMC4wMDFsNS40MzgtMTQuMzc0YzAuNzI2LTEuOTk1LTAuNDE2LTMuNjI2LTIuNTM2LTMuNjI2SDE5LjE1bDMuOTUxLTEwLjk3OEMyMy4zOTksNC4wMDgsMjMuNjk5LDQsMjQsNGMxMS4wNDYsMCwyMCw4Ljk1MywyMCwxOS45OTlTMzUuMDQ2LDQzLjk5NywyNCw0My45OTd6IE0zNi4xNSwxNy45OTloLTMuMTg1bC00LjUwOSwxMS45OTloMy4xODVMMzYuMTUsMTcuOTk5eiIvPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>HP Inc</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="7">
|
||||
<name>HPE</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icon-hpe.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93d3c
|
||||
udzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjAiIGlkPSJrYXRtYW5fMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA2MzAgNjMwIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzb2RpcG9kaTpkb2NuYW1lPSJpY29uLWhwZS5zdmciIHdpZHRoPSI2MzAiIGhlaWdodD0iNjMwIiBpbmtzY2FwZTp2ZXJzaW9uPSIxLjQuMyAoMGQxNWY3NTA0MiwgMjAyNS0xMi0yNSkiPjxkZWZzIGlkPSJkZWZzM
|
||||
iIvPjxzb2RpcG9kaTpuYW1lZHZpZXcgaWQ9Im5hbWVkdmlldzIiIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgYm9yZGVyY29sb3I9IiMwMDAwMDAiIGJvcmRlcm9wYWNpdHk9IjAuMjUiIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIyIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIiBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIwIiBpbmtzY2FwZTpkZXNrY29sb3I9IiNkMWQxZDEiIHNob3dndWlkZXM9InRydWUiIGlua3NjYXBlOnpvb209IjAuNjkwNTUxNSIgaW5rc2N
|
||||
hcGU6Y3g9Ii0yMTcuOTQxNzUiIGlua3NjYXBlOmN5PSIyNzUuMTQyNCIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIiBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYwIiBpbmtzY2FwZTp3aW5kb3cteD0iMCIgaW5rc2NhcGU6d2luZG93LXk9IjAiIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImthdG1hbl8xIj48c29kaXBvZGk6Z3VpZGUgcG9zaXRpb249IjE5Ny42NjI0NCwzMTQuNDg4NDgiIG9yaWVudGF0a
|
||||
W9uPSIwLC0xIiBpZD0iZ3VpZGUyIiBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyIgaWQ9InN0eWxlMSI+Cgkuc3Qwe2ZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MzY7fQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiMwM0E4ODM7c3Ryb2tlLXdpZHRoOjM2O30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0ibSAxOC41MTE5ODcsNDA1LjkzMDEyIHYgLTE4MCBtIDE
|
||||
1NC4wMDAwMDMsMTgwIHYgLTE4MCBtIC0xNTQuMDAwMDAzLDg5IEggMTU1LjUxMTk5IG0gOTUsOTEgdiAtMTgwIG0gMCwxOCBoIDEwMiBjIDI3LjYsMCA1MCwyMi40IDUwLDUwIDAsMjcuNiAtMjIuNCw1MCAtNTAsNTAgaCAtMTAyIG0gMjIyLC02NyB2IC0zMyBoIDE1OCIgaWQ9InBhdGgxIi8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Im0gNjMwLjUxMTk5LDM4Ny45MzAxMiBoIC0xNTggdiAtNzYgaCAxNTgiIGlkPSJwYXRoMiIvPgo8L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>HPE</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="8">
|
||||
<name>IBM</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-ibm.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMzZjUxYjUiIGQ9Ik00OCAxNkw0OCAxNCA0MC40NjkgMTQgMzkuODA5IDE2ek0zMyAzMUwzMyAyOSAyOSAyOSAyNyAyOSAyNyAzMXpNMzkuNzY2I
|
||||
DI4TDQwLjUxIDI2IDM0LjUxIDI2IDM1LjI2NiAyOHpNMjkgMjZIMzNWMjhIMjl6TTI5IDIzSDMzVjI1SDI5ek00MiAyOUw0MiAzMSA0OCAzMSA0OCAyOSA0NiAyOXpNMzYuMTgxIDE5TDM1LjUyMSAxNyAyNyAxNyAyNyAxOSAyOSAxOXpNMzcuMTcgMjJMMzYuNTEgMjAgMjkgMjAgMjkgMjJ6TTMzLjM3OCAyM0wzNC4xMzMgMjUgNDAuODgzIDI1IDQxLjYyOCAyM3pNNDIgMjNINDZWMjVINDJ6TTI3IDMySDMzVjM0SDI3ek0zNS4xOTEgMTZMMzQuNTMxIDE0IDI3IDE0IDI
|
||||
3IDE2ek0zNi43NzYgMzJMMzcuNTMxIDM0IDM4LjI3NiAzMnpNNDIgMzJINDhWMzRINDJ6TTM5LjQ3OSAxN0wzOC44MTkgMTkgNDYgMTkgNDggMTkgNDggMTd6TTM5LjM5MyAyOUwzNS42NDMgMjkgMzYuMzk4IDMxIDM4LjY0OCAzMXpNNDIgMjZINDZWMjhINDJ6TTM4LjQ5IDIwTDM3LjgzIDIyIDQ2IDIyIDQ2IDIwek0wIDE0SDhWMTZIMHpNMCAxN0g4VjE5SDB6TTIgMjBINlYyMkgyek0yIDIzSDZWMjVIMnpNMiAyNkg2VjI4SDJ6TTAgMjlIOFYzMUgwek0wIDMySDhWM
|
||||
zRIMHpNMTAgMTdIMThWMTlIMTB6TTI0Ljk3NyAxNmMtLjkxMy0xLjIwOC0yLjM0Ny0yLTMuOTc3LTJIMTB2Mmg3LjAyM0gyNC45Nzd6Ii8+PHBhdGggZmlsbD0iIzNmNTFiNSIgZD0iTTI1LjU3OCAxN2gtOS4xMzFDMTYuMTcxIDE3LjYxMyAxNiAxOC4yODMgMTYgMTloMTBDMjYgMTguMjg4IDI1Ljg0NiAxNy42MTMgMjUuNTc4IDE3ek0yMy45NzUgMjNIMTJ2MmgxMS45NzNjLS44MzMtLjYyLTEuODU0LTEtMi45NzMtMUMyMi4xMTkgMjQgMjMuMTQyIDIzLjYyMSAyMy4
|
||||
5NzUgMjN6TTE3LjAyMyAzMkgxMHYyaDExYzEuNjMgMCAzLjA2NS0uNzkyIDMuOTc3LTJIMTcuMDIzek0xOCAyOWgtMi02djJoNi40NDdIMThoNy41NzhDMjUuODQ2IDMwLjM4NyAyNiAyOS43MTIgMjYgMjlIMTh6TTIxIDIwYzAgMCAwIC4wODMgMCAxcy0xIDEtMSAxaDQuOTc5Yy40NDEtLjU4NC43Ny0xLjI1Ny45MjEtMkgyMXpNMTIgMjBIMTdWMjJIMTJ6Ii8+PGc+PHBhdGggZmlsbD0iIzNmNTFiNSIgZD0iTTIxIDI4aDQuODg1Yy0uMTU2LS43MzgtLjQ2Ny0xLjQxOC0uOTA3LTJIMjBjMCAwIDEgLjE2NyAxIDFTMjEgMjggMjEgMjh6TTEyIDI2SDE3VjI4SDEyeiIvPjwvZz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>IBM</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="9">
|
||||
<name>Lenovo</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-lenovo.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSIxNiIgeT0iMTYiIGZpbGw9IiNmZjE3NDQiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTEuOTM1LDI2LjA2MmMwLjM3LD
|
||||
AuMzQxLDAuNzgyLDAuNDUsMS4yMjcsMC40NzhjMC42NDUsMC4wMzksMS4yMTctMC4xNTYsMS43MjQtMC41NDYgYzAuMTI0LTAuMDk2LDAuMTYzLTAuMTI2LDAuMTYzLTAuMTI2czAuNzc3LDAuNjA5LDEuMDk3LDAuODU1Yy0wLjI2MSwwLjMwOS0wLjU2NywwLjUyMS0wLjkwMSwwLjY5MiBjLTEuMTAzLDAuNTY1LTIuMjQ5LDAuNjg3LTMuNDI0LDAuMjY0Yy0xLjM0Ni0wLjQ4NS0yLjEzMS0xLjY5My0yLjA1OS0zLjExN2MwLjA3My0xLjQ0MSwxLjAwNS0yLjYwOCwyLjM5
|
||||
Mi0yLjk0NCBjMS4wNjQtMC4yNTcsMi4wODQtMC4xNDMsMi45OCwwLjUzOWMwLjY1MSwwLjQ5NiwxLjAwMSwxLjI4LDEuMTQ3LDIuMDY4YzAsMC0yLjU5NSwxLjExLTMuNzk1LDEuNjA2IEMxMi4zMTMsMjUuOTAzLDEyLjE0MSwyNS45NzUsMTEuOTM1LDI2LjA2MnogTTExLjQ3MiwyNC45MjhjMC45NjktMC40MDEsMS45MzUtMC44MDEsMi45MDEtMS4yMDEgYy0wLjMzNC0wLjcyMi0xLjA5Ni0xLjAxNy0xLjg2Ni0wLjc0OEMxMS43NTgsMjMuMjQsMTEuMjgsMjQuMTI0LD
|
||||
ExLjQ3MiwyNC45Mjh6Ii8+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTI3LjA3NiwyNy45MzRjLTEuNjMyLTAuMDE3LTIuOTU2LTEuMDY4LTMuMjYxLTIuNmMtMC4zNy0xLjg1MiwwLjk2OS0zLjYzMywyLjg2LTMuODA4IGMxLjI4MS0wLjExOCwyLjM3MywwLjI1NCwzLjE1NSwxLjNjMS40NTEsMS45NDEsMC4yMiw0Ljc1Ny0yLjE5Myw1LjA1NUMyNy40NSwyNy45MDUsMjcuMjYzLDI3LjkxNywyNy4wNzYsMjcuOTM0eiBNMjcuMTEsMjYuNDM0IGMwLjkyOSwwLjAwMiwxLjYy
|
||||
Mi0wLjcyMywxLjYyOC0xLjcwNGMwLjAwNi0wLjk3LTAuNzI0LTEuNzQyLTEuNjQ5LTEuNzQ1Yy0wLjkzNi0wLjAwMy0xLjYzMSwwLjczNC0xLjYyOCwxLjcyNiBDMjUuNDY1LDI1LjY3NSwyNi4xODksMjYuNDMyLDI3LjExLDI2LjQzNHoiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNNDAuNjI0LDI3LjkzNGMtMS42MzItMC4wMTctMi45NTYtMS4wNjgtMy4yNjEtMi42Yy0wLjM3LTEuODUyLDAuOTY5LTMuNjMzLDIuODYtMy44MDggYzEuMjgxLTAuMTE4LDIuMzczLDAuMj
|
||||
U0LDMuMTU1LDEuM2MxLjQ1MSwxLjk0MSwwLjIyLDQuNzU3LTIuMTkzLDUuMDU1QzQwLjk5OCwyNy45MDUsNDAuODExLDI3LjkxNyw0MC42MjQsMjcuOTM0eiBNNDAuNjU4LDI2LjQzNGMwLjkyOSwwLjAwMiwxLjYyMy0wLjcyMywxLjYyOC0xLjcwNGMwLjAwNi0wLjk3LTAuNzI0LTEuNzQyLTEuNjQ5LTEuNzQ1Yy0wLjkzNi0wLjAwMy0xLjYzMSwwLjczNC0xLjYyOCwxLjcyNiBDMzkuMDEzLDI1LjY3NSwzOS43MzcsMjYuNDMyLDQwLjY1OCwyNi40MzR6Ii8+PHBhdGgg
|
||||
ZmlsbD0iI2ZmZiIgZD0iTTIxLjM3NywyNy45ODdjMC0wLjA5NSwwLjAwMS0yLjU4NywwLTMuNjYzYy0wLjAwMS0wLjc1OS0wLjYwNS0xLjMyNy0xLjQxNC0xLjMzMSBjLTAuNzk0LTAuMDA1LTEuMzgzLDAuNTYtMS4zODQsMS4zMzJjLTAuMDAxLDEuMDc2LDAsMy42NzksMCwzLjY3OWwtMS43NDEsMC4wMDJsMC4wMDctNi4zNzhjMCwwLDEuMTY4LTAuMDE4LDEuNzIyLTAuMDE4IGMwLDAuMjY0LTAuMDA2LDAuODMyLTAuMDA2LDAuODMyczAuMTM4LTAuMTI4LDAuMTgxLT
|
||||
AuMTcxYzEuMTU3LTEuMTc0LDMuMjI2LTAuOTczLDQuMDMxLDAuMzkxIGMwLjIyMywwLjM3OCwwLjMzOCwwLjc4OSwwLjM0LDEuMjIzYzAuMDA4LDEuMjY0LDAuMDAzLDQuMTA0LDAuMDAzLDQuMTA0UzIxLjk2NCwyNy45ODcsMjEuMzc3LDI3Ljk4N3oiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMzAuMTY0LDIxLjYwOGMwLjY0MiwwLDEuOTY0LDAuMDE1LDEuOTY0LDAuMDE1czEuNDc4LDQuMDI0LDEuNTI2LDQuMTQ5IGMwLjExNS0wLjMxMSwxLjIwOC0zLjI5LDEuNTIx
|
||||
LTQuMTc0YzAuNjQ2LDAuMDE4LDEuMjg4LDAuMDEsMS45NywwLjAxYy0wLjAyOSwwLjA4NC0yLjU2Miw2LjM5OC0yLjU2Miw2LjM5OGwtMS44NzYtMC4wMDMgQzMxLjkwNSwyNi4wNDIsMzAuMTkxLDIxLjY5MiwzMC4xNjQsMjEuNjA4eiIvPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01Ljc2NywyNi4zOTNjMC4xMDQsMCwzLjg2OCwwLjAxMSwzLjg2OCwwLjAxMWwtMC4wMDIsMS41ODFMNCwyNy45ODl2LTguMDczaDEuNzcgQzUuNzcsMTkuOTE2LDUuNzY3LDI2LjI4NCw1Ljc2NywyNi4zOTN6Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Lenovo</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="10">
|
||||
<name>Razer</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-razer.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiM2NGRkMTciIGQ9Ik0yNiwyMGMwLjEsMCwwLjIsMCwwLjMsMGMwLjMtMC4xLDAuNS0wLjMsMC42LTAuNWMwLjEtMC4yLDAuMS0wLjUsMC4xLTA
|
||||
uOGMtMC4yLTAuNi0xLTEuOC0yLTIuNCBjMCwwLjcsMCwxLjMsMCwxLjljMCwwLjUsMCwxLDAsMS4yYzAuMSwwLjIsMC4zLDAuNCwwLjUsMC42QzI1LjcsMjAsMjUuOCwyMCwyNiwyMCBNMjkuNCwyM2MwLjcsMCwxLjYtMC4xLDIuMy0wLjUgYy0wLjUtMC4zLTEtMC42LTEuNS0wLjljLTAuNC0wLjMtMC45LTAuNi0xLjEtMC42YzAsMC0wLjEsMC0wLjEsMGMtMC4yLDAtMC40LDAuMS0wLjYsMC4yYy0wLjIsMC4xLTAuNCwwLjQtMC40LDAuNiBjLTAuMSwwLjUsMC4zLDEuM
|
||||
SwwLjgsMS4yQzI5LDIzLDI5LjIsMjMsMjkuNCwyMyBNMjMsMjQuOWMwLjUtMC4yLDEtMC40LDEuNS0wLjZjMC41LTAuMiwxLTAuNCwxLjItMC41YzAuMi0wLjIsMC4zLTAuNCwwLjMtMC43IGMwLTAuMy0wLjEtMC41LTAuMy0wLjdDMjUuNiwyMi4xLDI1LjMsMjIsMjUsMjJjLTAuMiwwLTAuNSwwLjEtMC43LDAuM0MyMy45LDIyLjYsMjMuMiwyMy44LDIzLDI0LjkgTTQxLjUsMSBjLTAuNywwLTEuNCwwLjUtMS41LDEuM2MwLDAsMCwwLDAsMEMzOS43LDIuMSwzOS40LDI
|
||||
sMzksMmMtMS43LDAtMi45LDAuMi0zLjYsMC43QzM0LjUsMy4yLDM0LDQuMSwzNCw1YzAsMC4xLDAsMC4xLDAsMC4yIEMzMy42LDUuMSwzMy4xLDUsMzIuNyw1Yy0xLjMsMC0yLjQsMC43LTMuMSwyQzI5LjIsNy43LDI5LDguNCwyOSw5LjJjMCwyLjYsMi4yLDQuNiw0LjUsNi42YzIuNywyLjQsMy45LDMuOCwzLjMsNC44IGMtMC4yLDAuNC0wLjQsMC40LTAuNCwwLjRjLTAuMSwwLTAuMiwwLTAuMywwYy0wLjEsMC0wLjMsMC0wLjUtMC4xYzAtMC42LTAuMS0xLjEtMC4yL
|
||||
TEuNmMtMC4yLTAuNi0wLjUtMS4yLTEtMS43IGMtMC40LTAuNS0xLTAuNy0xLjUtMC45Yy0wLjEsMC0wLjItMC4xLTAuNC0wLjFjLTAuMywwLTAuNywwLjItMC44LDAuNWMtMC4zLDAuNC0wLjIsMC45LDAuMiwxLjNjMC4yLDAuMiwwLjQsMC40LDAuNSwwLjYgYzAuMSwwLjIsMC4xLDAuMywwLjEsMC41Yy0wLjItMC4xLTAuNS0wLjMtMC43LTAuNGMtMC44LTAuNS0xLjQtMC45LTEuOS0xYzAtMC4xLTAuMS0wLjItMC4xLTAuM2MtMC41LTEuNS0yLjEtMy43LTQuMy00LjU
|
||||
gYy0xLTMuNS0zLjMtNC4zLTUuMS00LjNjLTQuNiwwLTUuNCw0LjktNiw4LjVjLTAuMiwxLjQtMC43LDQtMS4zLDQuNWMwLTAuMi0wLjEtMC41LTAuMS0xQzEzLDE5LjksMTIuNywxNywxMCwxNyBjLTEuNiwwLTIuNCwxLjEtMi44LDEuN2MtMC4yLTAuMi0wLjMtMC40LTAuNC0wLjZjLTAuMy0wLjYtMS0xLjEtMS43LTEuMUM1LjEsMTYuOSw1LDE2LjcsNSwxNi41QzUsMTUuNyw0LjMsMTUsMy41LDE1IGMtMC43LDAtMS4yLDAuNC0xLjQsMS4xQzEuNCwxNi4zLDEsMTYuO
|
||||
CwxLDE3LjVDMSwxOC4zLDEuNywxOSwyLjUsMTljMC4xLDAsMC4yLDAsMC4zLDBDMi45LDE5LjEsMywxOS4xLDMsMTkuMiBjMCwwLjIsMC4xLDAuNSwwLjIsMC43YzEsMS45LDIuNSwyLjcsMywyLjlDNi42LDIyLjksNywyMyw3LjQsMjNjMC43LDAsMS4zLTAuMiwxLjgtMC41QzkuNSwyNCwxMC4zLDI2LDEzLDI2IGM0LjEsMCw0LjktNC42LDUuNC03LjljMC42LTMuNCwxLTUuMSwyLTUuMWMwLjMsMCwwLjcsMCwxLjEsMC45Yy0wLjQsMC4yLTAuNywwLjUtMSwwLjhjLTA
|
||||
uNSwwLjUtMC44LDEuMS0xLDEuNyBjLTAuMiwwLjYtMC4xLDEuMi0wLjEsMS43YzAuMSwwLjUsMC41LDAuOCwwLjksMC45YzAsMCwwLDAsMC4xLDBjMC41LDAsMC45LTAuMywxLTAuOGMwLjEtMC4zLDAuMi0wLjYsMC4zLTAuOCBjMC4xLTAuMSwwLjItMC4yLDAuMy0wLjNjMCwwLjMsMCwwLjYsMCwwLjljMCwwLjksMCwxLjUsMC4xLDJjLTEsMS0yLjIsMy0yLjIsNS4yYy0xLjMsMC45LTIuMiwxLjktMi43LDNjLTAuNSwxLjItMC41LDIuNSwwLjEsMy43IGMwLjgsMS45L
|
||||
DIuNSwyLjksNC45LDIuOWMxLjgsMCwzLjgtMC41LDUuNy0xLjFjMS43LTAuNSwzLjMtMC45LDQuMy0wLjljMC4yLDAsMC40LDAsMC42LDAuMWMtMC4yLDAuMS0wLjUsMC4zLTEsMC42IGMtMS4xLDAuNi0zLjYsMi0yLjUsNC41YzAuNywxLjYsMi41LDEuOCwzLjYsMS44bDAuMSwwYzAsMCwwLDAsMCwwYy0wLjEsMC4yLTAuMiwwLjMtMC40LDAuNmMtMC40LDAuNC0wLjYsMC44LTAuNiwxLjMgYy0wLjEsMC0wLjMsMC4xLTAuNSwwLjFjLTAuOCwwLTEuNSwwLjctMS41LDE
|
||||
uNWMwLDAuNywwLjQsMS4yLDEuMSwxLjRjMC4yLDAuNiwwLjgsMS4xLDEuNCwxLjFjMC44LDAsMS41LTAuNywxLjUtMS41bDAtMC4zIGMwLjEtMC4xLDAuMS0wLjEsMC4yLTAuMmMwLjUsMCwwLjktMC4yLDEuMi0wLjZjMS43LTEuNywxLjYtMy4zLDEuNi00LjFjMC0xLjMtMC45LTIuNC0yLTIuOWMxLjMtMC45LDIuNy0yLjUsMS42LTQuOCBjLTAuOC0xLjctMi4yLTIuNi00LjQtMi42Yy0xLjcsMC0zLjUsMC41LTUuMywxYy0xLjgsMC41LTMuNCwwLjktNC42LDAuOWMtM
|
||||
SwwLTEuMS0wLjMtMS4yLTAuNUMyMSwzMC4xLDIxLDI5LjksMjEsMjkuOCBjMC4xLTAuMiwwLjMtMC41LDAuOC0wLjljMC40LDAuNCwwLjksMC42LDEuMywwLjhjMC40LDAuMiwwLjksMC4zLDEuNCwwLjNjMC4yLDAsMC40LDAsMC42LTAuMWMwLjYtMC4xLDEuMi0wLjQsMS42LTAuNyBjMC40LTAuMywwLjYtMC44LDAuNC0xLjJjLTAuMS0wLjQtMC41LTAuNi0wLjktMC42Yy0wLjEsMC0wLjEsMC0wLjIsMGMtMC4yLDAtMC40LDAuMS0wLjYsMC4xYy0wLjEsMC0wLjIsMC0
|
||||
wLjIsMCBjLTAuMiwwLTAuMy0wLjEtMC40LTAuMmMwLjItMC4xLDAuNS0wLjIsMC43LTAuM2MxLTAuNCwxLjYtMC42LDItMWMwLjEtMC4xLDAuMS0wLjEsMC4yLTAuMmMwLjEsMCwwLjMsMC4xLDAuNCwwLjEgQzI4LjYsMjYsMjksMjYsMjkuNCwyNmMwLjksMCwyLjktMC4xLDQuNS0xLjRjMC44LDAuMiwxLjUsMC40LDIuMiwwLjRjMC40LDAsMC45LTAuMSwxLjMtMC4yYzEuMi0wLjMsMi4zLTEuMSwyLjktMi4zIGMyLjItMy45LTEuMy03LjEtNC4yLTkuN0MzNC45LDExL
|
||||
jcsMzMsMTAsMzMsOS4xYzAsMCwwLDAsMC0wLjFjMC4yLDAuMSwwLjQsMC4xLDAuOCwwLjNjMC42LDAuMiwxLjUsMC42LDIuNCwwLjYgYzEuMSwwLDEuOS0wLjUsMi41LTEuNWMwLjYtMSwwLjQtMS45LDAuMS0yLjVjMC4xLDAsMC4yLDAsMC4zLDBjMC42LDAsMS4yLTAuMywxLjYtMC44QzQxLjMsNS4xLDQyLDUsNDIuNSw1QzQzLjMsNSw0NCw0LjMsNDQsMy41IGMwLTAuNy0wLjQtMS4yLTEuMS0xLjRDNDIuNywxLjQsNDIuMiwxLDQxLjUsMUw0MS41LDF6Ii8+PHBhdGg
|
||||
gZD0iTTEzLDI1Yy0yLjYsMC0yLjgtMi41LTIuOS0zLjhjMC0wLjMtMC4xLTAuOS0wLjItMS4xYy0wLjEsMC4xLTAuMSwwLjItMC4yLDAuM2MtMC4xLDAuMS0wLjIsMC4zLTAuMywwLjUgYy0wLjYsMS0xLjksMS40LTIuOSwxYy0wLjgtMC4zLTEuOC0xLjEtMi41LTIuNGMtMC4yLTAuNSwwLTEuMSwwLjQtMS4zYzAuNS0wLjIsMS4xLDAsMS4zLDAuNGMwLjQsMC43LDEsMS4zLDEuNCwxLjQgYzAuMiwwLjEsMC40LDAsMC41LTAuMmMwLjEtMC4xLDAuMi0wLjMsMC4yLTAuN
|
||||
GMwLjMtMC42LDAuOC0xLjQsMi0xLjRjMS44LDAsMiwxLjksMi4xLDNjMC4yLDEuOCwwLjQsMiwwLjksMiBjMS41LDAsMS45LTIuMSwyLjUtNS40YzAuNi0zLjQsMS4zLTcuNiw1LTcuNmMyLjcsMCwzLjgsMS45LDQuMiw0LjFjMi4xLDAuNCwzLjcsMi43LDQuMSw0YzAuMiwwLjgsMC4yLDEuNi0wLjIsMi4zcy0xLDEuMi0xLjcsMS41IGMtMC44LDAuMi0xLjYsMC4yLTIuMy0wLjJjLTAuNy0wLjQtMS4yLTEtMS41LTEuN0MyMywxOS42LDIzLDE5LjEsMjMsMTguMmMwLTM
|
||||
uNy0wLjQtNi4yLTIuNi02LjJjLTEuOSwwLTIuNCwyLjQtMyw2IEMxNi45LDIxLjMsMTYuMywyNSwxMywyNXogTTI1LDE2LjNjMCwwLjcsMCwxLjMsMCwxLjljMCwwLjUsMCwxLDAsMS4yYzAuMSwwLjIsMC4zLDAuNCwwLjUsMC42YzAuMiwwLjEsMC41LDAuMSwwLjgsMC4xIGMwLjMtMC4xLDAuNS0wLjMsMC42LTAuNWMwLjEtMC4yLDAuMS0wLjUsMC4xLTAuOEMyNi44LDE4LjEsMjYsMTYuOSwyNSwxNi4zeiIvPjxwYXRoIGQ9Ik0yNCAxNmMtLjMtLjEtLjctLjEtMS4xL
|
||||
S4xLS40IDAtLjcuMS0xLjEuMi0uMy4xLS42LjQtLjkuNy0uMy4zLS40LjctLjUgMS4xLS4xLS40LS4xLS45IDAtMS40LjEtLjUuNC0uOS43LTEuMy40LS40LjgtLjcgMS4yLS45LjUtLjIuOS0uNCAxLjUtLjVsLjEgMGMuNi0uMSAxLjEuMyAxLjIuOFMyNSAxNS45IDI0LjUgMTZDMjQuMyAxNiAyNC4xIDE2IDI0IDE2ek0zLjUgMTguMWMtLjEgMC0uMSAwLS4yIDBDMy4xIDE4IDIuOCAxOCAyLjUgMTggMi4yIDE4IDIgMTcuOCAyIDE3LjVTMi4yIDE3IDIuNSAxN2MuNSA
|
||||
wIC44IDAgMS4yLjJDNCAxNy4zIDQuMSAxNy42IDQgMTcuOCAzLjkgMTggMy43IDE4LjEgMy41IDE4LjF6Ii8+PHBhdGggZD0iTTQuNSAxOWMtLjEgMC0uMSAwLS4yLS4xLS4xIDAtMS4zLS43LTEuMy0yLjRDMyAxNi4yIDMuMiAxNiAzLjUgMTZTNCAxNi4yIDQgMTYuNWMwIDEuMS43IDEuNS43IDEuNi4yLjEuMy40LjIuN0M0LjkgMTguOSA0LjcgMTkgNC41IDE5ek0zNCA0M2MtLjMgMC0uNS0uMS0uNy0uMy0uNC0uNC0uNC0xIDAtMS40LjctLjcuNy0xLjQuNy0xLjggM
|
||||
C0uMi0uMi0uMy0uNC0uNC0uMiAwLS40IDAtLjctLjEtMS0uMS0yLjMtLjItMi44LTEuMi0uNy0xLjcgMS0yLjYgMi4xLTMuMiAxLjctLjkgMS45LTEuMiAxLjYtMS44LS42LTEuMy0yLjgtLjgtNi4yLjEtMy43IDEtNy44IDIuMi05LjMtMS4zLS40LTEtLjUtMi0uMS0yLjkuNS0xLjIgMS42LTIuMSAyLjgtMi44LS4zLTIuMSAxLTQuMyAyLTUuMSAxLjItMS4xIDMuMS0xIDQuMi4yIDEuMSAxLjIgMSAzLjEtLjIgNC4yLS4zLjMtLjguNS0xLjcuOS0uNi4zLTEuNS42LTI
|
||||
uMyAxLS4xLjEtLjIuMi0uMy4yLS4xIDAtLjEuMS0uMi4xLTEgLjYtMiAxLjMtMi4zIDIuMS0uMi40LS4yLjkuMSAxLjQuOCAxLjcgMy4zIDEuMiA3IC4yIDMuNC0uOSA3LjItMiA4LjYgMSAxIDIuMy0xLjIgMy42LTIuNSA0LjMtLjMuMi0uOC40LTEgLjYuMyAwIC42LjEuOS4xLjMgMCAuNiAwIC44LjEgMS4yLjIgMi4xIDEuMiAyLjEgMi4zIDAgLjYuMSAyLTEuMyAzLjNDMzQuNSA0Mi45IDM0LjMgNDMgMzQgNDN6TTI1IDIyYy0uMiAwLS41LjEtLjcuMy0uNC40LTEuM
|
||||
iAxLjUtMS4zIDIuNi41LS4yIDEtLjQgMS41LS42LjUtLjIgMS0uNCAxLjItLjUuNC0uMy40LTEgMC0xLjRDMjUuNSAyMi4xIDI1LjMgMjIgMjUgMjJ6Ii8+PHBhdGggZD0iTTIzLjIgMjYuMWMwIC4zLjIuNy4zIDEgLjIuMy4zLjYuNi45LjIuMy42LjQgMSAuNS40LjEuOC4xIDEuMiAwLS40LjItLjguNS0xLjIuNS0uNS4xLTEgMC0xLjUtLjItLjUtLjItLjktLjUtMS4zLS44LS40LS40LS43LS43LTEtMS4ybC0uMS0uMWMtLjMtLjUtLjEtMS4xLjQtMS40LjUtLjMgMS4
|
||||
xLS4xIDEuNC40QzIzLjIgMjUuOCAyMy4yIDI1LjkgMjMuMiAyNi4xek0zMi41IDQ1Yy0uMyAwLS41LS4yLS41LS41bDAtLjVjMC0uMiAwLS40IDAtLjYgMC0uMy4zLS41LjUtLjUuMyAwIC41LjIuNS41IDAgLjIgMCAuMyAwIC41bDAgLjVDMzMgNDQuOCAzMi44IDQ1IDMyLjUgNDV6Ii8+PHBhdGggZD0iTTMxLjUgNDRjLS4zIDAtLjUtLjItLjUtLjVzLjItLjUuNS0uNWMxLjEgMCAxLjUtLjcgMS42LS43LjEtLjIuNC0uMy43LS4yLjIuMS4zLjQuMi43QzMzLjkgNDIuO
|
||||
CAzMy4zIDQ0IDMxLjUgNDR6TTI5LjQgMjVjLS40IDAtLjcgMC0xLS4xLTEuNi0uMy0yLjctMS45LTIuNC0zLjUuMi0uOC42LTEuNSAxLjMtMS45LjctLjQgMS41LS42IDIuMy0uNS40LjEuOC4zIDEuNy45LjYuNCAxLjQuOCAyLjIgMS4yIDAgMCAwIDAgMCAwIC4yIDAgLjMgMCAuNS4xLjEuMS4yLjEuMy4yLjkuNCAxLjguNiAyLjQuNC40LS4xLjgtLjQgMS4xLS45IDEtMS43LS44LTMuNS0zLjUtNkMzMiAxMy4xIDMwIDExLjMgMzAgOS4yYzAtLjYuMS0xLjIuNC0xLjd
|
||||
DMzEuMSA2LjMgMzIgNiAzMi43IDZjLjggMCAxLjYuMyAyLjMuNi4yLjEuNi4yLjguMyAwIDAgMCAwIDAgMC0uMi0uMi0uMy0uNC0uNS0uN0MzNS4xIDUuOCAzNSA1LjQgMzUgNWMwLS42LjMtMS4xLjktMS41QzM2LjYgMy4xIDM4LjEgMyAzOSAzYy42IDAgMSAuNCAxIDFzLS40IDEtMSAxYy0uOCAwLTEuNi4xLTIgLjIgMCAwIDAgMCAwIDAgLjEuMi4yLjQuMy41QzM3LjggNi4yIDM4LjMgNyAzNy44IDhjLS45IDEuNi0yLjUuOS0zLjYuNEMzMy43IDguMiAzMy4xIDggM
|
||||
zIuNyA4Yy0uMSAwLS4zIDAtLjYuNEMzMiA4LjYgMzIgOC45IDMyIDkuMWMwIDEuMyAxLjggMi45IDMuNSA0LjQgMi43IDIuNCA1LjcgNS4yIDQgOC40LS41IDEtMS4zIDEuNi0yLjMgMS45LTEuMS4zLTIuMy4xLTMuNC0uNEMzMi42IDI0LjYgMzAuOCAyNSAyOS40IDI1ek0yOSAyMWMtLjIgMC0uNC4xLS42LjItLjIuMS0uNC40LS40LjYtLjEuNS4zIDEuMS44IDEuMi41LjEgMS45LjEgMi45LS41LS41LS4zLTEtLjYtMS41LS45LS40LS4zLS45LS42LTEuMS0uNkMyOS4
|
||||
xIDIxIDI5LjEgMjEgMjkgMjF6Ii8+PHBhdGggZD0iTTMyLjYgMjEuN2MuMi0uMi40LS42LjYtLjkuMi0uMy4zLS43LjMtMS4xIDAtLjQgMC0uNy0uMi0xLjEtLjEtLjQtLjQtLjctLjgtMSAuNC4yLjguMyAxLjIuNy4zLjMuNi44LjggMS4zLjEuNS4yIDEgLjIgMS41IDAgLjUtLjEgMS0uMyAxLjVsMCAuMWMtLjIuNS0uOC44LTEuMy42cy0uOC0uOC0uNi0xLjNDMzIuNCAyMS45IDMyLjUgMjEuOCAzMi42IDIxLjd6TTQwLjggNC4xYy0uMiAwLS40LS4yLS41LS40IDAtL
|
||||
jMuMS0uNS40LS42LjEgMCAuMi0uMi4yLS42QzQxIDIuMiA0MS4yIDIgNDEuNSAyUzQyIDIuMiA0MiAyLjVDNDIgMy4zIDQxLjUgNCA0MC44IDQuMSA0MC45IDQuMSA0MC45IDQuMSA0MC44IDQuMXoiLz48cGF0aCBkPSJNMzksNC41Yy0wLjIsMC0wLjQtMC4yLTAuNS0wLjRjLTAuMS0wLjMsMC4xLTAuNSwwLjQtMC42QzM5LDMuNSw0MSwzLDQyLjUsM0M0Mi44LDMsNDMsMy4yLDQzLDMuNVM0Mi44LDQsNDIuNSw0IGMtMS40LDAtMy40LDAuNS0zLjQsMC41QzM5LjEsNC41LDM5LDQuNSwzOSw0LjV6Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Razer</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="11">
|
||||
<name>Samsung</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-samsung.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwZDQ3YTEiIGQ9Ik00Ny45NywxOS44MjZjMC42NTQsMy43NDctOS41NDcsOC42NTUtMjIuNzg4LDEwLjk2Yy0xMy4yMzgsMi4zMDYtMjQuN
|
||||
SwxLjEzNi0yNS4xNTMtMi42MTMgYy0wLjY1My0zLjc0Nyw5LjU1MS04LjY1NCwyMi43OS0xMC45NThDMzYuMDU5LDE0LjkwNyw0Ny4zMTgsMTYuMDc4LDQ3Ljk3LDE5LjgyNnoiLz48cG9seWdvbiBmaWxsPSIjZmFmYWZhIiBwb2ludHM9IjM1LjUxLDI1LjM4OCAzNS40NDIsMjEuNDkyIDM2LjY3MSwyMS40OTIgMzYuNjcxLDI2LjQwMyAzNC45MDUsMjYuNDAzIDMzLjY3OCwyMi4zNzMgMzMuNjUyLDIyLjM3MyAzMy43MiwyNi40MDMgMzIuNDk5LDI2LjQwMyAzMi40OTk
|
||||
sMjEuNDkyIDM0LjM0MiwyMS40OTIgMzUuNDgzLDI1LjM4OCIvPjxwb2x5Z29uIGZpbGw9IiNmYWZhZmEiIHBvaW50cz0iMTMuMTc3LDIxLjk1MiAxMi40OTcsMjYuNDU1IDExLjE1NywyNi40NTUgMTIuMDc2LDIxLjQ5MiAxNC4yODQsMjEuNDkyIDE1LjIwMSwyNi40NTUgMTMuODY1LDI2LjQ1NSAxMy4yMDQsMjEuOTUyIi8+PHBvbHlnb24gZmlsbD0iI2ZhZmFmYSIgcG9pbnRzPSIxOC45NjQsMjUuMjg2IDE5LjU3NywyMS40OTIgMjEuNjAxLDIxLjQ5MiAyMS43MDgsM
|
||||
jYuNDU1IDIwLjQ2OCwyNi40NTUgMjAuNDM1LDIxLjk5MyAyMC40MDksMjEuOTkzIDE5LjU4LDI2LjQ1NSAxOC4zMjEsMjYuNDU1IDE3LjQ5LDIxLjk5MyAxNy40NjQsMjEuOTkzIDE3LjQzMywyNi40NTUgMTYuMTksMjYuNDU1IDE2LjMsMjEuNDkyIDE4LjMyNSwyMS40OTIgMTguOTM3LDI1LjI4NiIvPjxwYXRoIGZpbGw9IiNmYWZhZmEiIGQ9Ik05LjA2NywyNS4wNTVjMC4wNDksMC4xMiwwLjAzNCwwLjI3NSwwLjAxMSwwLjM2OGMtMC4wNDIsMC4xNjUtMC4xNTQsMC4
|
||||
zMzMtMC40ODMsMC4zMzMgYy0wLjMxMiwwLTAuNS0wLjE3OS0wLjUtMC40NXYtMC40OEg2Ljc2M0w2Ljc2MiwyNS4yMWMwLDEuMTA2LDAuODcxLDEuNDQxLDEuODA1LDEuNDQxYzAuODk4LDAsMS42MzctMC4zMDcsMS43NTQtMS4xMzQgYzAuMDYxLTAuNDI5LDAuMDE1LTAuNzA5LTAuMDA1LTAuODE2Yy0wLjIwOS0xLjAzOS0yLjA5My0xLjM0OS0yLjIzMy0xLjkzYy0wLjAyNC0wLjA5OS0wLjAxNy0wLjIwNS0wLjAwNS0wLjI2MiBjMC4wMzUtMC4xNTgsMC4xNDMtMC4zM
|
||||
zIsMC40NTMtMC4zMzJjMC4yOSwwLDAuNDYxLDAuMTgsMC40NjEsMC40NWMwLDAuMDkxLDAsMC4zMDcsMCwwLjMwN2gxLjIzN3YtMC4zNDggYzAtMS4wODEtMC45Ny0xLjI1LTEuNjczLTEuMjVjLTAuODgzLDAtMS42MDQsMC4yOTItMS43MzYsMS4wOTljLTAuMDM2LDAuMjIzLTAuMDQxLDAuNDIyLDAuMDExLDAuNjcxIEM3LjA0OSwyNC4xMTgsOC44MTEsMjQuNDEyLDkuMDY3LDI1LjA1NXoiLz48cGF0aCBmaWxsPSIjZmFmYWZhIiBkPSJNMjUuMjA0LDI1LjA0NmMwLjA
|
||||
0OSwwLjExOSwwLjAzMywwLjI3LDAuMDExLDAuMzYzYy0wLjA0MSwwLjE2NS0wLjE1MiwwLjMzLTAuNDc5LDAuMzMgYy0wLjMwNywwLTAuNDk0LTAuMTc5LTAuNDk0LTAuNDQ0bC0wLjAwMS0wLjQ3NmgtMS4zMThsLTAuMDAyLDAuMzc5YzAsMS4wOTUsMC44NjMsMS40MjYsMS43ODcsMS40MjYgYzAuODg4LDAsMS42Mi0wLjMwMywxLjczNi0xLjEyMmMwLjA2MS0wLjQyNiwwLjAxOC0wLjcwMi0wLjAwNC0wLjgwN2MtMC4yMDgtMS4wMjktMi4wNzMtMS4zMzYtMi4yMTEtM
|
||||
S45MTIgYy0wLjAyNC0wLjA5OS0wLjAxNy0wLjIwMy0wLjAwNS0wLjI1N2MwLjAzNi0wLjE2LDAuMTQyLTAuMzI5LDAuNDQ5LTAuMzI5YzAuMjg4LDAsMC40NTUsMC4xNzUsMC40NTUsMC40NDQgYzAsMC4wOSwwLDAuMzA0LDAsMC4zMDRoMS4yMjh2LTAuMzQ1YzAtMS4wNy0wLjk2Mi0xLjIzNy0xLjY1OS0xLjIzN2MtMC44NzMsMC0xLjU4OCwwLjI4OC0xLjcxNywxLjA5IGMtMC4wMzYsMC4yMi0wLjA0LDAuNDE1LDAuMDEyLDAuNjYzQzIzLjIwNiwyNC4xMTgsMjQuOTU
|
||||
xLDI0LjQxLDI1LjIwNCwyNS4wNDZ6Ii8+PHBhdGggZmlsbD0iI2ZhZmFmYSIgZD0iTTI5LjM3MiwyNS43MTNjMC4zNDQsMCwwLjQ1MS0wLjIzOCwwLjQ3NS0wLjM2YzAuMDEtMC4wNTQsMC4wMTMtMC4xMjUsMC4wMTItMC4xOVYyMS40OWgxLjI1NSB2My41NmMwLjAwMywwLjA5MS0wLjAwNiwwLjI3OS0wLjAxMSwwLjMyNWMtMC4wODgsMC45MjctMC44MjEsMS4yMjctMS43MzIsMS4yMjdjLTAuOTEzLDAtMS42NDYtMC4zMDEtMS43MzMtMS4yMjcgYy0wLjAwNC0wLjA0N
|
||||
y0wLjAxMy0wLjIzNS0wLjAxMS0wLjMyNXYtMy41NmgxLjI1NHYzLjY3MmMwLDAuMDY0LDAuMDAyLDAuMTM3LDAuMDEyLDAuMTkgQzI4LjkyMSwyNS40NzMsMjkuMDI1LDI1LjcxMywyOS4zNzIsMjUuNzEzeiIvPjxwYXRoIGZpbGw9IiNmYWZhZmEiIGQ9Ik0zOS43MjUsMjUuNjZjMC4zNTksMCwwLjQ4NS0wLjIyNywwLjUwOC0wLjM1OWMwLjAwOS0wLjA1NywwLjAxMi0wLjEyNiwwLjAxMS0wLjE4OXYtMC43MiBoLTAuNTA5di0wLjcyNGgxLjc2VjI1Yy0wLjAwMSwwLjA
|
||||
5My0wLjAwMywwLjE2Mi0wLjAxOCwwLjMyN2MtMC4wODIsMC45MDMtMC44NjYsMS4yMjUtMS43NDUsMS4yMjUgYy0wLjg4MSwwLTEuNjYzLTAuMzIyLTEuNzQ3LTEuMjI1Yy0wLjAxNC0wLjE2Ni0wLjAxNi0wLjIzNC0wLjAxOC0wLjMyN2wwLjAwMS0yLjA4OWMwLTAuMDg4LDAuMDExLTAuMjQ0LDAuMDIxLTAuMzI3IGMwLjExLTAuOTI4LDAuODYyLTEuMjI2LDEuNzQzLTEuMjI2YzAuODgsMCwxLjY1MSwwLjI5NywxLjc0MiwxLjIyNmMwLjAxNiwwLjE1OCwwLjAxMSwwL
|
||||
jMyNywwLjAxMSwwLjMyN3YwLjE2NmgtMS4yNTF2LTAuMjc4IGMwLjAwMSwwLjAwMS0wLjAwMi0wLjExOC0wLjAxNi0wLjE4OWMtMC4wMjEtMC4xMS0wLjExNi0wLjM2Mi0wLjQ5NS0wLjM2MmMtMC4zNjIsMC0wLjQ2NywwLjIzOC0wLjQ5NCwwLjM2MiBjLTAuMDE1LDAuMDY1LTAuMDIxLDAuMTU0LTAuMDIxLDAuMjM0djIuMjdjLTAuMDAxLDAuMDYzLDAuMDAzLDAuMTMyLDAuMDEzLDAuMTg5QzM5LjI0MSwyNS40MzMsMzkuMzY2LDI1LjY2LDM5LjcyNSwyNS42NnoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Samsung</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="12">
|
||||
<name>Sony</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icon-sony.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmc6c3ZnIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOnN2Zz0iaH
|
||||
R0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjgwIDEyODAiIHZlcnNpb249IjEuMSIgaWQ9InN2ZzEiIHNvZGlwb2RpOmRvY25hbWU9Imljb24tc29ueS5zdmciIGlua3NjYXBlOnZlcnNpb249IjEuNC4zICgwZDE1Zjc1MDQyLCAyMDI1LTEyLTI1KSIgd2lkdGg9IjEyODAiIGhlaWdodD0iMTI4MCI+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2aWV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9y
|
||||
ZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgaW5rc2NhcGU6em9vbT0iMC42MzQxODYzOSIgaW5rc2NhcGU6Y3g9Ii00NjIuNzk3NjkiIGlua3NjYXBlOmN5PSIyMjUuNDg1NzYiIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MC
|
||||
IgaW5rc2NhcGU6d2luZG93LXg9IjAiIGlua3NjYXBlOndpbmRvdy15PSIwIiBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJnNCIgc2hvd2d1aWRlcz0idHJ1ZSI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSIxNzMuMzcxMDgsNjQxLjg5MDI0IiBvcmllbnRhdGlvbj0iMCwtMSIgaWQ9Imd1aWRlMSIgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIvPjwvc29kaXBvZGk6bmFtZWR2aWV3Pjxzdmc6ZGVmcyBpZD0iZGVmczEi
|
||||
Lz48c3ZnOmcgaWQ9IkxheWVyXzIiPjxzdmc6ZyBpZD0iZzQiIGlua3NjYXBlOmxhYmVsPSJsb2dvIj48c3ZnOnBhdGggZD0ibSA0NTYuMDEyOSw3NTEuNzQ2ODcgYyAtNDYuNDEyNzksMCAtODkuNDIwNzksLTEzLjgyMzk5IC0xMTguMDkyNzksLTM5LjYwMzE5IGEgOTYuODk1OTg5LDk2Ljg5NTk4OSAwIDAgMSAtMzIuMTI3OTksLTczLjE5MDM5IDk4LjMyOTU4OCw5OC4zMjk1ODggMCAwIDEgMzIuMTI3OTksLTcyLjkzNDQgYyAyNi42MjQsLTI0LjE5MTk5IDczLjcyOC
|
||||
wtMzkuNTUxOTkgMTE4LjA5Mjc5LC0zOS41NTE5OSA0OS4wNzUxOSwwIDg4LjM3MTE5LDEyLjM2NDggMTE4LjM5OTk5LDM5LjYwMzE5IGEgOTcuNDA3OTg5LDk3LjQwNzk4OSAwIDAgMSAzMS42OTI3OSw3Mi44ODMyIDEwMS41Mjk1OSwxMDEuNTI5NTkgMCAwIDEgLTMxLjY5Mjc5LDczLjE5MDM5IGMgLTI3Ljk4MDgsMjUuOTMyOCAtNzEuOTEwNCwzOS42MDMxOSAtMTE4LjM5OTk5LDM5LjYwMzE5IHYgLTI5LjY0NDc5IGMgMjQuNjAxNiwwIDQ3LjQzNjc5LC04LjQ5OTIg
|
||||
NjMuMzg1NTksLTI0LjM3MTIgMTUuOTQ4OCwtMTUuODcyIDIzLjE5MzYsLTM1LjEyMzIgMjMuMTkzNiwtNTguODc5OTkgMCwtMjIuNjgxNiAtNy45NjE2LC00My44Nzg0IC0yMy4xOTM2LC01OC44OCAtMTUuNzQ0LC0xNS40ODc5OSAtMzkuMTE2NzksLTI0LjIxNzU5IC02My4zODU1OSwtMjQuMjE3NTkgLTI0LjI2ODgsMCAtNDcuNzQzOTksOC42NTI4IC02My40ODc5OSwyNC4yMTc1OSAtMTUuMTgwOCwxNS4wMjcyIC0yMy4wNCwzNi4zMDA4IC0yMy4wNCw1OC44OCBhID
|
||||
gyLjM1NTE5LDgyLjM1NTE5IDAgMCAwIDIzLjA0LDU4Ljg3OTk5IGMgMTUuNzQ0LDE1LjY5MjggMzkuMDY1NTksMjQuMzcxMiA2My40ODc5OSwyNC4zNzEyIHogTSAxMTcuMTIwMTQsNTI2LjQ2NjkgYyAtMjQuODA2MzkyLDAgLTUyLjk5MTk4OSw0LjY1OTIgLTc2Ljc5OTk4NiwxNS4zNiBDIDE4LjA5OTM1NSw1NTEuNzU5NyAxLjU3NWUtNCw1NjcuNzA4NDkgMS41NzVlLTQsNTk0LjE1MzI5IGEgNTQuMjIwNzk0LDU0LjIyMDc5NCAwIDAgMCAxNC43MTk5OTg1LDM3LjI3
|
||||
MzYgYyA2LjQyNTU5OSw1LjkzOTIgMTYuNzkzNTk5LDE2LjAyNTYgNDMuODc4Mzk2LDIxLjk2NDggMTIuMTA4Nzk4LDIuNTU5OTkgMzcuOTkwMzk1LDYuNjgxNTkgNjMuNzY5NTg4LDkuMzk1MTkgMjUuNzc5MiwyLjcxMzYgNTAuNzY0OCw1LjEyIDYxLjAwNDgsNy44NTkyIDguMTQwOCwyLjA3MzYgMjEuODM2NzksNC44ODk2IDIxLjgzNjc5LDIwLjI0OTYgMCwxNS4zNiAtMTQuNDEyNzksMTkuOTY4IC0xNi45MjE1OSwyMC45NjY0IC0yLjUwODgsMC45OTg0IC0xOS44MT
|
||||
Q0LDguOTM0NCAtNTAuODkyOCw4LjkzNDQgYSAyMTYuNDIyMzcsMjE2LjQyMjM3IDAgMCAxIC02MC41OTUxOSwtMTAuNDE5MiBjIC0xMS41OTY3OTksLTQuMTQ3MiAtMjMuNzU2Nzk3LC05LjYgLTM1LjA5NzU5NiwtMjMuNDQ5NiBhIDQwLjI2ODc5NSw0MC4yNjg3OTUgMCAwIDEgLTcuMjk1OTk5LC0yMi4yMjA4IEggNi4yNDY1NTY3IHYgNzguODQ3OTkgSCAzNy41Mjk3NTQgdiAtMTAuNjc1MTkgYSA0LjQ1NDM5OTUsNC40NTQzOTk1IDAgMCAxIDYuNzU4NCwtMy44NCAy
|
||||
NDYuNDI1NTcsMjQ2LjQyNTU3IDAgMCAwIDQ1Ljc3Mjc5NCwxNC43OTY3OSBjIDE2LjQzNTIwMiwzLjQzMDQgMjcuMDU5MTkyLDUuOTEzNiA0Ny40ODc5OTIsNS45MTM2IGEgMjAyLjYyMzk4LDIwMi42MjM5OCAwIDAgMCA2My42NDE2LC04Ljk4NTYgMTExLjA3ODM5LDExMS4wNzgzOSAwIDAgMCAzNy44MTExOSwtMTguNjYyMzkgNTEuODE0Mzk0LDUxLjgxNDM5NCAwIDAgMCAyMC4yNDk1OSwtNDEuNDk3NiA1OC4wNjA3OTMsNTguMDYwNzkzIDAgMCAwIC0xNi4zNTgzOS
|
||||
wtNDAuODA2MzkgNzIuMDEyNzkyLDcyLjAxMjc5MiAwIDAgMCAtMjAuMTcyOCwtMTMuNzk4NCAxNDguNjA3OTgsMTQ4LjYwNzk4IDAgMCAwIC0yNC44ODMxOSwtOC42Nzg0IGMgLTE2LjIzMDQsLTMuOTY4IC01Mi42ODQ4LC04LjkzNDQgLTcwLjExODQsLTEwLjY3NTIgLTE4LjI3ODM5LC0xLjg5NDQgLTQ5Ljk5Njc5LC00LjUzMTIgLTYyLjY2ODc4OSwtOC40NDggLTMuODM5OTk5LC0xLjIwMzIgLTExLjY3MzU5OSwtNC45MTUyIC0xMS42NzM1OTksLTE0LjAwMzIgMCwt
|
||||
Ni40NzY4IDMuNTg0LC0xMS45NTUyIDEwLjY0OTU5OSwtMTYuMzg0IEMgNzUuMjY0MTUsNTYwLjc3MDkgOTcuOTQ1NzQ3LDU1Ni4zOTMzIDEyMS42MDAxNCw1NTYuMzkzMyBhIDE2Ni45ODg3OCwxNjYuOTg4NzggMCAwIDEgNjYuNzEzNiwxMy4wMzAzOSA3Mi44NTc1OTEsNzIuODU3NTkxIDAgMCAxIDE1Ljg3MTk5LDkuNDcyIDQ3LjcxODM5NCw0Ny43MTgzOTQgMCAwIDEgMTUuNjQxNiwyNi4xNjMyIGggMjUuMjY3MiBWIDUzNi40MjUzIGggLTI4LjE2IHYgNy45NjE2IG
|
||||
MgMCwyLjU2IC0yLjU2LDUuOTM5MiAtNy42OCwzLjE0ODggLTEyLjY5NzU5LC02LjYwNDggLTQ4LjM4Mzk5LC0yMC44ODk2IC05Mi4xMzQzOSwtMjEuMDY4OCB6IG0gNjE4LjIxNDMzLDEyLjU5NTIgMTM3LjYyNTU4LDEyNC4xODU1OCAtMS40MDgsLTgzLjYwOTU5IGMgLTAuMTUzNiwtMTAuOTgyNCAtMi4xNTA0LC0xNS41NjQ3OSAtMTQuMDI4OCwtMTUuNTY0NzkgaCAtMjUuODU1OTkgdiAtMjUuMDExMiBoIDExNy43NTk5OCB2IDI1LjAxMTIgaCAtMjUuMjY3MTkgYyAt
|
||||
MTIuMDgzMiwwIC0xMi44LDMuODkxMTkgLTEzLjAwNDgsMTUuNTY0NzkgbCAyLjEyNDgsMTU5Ljc2OTU5IGggLTQwLjMyIEwgNzE0LjQxOTI3LDU5Ny45NDIwOSB2IDEwMC4zNzc1OSBjIDAuMTI4LDEwLjkzMTIgMC42NCwxNi4wNzY4IDExLjg3ODQsMTYuMDc2OCBoIDI4LjE2IHYgMjUuMDExMiBIIDYzOS4wMjcyOCB2IC0yNS4wMTEyIGggMjcuMDMzNiBjIDEwLjA4NjM5LDAgOS42NzY3OSwtOS42MjU2IDkuNjc2NzksLTE2LjY0IFYgNTgwLjU4NTI5IGMgMCwtNy42OC
|
||||
AtMS4wNzUyLC0xNi40ODYzOSAtMTYuODk1OTksLTE2LjQ4NjM5IGggLTIxLjkxMzYgViA1MzkuMDYyMSBaIE0gMTA4My43NzYsNzE0LjM0NTI4IGEgNTUuODU5MTkzLDU1Ljg1OTE5MyAwIDAgMCA2Ljk2MzIsLTAuNDM1MiA4LjYyNzE5OSw4LjYyNzE5OSAwIDAgMCA1LjQyNzIsLTQuODEyOCAyOC4wMDYzOTcsMjguMDA2Mzk3IDAgMCAwIDAuNTM3NiwtNS40MDE2IHYgLTM5LjU1MiBjIDAsLTEuMzMxMiAwLC0xLjM1NjggLTEuNjg5NiwtMy40NTYgLTEuNjg5NiwtMi4w
|
||||
OTkyIC03Mi4wODk2LC04MS45MTk5OSAtNzUuMjg5NiwtODUuNTAzOTkgLTMuOTkzNiwtNC4zNTIgLTExLjAwOCwtMTEuMDg0NzkgLTIxLjY4MzIsLTExLjA4NDc5IGggLTI0LjQ0Nzk2IHYgLTI1LjAzNjggaCAxMzcuOTgzOTYgdiAyNC45ODU2IGggLTE2LjY0IGMgLTMuODQsMCAtNi40LDMuNjYwNzkgLTMuMTIzMiw3LjY3OTk5IDAsMCA0Ni40Mzg0LDU1LjU1MiA0Ni44NzM2LDU2LjE0MDggMC40MzUyLDAuNTg4OCAwLjgxOTIsMC43MTY4IDEuNDA4LDAuMTc5MiAwLj
|
||||
U4ODgsLTAuNTM3NiA0Ny41OTA0LC01NS44MDggNDcuOTQ4OCwtNTYuMzIgYSA0Ljc4NzE5OTQsNC43ODcxOTk0IDAgMCAwIC00LjA5NiwtNy42Nzk5OSBoIC0xNy4wNzUyIFYgNTM5LjA2MjEgSCAxMjgwIHYgMjUuMDM2OCBoIC0yNS4yNjcyIGMgLTkuMTY0OCwwIC0xMi44LDEuNjg5NTkgLTE5Ljc4ODgsOS40NzE5OSBsIC03Ni4xNiw4Ni44ODYzOSBhIDUuMzc1OTk5NCw1LjM3NTk5OTQgMCAwIDAgLTAuOTIxNiwzLjY4NjQgdiAzOS41MjY0IGEgMjguMTU5OTk3LDI4
|
||||
LjE1OTk5NyAwIDAgMCAwLjU2MzIsNS40MDE2IDguNTI0Nzk5LDguNTI0Nzk5IDAgMCAwIDUuNDAxNiw0LjgxMjggNTAuNjExMTk0LDUwLjYxMTE5NCAwIDAgMCA2LjkxMiwwLjQzNTIgaCAyNS44MzA0IHYgMjUuMDM2OCBoIC0xMzcuMjY3MiB2IC0yNS4wMzY4IHoiIGlkPSJwYXRoMSIgZmlsbD0iIzAwMDAwMCIgc3R5bGU9InN0cm9rZS13aWR0aDoyLjU2Ii8+PC9zdmc6Zz48L3N2ZzpnPjwvc3ZnOnN2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Sony</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="13">
|
||||
<name>Toshiba</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>logo-toshiba.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmc6c3ZnIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOnN2Zz0
|
||||
iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI4MDAiIGhlaWdodD0iODAwIiB2ZXJzaW9uPSIxLjAiIHZpZXdCb3g9IjAgMCA4MDAgODAwLjAxOTY5IiBpZD0ic3ZnMSIgc29kaXBvZGk6ZG9jbmFtZT0ibG9nby10b3NoaWJhLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c3ZnOmRlZnMgaWQ9ImRlZnMxIi8+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2a
|
||||
WV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iMS41MzgxMjUiIGlua3NjYXBlOmN4PSIzNzguNzA3ODQiIGlua3NjYXBlOmN5PSIyODg
|
||||
uMDEzIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMSI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSIyMjcuMzE3MTYsMzk5LjM4NTQyIiBvcmllbnRhdGlvbj0iMCwtMSIgaWQ9Imd1aWRlMSIgaW5rc2NhcGU6bG9ja2VkPSJmY
|
||||
WxzZSIvPjwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxzdmc6cGF0aCBmaWxsPSIjZTYxZTFlIiBkPSJtIDc2Ni4xMDAxNiw0NTkuNzEzNiBoIDM0LjU1IGwgLTM1LjY1LC0xMTcuNjYgLTQ5LjEsLTAuMDAyIC0zNS42NSwxMTcuNjYgaCAzNC41NiBsIDYuMywtMjEuNzggaCAzOC42NiBsIDYuMzMsMjEuNzggbSAtMzcuNTEsLTQ3Ljk0MyAxMS43NiwtNDAuNjUxIGggMC4yIGwgMTEuNzYsNDAuNjUxIHogbSAtNTU1LjQ2LDUwLjA1NSBjIDM1LjQ4LDAgNTIuNjMsLTYuMjU
|
||||
gNTUuMDYsLTM4LjI2NSAwLjU4LC03LjYxOCAwLjY5LC0xNS40MzkgMC42OSwtMjIuNjg5IDAuMDEsLTcuMjI1IC0wLjExLC0xNS4wNTQgLTAuNjksLTIyLjY3MSAtMi40MywtMzIuMDI1IC0xOS41OCwtMzguMjY1IC01NS4wNiwtMzguMjY1IC0zNS40OCwwIC01Mi42Miw2LjI0IC01NS4wNCwzOC4yNjUgLTAuNTksNy42MTcgLTAuNzEsMTUuNDQ2IC0wLjcxLDIyLjY3MSAwLjAxLDcuMjUgMC4xMiwxNS4wNzEgMC43MSwyMi42ODkgMi40MiwzMi4wMTUgMTkuNTYsMzguMjY1IDU1LjA0LDM4LjI2NSBtIC0yMi4zMSwtNjAuOTU0IGMgMCwtNi40NjEgMC4xNiwtMTAuMjggMC4zLC0xMy4xMTQgMC45LC0xOC4xNjEgOC4wNywtMjAuMjc4IDIyLjAxLC0yMC4yNzggMTMuOTUsMCAyMS4xMiwyLjExNyAyMi4wMSwyMC4yNzggMC4xNCwyLjgzMyAwLjMxLDYuNjUyIDAuMzEsMTMuMTE0IDAsNi40ODIgLTAuMTcsMTAuMzA4IC0wLjMxLDEzLjEzNSAtMC44OSwxOC4xNjQgLTguMDYsMjAuMjg1IC0yMi4wMSwyMC4yODUgLTEzLjk0LDAgLTIxLjExLC0yLjEyMSAtMjIuMDEsLTIwLjI4NSAtMC4xNCwtMi44MjcgLTAuMywtNi42NTMgLTAuMywtMTMuMTM1IHogTSAwLjY1MDE1ODIyLDM0Mi4xMDU2IHYgMjkuMzMxIEggMzUuODIyMTU4IHYgODguMzI3IGggMzUuMTg1IHYgLTg4LjMyNyBoIDM1LjE3MzAwMiB2IC0yOS4zMzEgSCAwLjY1MDE1ODIyIE0gNTQwLjUwMDE2LDQ1OS43MTM2IHYgLTExNy42NjIgaCAtMzMuMzkgdiAxMTcuNjYyIGggMzMuMzkgbSAtMTM0LjM1LC03NC43MDMgdiAtNDIuOTU5IGggLTMzLjIgdiAxMTcuNjYyIGggMzMuMiB2IC00NS4zNzIgaCAzOC41OCB2IDQ1LjM3MiBoIDMzLjE5IHYgLTExNy42NjIgaCAtMzMuMTkgdiA0Mi45NTkgaCAtMzguNTggbSAyNDQuMTcsMTMuMjA2IGMgMTQuNzksLTMuNzgxIDE5LjEzLC0xMi42MTYgMTkuMTMsLTI1LjM4NiAwLC0yNS44NTkgLTE2LjI3LC0zMC43OCAtMzkuNCwtMzAuNzggaCAtNTkuOTUgdiAxMTcuNjYgaCA2Mi45MiBjIDI4Ljk3LDAgMzguNzEsLTEyLjQ4IDM4LjcxLC0zMS42NzUgMCwtMTMuMzgzIC0zLjA2LC0yNS4xOTEgLTIxLjQxLC0yOS44MjIgbSAtNDcuMDMsMTMuMTY5IGggMjMuMDIgYyA5LjMsMCAxMS4yNCw0LjA3NCAxMS4yNCwxMC43IDAsNi42MzIgLTMuNjQsMTAuNzE3IC0xMS4yNCwxMC43MTcgaCAtMjMuMDIgeiBtIDAsLTQyLjQyNSBoIDIzLjAyIGMgNi4wMSwwIDkuNzMsMi44NTEgOS43Myw5LjcwOCAwLDUuODc4IC0zLjY4LDkuNDk2IC05LjczLDkuNDk2IGggLTIzLjAyIHogbSAtMzU1LjA2LDUyLjE0MyBoIDMxLjY1IGMgMC4wMyw1LjcwOCAwLjc2LDkuNTIzIDMuNTMsMTEuNjMgMy4xNSwyLjM3NCA1Ljk3LDMuMTU4IDE1LjMyLDMuMTU4IDksMCAxOC44NiwwIDE4Ljg2LC0xMS4wODUgMCwtOC43NDIgLTUuNTEsLTEwLjczNyAtMTUuNjgsLTExLjI3OSAtMjUuMjIsLTEuMzM2IC0zNC4zNCwtMi4wNDkgLTQzLjczLC05LjAyNSAtNi40LC00Ljc1NyAtOS43MiwtMTQuMDE4IC05LjcyLC0yNi41NDIgMCwtMjEuMjk3IDcuNDMsLTI4Ljc2OCAxOC4xNSwtMzMuOTgxIDExLjA2LC01LjM4MSA1NC40NywtNS4zODEgNjYuMTUsMCAxNC42OSw2Ljc2OCAxNS4xMiwyMS40MiAxNS4xMiwzNS4wMTEgaCAtMzEuNTcgYyAtMC4wNiwtNi45MjkgLTEuNjIsLTguODg2IC0yLjg5LC0xMC4xNzUgLTMuMjgsLTIuOTA4IC03Ljk1LC0zLjUyMiAtMTQuNjksLTMuNTIyIC04LjE2LDAgLTE3LjYsMC4zNjggLTE3LjYsMTAuMjc3IDAsNy41NiAzLjI3LDEwLjcyIDExLjg1LDExLjI3NiAxMS43OSwwLjc1NCAzNS4wMiwxLjQ5NyA0My4zLDYuMzgzIDExLjYxLDYuODY3IDE0LjYyLDE2LjE1OSAxNC42MiwzMS4zMTkgMCwyMS45MDggLTcuODQsMjguMzM4IC0xOC43NSwzMy4xNTggLTEyLjU5LDUuNTYgLTU0LjY0LDUuNTYgLTY4LjMxLC0wLjQzIC0xNS4zLC02LjY3IC0xNS42MSwtMTkuOTY0IC0xNS42MSwtMzYuMTczIiBpZD0icGF0aDEiLz4KPC9zdmc6c3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Toshiba</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="1">
|
||||
<name>Acer</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="2">
|
||||
<name>Apple</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="3">
|
||||
<name>Asus</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="4">
|
||||
<name>Cisco</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="5">
|
||||
<name>Dell</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="6">
|
||||
<name>HP Inc</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="7">
|
||||
<name>HPE</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="8">
|
||||
<name>IBM</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="9">
|
||||
<name>Lenovo</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="10">
|
||||
<name>Razer</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="11">
|
||||
<name>Samsung</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="12">
|
||||
<name>Sony</name>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="13">
|
||||
<name>Toshiba</name>
|
||||
</Brand>
|
||||
</Set>
|
||||
|
||||
|
||||
@@ -1,116 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<OSFamily alias="OSFamily" id="1">
|
||||
<name>Arch</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-arch-linux.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmlld0JveD0iMCwwLDI1NiwyNTYiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiIGZpbGwtcnVsZT0ibm9uemVybyI+PGcgZmlsbD0iIzAwODhjYyIgZmlsbC1ydWxlPSJub256ZXJvIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgZm9udC1mYW1pbHk9Im5vbmUiIGZvbnQtd2VpZ2h0PSJub25lIiBmb250LXNpemU9Im5vbmUiIHRleHQtYW5jaG9yPSJub25lIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6IG5vcm1hbCI+PGcgdHJhbnNmb3JtPSJzY2FsZSg1LjMzMzMzLDUuMzMzMzMpIj48cGF0aCBkPSJNMjguNDY1LDM4LjYxMWMwLjQxOSwtMS4xMDUgMC42NjQsLTIuMzY1IDAuNjY0LC0zLjcxNGMwLC00LjEzMyAtMi4yMTEsLTcuNDk0IC00LjkyOSwtNy40OTRjLTIuNzQxLDAgLTQuOTUxLDMuMzYxIC00Ljk1MSw3LjQ5NGMwLDEuMzI2IDAuMjIxLDIuNTg2IDAuNjQxLDMuNjY5Yy05LjA0MSwwLjk1MSAtMTUuNDA3LDQuNzMxIC0xNy45OTMsNi40MzJjNC4zNTUsLTYuMjc4IDguOTA5LC0xMy42MzggMTMuMjYyLC0yMi4xMDVjMS4wODMsLTIuMTAxIDIuMTAxLC00LjE3OCAzLjA1LC02LjIxMWMwLjM3NSwwLjI0MyAwLjc1MSwwLjUwOSAxLjE3MSwwLjc3NWMxLjk0NSwxLjIxNSAzLjc1OSwxLjg3OSA1LjA4NCwyLjIzM2MtMC45NzMsLTAuNzMgLTIuMDMzLC0xLjYxMyAtMy4xMTYsLTIuNjk3Yy0wLjgxNywtMC44MTcgLTEuNTQ3LC0xLjYzNyAtMi4xNjcsLTIuNDMzYzEuODM1LC00LjAyMiAzLjQyNywtNy44OTEgNC44MTksLTExLjU2YzIuMzIsNi4xNDQgNS4yMTcsMTIuODQyIDguODQxLDE5Ljg5M2MyLjM0Myw0LjUzMSA0LjczMSw4Ljc1NCA3LjExNywxMi42NDRjLTAuNjg1LC0wLjM3NSAtMS40MzcsLTAuNzMgLTIuMjMzLC0xLjAzOWMtMS4zNzEsLTAuNTMgLTIuNjUyLC0wLjg2MiAtMy43NTksLTEuMDZjMS41MDMsMC43NTEgMy4yNSwxLjc0NyA1LjA4NCwzLjA3M2MxLjE5NCwwLjg4NSAyLjI1NCwxLjc2OSAzLjE2MSwyLjYzMWMwLjAyMSwwLjAyMSAwLjAyMSwwLjAyMSAwLjA0NSwwLjA0NWMxLjI2LDIuMDU2IDIuNTY1LDMuOTU3IDMuODQ2LDUuODEzYy0yLjU0MSwtMS42ODEgLTguNzk2LC01LjM5NSAtMTcuNjM3LC02LjM4OXoiLz48L2c+PC9nPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Arch</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="2">
|
||||
<name>Debian</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-debian.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNFOTFFNjMiIGQ9Ik0yNi43NjMsMjQuNTQ4Yy0wLjYxNCwwLjAxLDAuMTE3LDAuMzE3LDAuOTE4LDAuNDRjMC4yMi0wLjE3MiwwLjQxOS0wLj
|
||||
M0OCwwLjYtMC41MTVDMjcuNzgxLDI0LjU5MiwyNy4yNzQsMjQuNTk0LDI2Ljc2MywyNC41NDggTTMwLjA1NCwyMy43MjdjMC4zNjQtMC41LDAuNjMxLTEuMDU1LDAuNzIzLTEuNjI0Yy0wLjA4MiwwLjQwNS0wLjMwMywwLjc1NS0wLjUxLDEuMTI4Yy0xLjE0NiwwLjcyMS0wLjEwOC0wLjQzLDAtMC44NjVDMjkuMDM1LDIzLjkxMywzMC4wOTgsMjMuMjkzLDMwLjA1NCwyMy43MjcgTTMxLjI2OSwyMC41NjhjMC4wNzMtMS4xMDUtMC4yMTktMC43NTYtMC4zMTctMC4zMzZD
|
||||
MzEuMDY4LDIwLjI5NCwzMS4xNTYsMjEuMDEzLDMxLjI2OSwyMC41NjggTTI0LjQzOSw1LjQ3OGMwLjMyNywwLjA1OCwwLjcwNiwwLjEwNCwwLjY1MywwLjE4M0MyNS40NDksNS41ODIsMjUuNTMxLDUuNTEsMjQuNDM5LDUuNDc4IE0yNS4wOTMsNS42NmwtMC4yMzIsMC4wNDdsMC4yMTUtMC4wMTdMMjUuMDkzLDUuNjYgTTM1LjI5NCwyMC45ODZjMC4wMzgsMC45OTEtMC4yOSwxLjQ3Mi0wLjU4NSwyLjMyMmwtMC41MjksMC4yNjZjLTAuNDM1LDAuODQxLDAuMDQxLDAuNT
|
||||
M1LTAuMjY4LDEuMjAyYy0wLjY3OSwwLjYwMy0yLjA1NSwxLjg4My0yLjQ5NiwyLjAwNGMtMC4zMjEtMC4wMDksMC4yMTgtMC4zODIsMC4yODktMC41MjZjLTAuOTA2LDAuNjItMC43MjgsMC45MzQtMi4xMTMsMS4zMTNsLTAuMDQxLTAuMDljLTMuNDE5LDEuNjA3LTguMTY2LTEuNTc2LTguMTAzLTUuOTI4Yy0wLjAzNywwLjI3NS0wLjEwNCwwLjIwOS0wLjE4LDAuMzJjLTAuMTc1LTIuMjM3LDEuMDMzLTQuNDg2LDMuMDczLTUuNDAzYzEuOTk1LTAuOTg3LDQuMzM1LTAu
|
||||
NTgsNS43NjMsMC43NWMtMC43ODUtMS4wMjgtMi4zNDgtMi4xMTktNC4xOTktMi4wMTdjLTEuODE0LDAuMDI5LTMuNTEsMS4xODItNC4wNzcsMi40MzRjLTAuOTI5LDAuNTg1LTEuMDM4LDIuMjU2LTEuNDQxLDIuNTYzYy0wLjU0NSw0LjAwMywxLjAyNCw1LjczMywzLjY4LDcuNzY4YzAuNDE3LDAuMjgyLDAuMTE4LDAuMzI2LDAuMTc1LDAuNTQxYy0wLjg4My0wLjQxMi0xLjY5LTEuMDM3LTIuMzU0LTEuODAxYzAuMzUzLDAuNTE3LDAuNzMzLDEuMDE3LDEuMjIzLDEuND
|
||||
FjLTAuODMxLTAuMjc5LTEuOTQyLTIuMDEzLTIuMjY3LTIuMDg0YzEuNDM1LDIuNTY3LDUuODE4LDQuNTAyLDguMTEzLDMuNTQxYy0xLjA2MiwwLjA0LTIuNDEyLDAuMDIxLTMuNjA0LTAuNDJjLTAuNTAxLTAuMjU3LTEuMTgzLTAuNzkxLTEuMDYyLTAuODkzYzMuMTMzLDEuMTcxLDYuMzY5LDAuODg3LDkuMDc4LTEuMjg2YzAuNjg5LTAuNTM3LDEuNDQzLTEuNDQ5LDEuNjYyLTEuNDY0Yy0wLjMyNywwLjQ5MywwLjA1NywwLjIzOS0wLjE5NywwLjY3NGMwLjY4OC0xLjEw
|
||||
OS0wLjI5OS0wLjQ0OSwwLjcxMS0xLjkxM2wwLjM3MywwLjUxMmMtMC4xMzktMC45MTcsMS4xNDMtMi4wMzMsMS4wMTItMy40ODljMC4yOTEtMC40NDUsMC4zMjYsMC40NzgsMC4wMTUsMS41MDJjMC40MzQtMS4xMzYsMC4xMTMtMS4zMTcsMC4yMjQtMi4yNTRjMC4xMjEsMC4zMTUsMC4yNzksMC42NDgsMC4zNTksMC45ODFjLTAuMjgxLTEuMDk3LDAuMjg5LTEuODQ4LDAuNDMzLTIuNDg1Yy0wLjE0Mi0wLjA2My0wLjQzNSwwLjQ4NS0wLjUwMy0wLjgxMmMwLjAxLTAuNT
|
||||
YyLDAuMTU2LTAuMjk1LDAuMjE0LTAuNDM1Yy0wLjExMS0wLjA2NC0wLjQtMC40OTYtMC41NzctMS4zMjNjMC4xMjctMC4xOTMsMC4zNDIsMC41MDYsMC41MTYsMC41MzNjLTAuMTEyLTAuNjU1LTAuMzA0LTEuMTU5LTAuMzEzLTEuNjY1Yy0wLjUxLTEuMDYxLTAuMTgxLDAuMTQzLTAuNTkyLTAuNDU4Yy0wLjU0My0xLjY4NywwLjQ0OS0wLjM5LDAuNTE0LTEuMTU2YzAuODIsMS4xODgsMS4yODksMy4wMjksMS41MDQsMy43OTJjLTAuMTY0LTAuOTMtMC40MjgtMS44MzIt
|
||||
MC43NTItMi43MDRjMC4yNDksMC4xMDgtMC40MDEtMS45MTEsMC4zMjQtMC41NzVjLTAuNzcyLTIuODQ4LTMuMzE0LTUuNTExLTUuNjUtNi43NmMwLjI4NiwwLjI2MiwwLjY0NiwwLjU5MSwwLjUxNywwLjY0MmMtMS4xNjMtMC42OS0wLjk1OS0wLjc0NS0xLjEyNC0xLjA0MWMtMC45NDYtMC4zODMtMS4wMSwwLjAzNC0xLjYzNiwwYy0xLjc4Ni0wLjk0My0yLjEyOS0wLjg0NS0zLjc3Mi0xLjQzN2wwLjA3OCwwLjM0OWMtMS4xODQtMC4zOTQtMS4zNzksMC4xNDYtMi42NT
|
||||
csMC4wMDJjLTAuMDc4LTAuMDYyLDAuNDEtMC4yMTksMC44MTEtMC4yNzhjLTEuMTQzLDAuMTUtMS4wOS0wLjIyOC0yLjIwOCwwLjA0MmMwLjI3Ny0wLjE5NywwLjU2Ni0wLjMyMiwwLjg2MS0wLjQ4NmMtMC45MzIsMC4wNTktMi4yMjYsMC41NDItMS44MjUsMC4xMDNjLTEuNTIxLDAuNjc2LTQuMjIsMS42My01LjczNSwzLjA1MWwtMC4wNDctMC4zMjJjLTAuNjk0LDAuODM1LTMuMDI4LDIuNDkyLTMuMjE1LDMuNTdsLTAuMTg1LDAuMDQzYy0wLjM2MSwwLjYxMy0wLjU5
|
||||
NSwxLjMwNS0wLjg4MSwxLjkzNWMtMC40NzQsMC44MDYtMC42OTIsMC4zMTEtMC42MjYsMC40MzZjLTAuOTI5LDEuODgzLTEuMzksMy40NjctMS43OSw0Ljc2OGMwLjI4NCwwLjQyNCwwLjAwNywyLjU1OCwwLjExMyw0LjI2NGMtMC40NjcsOC40MjksNS45MTYsMTYuNjA5LDEyLjg5MSwxOC41YzEuMDIzLDAuMzY1LDIuNTQyLDAuMzU0LDMuODM2LDAuMzljLTEuNTI1LTAuNDM4LTEuNzIyLTAuMjMyLTMuMjA5LTAuNzQ5Yy0xLjA3NC0wLjUwNi0xLjMwOC0xLjA4Mi0yLj
|
||||
A2Ni0xLjc0bDAuMywwLjUzYy0xLjQ5LTAuNTI2LTAuODY3LTAuNjUyLTIuMDc4LTEuMDM0bDAuMzIxLTAuNDI0Yy0wLjQ4Mi0wLjAzMi0xLjI3OS0wLjgxMS0xLjQ5Ny0xLjI0MWwtMC41MjgsMC4wMjFjLTAuNjM0LTAuNzgzLTAuOTcyLTEuMzQ4LTAuOTQ4LTEuNzg1bC0wLjE3LDAuMzA1Yy0wLjE5NC0wLjMzMi0yLjMzNS0yLjkzNy0xLjIyNC0yLjMzYy0wLjIwNy0wLjE4OC0wLjQ4MS0wLjMwNy0wLjc3OS0wLjg1bDAuMjI3LTAuMjU4Yy0wLjUzNS0wLjY4Ni0wLjk4
|
||||
My0xLjU2OC0wLjk0OS0xLjg2YzAuMjg0LDAuMzg0LDAuNDgyLDAuNDU0LDAuNjc5LDAuNTIyYy0xLjM1MS0zLjM0OS0xLjQyNi0wLjE4Ny0yLjQ0OC0zLjQwOWwwLjIxNi0wLjAxOWMtMC4xNjYtMC4yNDYtMC4yNjUtMC41MjEtMC4zOTktMC43ODVsMC4wOTQtMC45MzhjLTAuOTcyLTEuMTI1LTAuMjcyLTQuNzgxLTAuMTMyLTYuNzgzYzAuMDk3LTAuODE2LDAuODExLTEuNjg0LDEuMzU0LTMuMDQ1bC0wLjMzMi0wLjA1NWMwLjYzMi0xLjEwNCwzLjYxMi00LjQzMyw0Lj
|
||||
k5LTQuMjZjMC42NjktMC44NDEtMC4xMzItMC4wMDItMC4yNjMtMC4yMTVjMS40NjktMS41MiwxLjkzLTEuMDczLDIuOTItMS4zNDljMS4wNjgtMC42MzMtMC45MTcsMC4yNTEtMC40MS0wLjIzOWMxLjg0OC0wLjQ3MywxLjMxLTEuMDczLDMuNzE4LTEuMzExYzAuMjU0LDAuMTQ1LTAuNTksMC4yMjMtMC44LDAuNDFjMS41MzgtMC43NTMsNC44Ny0wLjU4NCw3LjAzNCwwLjQxN2MyLjUxMSwxLjE3Myw1LjMzLDQuNjQyLDUuNDQzLDcuOTA0bDAuMTI2LDAuMDM1Yy0wLjA2
|
||||
MywxLjI5OCwwLjE5OCwyLjc5OC0wLjI1Nyw0LjE3NUwzNS4yOTQsMjAuOTg2IE0yMC4wNzIsMjUuMzg5bC0wLjA4NiwwLjQzMWMwLjQwMywwLjU0NywwLjcyNCwxLjE0MiwxLjIzNywxLjU2N0MyMC44NTMsMjYuNjY0LDIwLjU3NywyNi4zNjQsMjAuMDcyLDI1LjM4OSBNMjEuMDIzLDI1LjM1M2MtMC4yMTMtMC4yMzctMC4zNC0wLjUxOC0wLjQ4LTAuODAyYzAuMTM1LDAuNDk1LDAuNDExLDAuOTIyLDAuNjY5LDEuMzU3TDIxLjAyMywyNS4zNTMgTTM3Ljg3NywyMS42OD
|
||||
hsLTAuMDg4LDAuMjI2Yy0wLjE2NiwxLjE3NC0wLjUyMywyLjMzMi0xLjA2OCwzLjQxMkMzNy4zMjQsMjQuMTg5LDM3LjcxNCwyMi45NDcsMzcuODc3LDIxLjY4OCBNMjQuNTYsNS4xODVDMjQuOTc0LDUuMDMxLDI1LjU3OSw1LjEwMSwyNi4wMTksNWMtMC41NzMsMC4wNDgtMS4xNDQsMC4wNzktMS43MDYsMC4xNTFMMjQuNTYsNS4xODUgTTEwLjAwNywxMi45MjNjMC4wOTUsMC44ODItMC42NjcsMS4yMjksMC4xNjcsMC42NDRDMTAuNjIzLDEyLjU2MiwxMCwxMy4yODYsMTAuMDA3LDEyLjkyMyBNOS4wMjgsMTcuMDE2YzAuMTkxLTAuNTkyLDAuMjI2LTAuOTQzLDAuMy0xLjI4NUM4Ljc5NywxNi40MSw5LjA4NCwxNi41NTMsOS4wMjgsMTcuMDE2Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Debian</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="3">
|
||||
<name>Oracle Linux</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icon-oracle-linux.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dH
|
||||
A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjMxIDIzMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pbllNaWQiIHZlcnNpb249IjEuMSIgaWQ9InN2ZzQiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIyMzEiIGhlaWdodD0iMjMxIiBzb2RpcG9kaTpkb2NuYW1lPSJpY29uLW9yYWNsZS1saW51eC5zdmciIGlua3NjYXBlOnZlcnNpb249IjEuNC4zICgwZDE1Zjc1MDQyLCAy
|
||||
MDI1LTEyLTI1KSI+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2aWV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iNy41MzMyOD
|
||||
kxIiBpbmtzY2FwZTpjeD0iMTA3LjA1ODE1IiBpbmtzY2FwZTpjeT0iOTAuNzk2OTkzIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnNCI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSI0MS43NjM1ODksMTE1LjQ2OCIgb3JpZW50
|
||||
YXRpb249IjAsLTEiIGlkPSJndWlkZTEiIGlua3NjYXBlOmxvY2tlZD0iZmFsc2UiLz48L3NvZGlwb2RpOm5hbWVkdmlldz48ZGVmcyBpZD0iZGVmczgiPjxyZWN0IHg9Ii0xMzguMjQ2NDEiIHk9IjgxLjU2NzIzOCIgd2lkdGg9IjM4Mi4zNjc0IiBoZWlnaHQ9IjI0MC4yMTE1NiIgaWQ9InJlY3Q0OTUiLz48cmVjdCB4PSItMTcuNjEyNjIzIiB5PSIxMDQuMzU4OTgiIHdpZHRoPSIxNzEuMDUyMzgiIGhlaWdodD0iMTk3LjMxNDQ0IiBpZD0icmVjdDI5MSIvPjwvZGVmcz
|
||||
48ZyBpZD0iZzE0MDciIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuNjEzMjE1NDIsNzYuODM1NTMzKSI+PHBhdGggZD0ibSA5OS41OSwxOS41MiBoIDE1LjI0IEwgMTA2Ljc4LDYuNTIgOTEuOTgsMzAgaCAtNi43MyBsIDE4LC0yOC4xNyBhIDQuMjksNC4yOSAwIDAgMSA3LC0wLjA1IEwgMTI4LjMsMzAgaCAtNi43MyBsIC0zLjE3LC01LjI1IGggLTE1LjQyIGwgLTMuMzYsLTUuMjMgbSA2OS45Myw1LjIzIFYgMC4yOCBoIC01LjcyIHYgMjYuODggYSAyLjc2LDIuNzYgMCAw
|
||||
IDAgMC44NSwyIDIuODksMi44OSAwIDAgMCAyLjA4LDAuODcgaCAyNiBsIDMuMzksLTUuMjUgaCAtMjYuNjMgbSAtOTQuNTQsLTQuNCBhIDEwLjA1LDEwLjA1IDAgMCAwIDAsLTIwLjEgaCAtMjUgViAzMCBoIDUuNzEgViA1LjU0IGggMTguOTQgYSA0LjgxLDQuODEgMCAwIDEgMCw5LjYyIEggNTguNTIgTCA3NS41OCwzMCBoIDguMjkgTCA3Mi40MSwyMC4zOCBoIDIuNTcgTSAxNC44NiwzMCBoIDE3LjI3IGEgMTQuODYsMTQuODYgMCAwIDAgMCwtMjkuNzEgSCAxNC44Ni
|
||||
BhIDE0Ljg2LDE0Ljg2IDAgMSAwIDAsMjkuNzEgbSAxNi44OCwtNS4yMyBoIC0xNi41IGEgOS42Miw5LjYyIDAgMCAxIDAsLTE5LjIzIGggMTYuNSBhIDkuNjIsOS42MiAwIDEgMSAwLDE5LjIzIE0gMTQwLjIzLDMwIGggMTcuNjMgbCAzLjM0LC01LjIzIGggLTIwLjU4IGEgOS42Miw5LjYyIDAgMSAxIDAsLTE5LjIzIGggMTYuNzUgbCAzLjM4LC01LjI1IGggLTIwLjUyIGEgMTQuODYsMTQuODYgMCAxIDAgMCwyOS43MSBtIDY5Ljg3LC01LjIzIGEgOS42Miw5LjYyIDAg
|
||||
MCAxIC05LjI2LC03IGggMjQuNDIgbCAzLjM2LC01LjI0IGggLTI3Ljc4IGEgOS42MSw5LjYxIDAgMCAxIDkuMjYsLTcgaCAxNi43NiBsIDMuMzUsLTUuMjUgaCAtMjAuNSBhIDE0Ljg2LDE0Ljg2IDAgMCAwIDAsMjkuNzEgaCAxNy42MyBsIDMuMzUsLTUuMjMgaCAtMjAuNiIgc3R5bGU9ImZpbGw6I2M3NDYzNCIgaWQ9InBhdGgyIi8+PHBhdGggaWQ9InJlY3Q3NDkiIHN0eWxlPSJmaWxsOiNjNzQ2MzQ7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjUuMjUxOTtzdH
|
||||
Jva2UtbGluZWNhcDpzcXVhcmU7cGFpbnQtb3JkZXI6c3Ryb2tlIGZpbGwgbWFya2VycyIgZD0ibSAyNS4zOTE1MTcsNDcuOTMwODcxIGggNC45ODA4NjMgdiAzLjgzMDAyNSBoIC00Ljk4MDg2MyB6IG0gNjEuNTAwOCwxOC41NTcwNjEgLTcuMjQsLTEwLjI0MDAwMiBoIDQuOTYgbCA0LjY0LDcuMDgwMDAyIGggMC4yNCBsIDQuNzYsLTcuMDgwMDAyIGggNC43MiBsIC03LjI4LDEwLjE2MDAwMiA3LjY0LDEwLjg4IGggLTQuOTYgbCAtNS4wOCwtNy43MiBoIC0wLjI0IGwg
|
||||
LTUuMTIsNy43MiBoIC00LjcyIHogbSAtMjEuNTk5OTk4LDExLjI4IHEgLTYuNjgsMCAtNi42OCwtNy4yNCBWIDU2LjI0NzkzIGggNC4xMiB2IDEzLjc2MDAwMiBxIDAsMi4zNiAxLjA0LDMuMzIgMS4wOCwwLjkyIDMuMTIsMC45MiAxLjQsMCAyLjYsLTAuNjggMS4yLC0wLjcyIDEuODgsLTIgMC43MiwtMS4yOCAwLjcyLC0yLjk2IFYgNTYuMjQ3OTMgaCA0LjEyIHYgMjEuMDQwMDAyIGggLTMuMzIgbCAtMC40LC0yLjggaCAtMC4yOCBxIC0xLjE2LDEuNiAtMi45MiwyLj
|
||||
Q0IC0xLjc2LDAuODQgLTQsMC44NCB6IE0gMzUuODEyMzIsNTYuMjQ3OTMgaCAzLjMyMDAwMSBsIDAuNCwyLjgwMDAwMiBoIDAuMjggcSAxLjEyLC0xLjYwMDAwMiAyLjg4LC0yLjQ0MDAwMiAxLjgsLTAuODQgNC4wNCwtMC44NCA2LjY4LDAgNi42OCw3LjI0MDAwMiB2IDE0LjI4IGggLTQuMTIgdiAtMTMuNzYgcSAwLC0yLjM2IC0xLjA4LC0zLjI4IC0xLjA0LC0wLjk2IC0zLjA4LC0wLjk2IC0xLjQsMCAtMi42LDAuNzIgLTEuMiwwLjY4IC0xLjkyLDEuOTYgLTAuNjgsMS4yOCAtMC42OCwyLjk2IHYgMTIuMzYgSCAzNS44MTIzMiBaIE0gMy42MTIzOSw0Ny45MzA4NzEgaCA0LjQ0IHYgMjUuNTE3MDYxIGggMTQuMjggdiAzLjg0IGggLTE4LjcyIHogTSAyNi4yNTY3NjgsNTkuNDYzOTUgViA3Ny4yODc5MzIgSCAzMC4zNzIzOCBWIDU2LjI3NTQ2NCBoIC02LjM4NzYxMiB2IDEuODI1NjgxIHoiLz48L2c+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Oracle Linux</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="4">
|
||||
<name>Red Hat</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-red-hat.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMzNzQ3NEYiIGQ9Ik0yNy44MTMsMzQuODg4Yy0wLjMxOSwwLjM1My0wLjc1NSwwLjM3OC0xLjI4NCwwLjA3NWMtMC40OTctMC4yODItMS4yN
|
||||
zYtMC4yODItMS41MS0wLjAwMSBjLTAuMjY5LDAuMzIzLTAuMDc1LDAuNjgxLDAuMzY3LDAuNjgxYzAuMjA3LDAsMC42MDQsMC4xMzcsMC44NzQsMC4zMDNjMC4yNzEsMC4xNjcsMC42NTMsMC4zMDMsMC44NDcsMC4zMDMgYzAuNDc1LDAuMDAyLDEuMjM0LTAuNzgyLDEuMjM0LTEuMjczQzI4LjM0MiwzNC41MDYsMjguMTgyLDM0LjQ4LDI3LjgxMywzNC44ODh6IE00MywyNS45NzFjMCwzLjIyMS0wLjUzNSw1LjYwMi0xLjg4Nyw4LjM4NiBjLTAuOTgsMi4wMjItMC44NDY
|
||||
sMS45Mi0yLjI3MiwxLjc0Yy0xLjI5My0wLjE2My0yLjk4OS0wLjAyNi00LjA3NSwwLjMzMWMtMC40ODQsMC4xNi0wLjYxNywwLjI4My0wLjY4MSwwLjY0MyBjLTAuMDY1LDAuMzc5LTAuMjA2LDAuNDkzLTAuOTc5LDAuNzkzYy0wLjY1MiwwLjI1My0wLjk3NywxLjAzMy0xLjY4NiwxLjcyOGMtMC41NDMsMC41My0xLjEyMSwxLjAzLTEuMjg4LDEuMTEzIEMyOS43NDIsNDAuODk0LDI5LDQxLjA2OSwyOSw0MC45NzRjMC0wLjA3MSwwLjk4Ni0yLjI1MSwyLjM1Ny00LjIxO
|
||||
GMwLjQ5LTAuNzA0LDAuNjYxLTEuMTA0LDAuNzA5LTEuNjYxIGMwLjAzNi0wLjQwNSwwLjIxMS0xLjIyOSwwLjM4OS0xLjgzYzAuMTc5LTAuNjAzLDAuMjg5LTEuMTMsMC4yNDYtMS4xNzNzLTAuMzcsMC4wMjUtMC43MjYsMC4xNDggYy0wLjc3OSwwLjI3NS0xLjI5MywwLjI4Ni0yLjE3NywwLjA1MWMtMC41NjMtMC4xNTEtMC43NzEtMC4xMzktMS4zNDQsMC4wOGMtMC42MzksMC4yNDYtMC43MTksMC4yNDYtMS4zMTMsMC4wMDYgYy0wLjU5NS0wLjIzNy0wLjcyNS0wLjI
|
||||
zNy0yLjE0NiwwLjAxNGMtMi42NTUsMC40NjYtMy41MTMsMC4yMDYtNS4yODQtMS42MDljLTEuMDk4LTEuMTI1LTEuNTA4LTEuMzcyLTEuNzE3LTEuMDMgYy0wLjA1MSwwLjA4My0wLjI1MywwLjE1MS0wLjQ0NiwwLjE1MWMtMC4yNTgsMC0wLjQ4NC0wLjIwMy0wLjg0MS0wLjc2Yy0wLjI2Ny0wLjQxNS0wLjY3Ny0wLjg5My0wLjkwOS0xLjA1OCBjLTEuMjc0LTAuOTA2LTIuNzE1LTAuMjUtMi43MTUsMS4yNGMwLDAuNjE0LDEuMjI4LDIuNDY1LDEuODQ3LDIuNzg2YzAuO
|
||||
DE4LDAuNDIzLDAuMzU3LDEuMDU3LTAuNjcxLDAuOTE5IGMtMC41MzItMC4wNzItMC43NjctMC4yMzEtMS40ODItMS4wMDNjLTAuNzY0LTAuODI2LTAuOTA3LTAuOTE2LTEuNDQzLTAuOTE0Yy0wLjMyOCwwLjAwMi0wLjg3NSwwLjEzMS0xLjIxNSwwLjI4NCBjLTAuODc3LDAuMzk5LTIuMDIyLDAuNjItMy4yMjEsMC42Mkg1Ljg2NUw1LjYzLDMxLjE0NkM1LjA5MywyOS4xNzEsNSwyOC40LDUsMjUuOTcxYzAtMS44NTcsMC4wNzEtMi44MjEsMC4yNzktMy43NzkgYzEuMTI
|
||||
0LTUuMTcyLDMuOTg0LTkuMzUzLDguMzIzLTEyLjE2OWMyLjEyOC0xLjM4Miw0LjA4NC0yLjE5Miw2LjU3OS0yLjcyOWMxLjc4My0wLjM4Myw1Ljc3Ni0wLjM5NCw3LjUxLTAuMDIxIGM1LjkwMiwxLjI3MywxMC43OTQsNC45OTYsMTMuMzM5LDEwLjE2QzQyLjQ1NywyMC4zMjUsNDMsMjIuNjc3LDQzLDI1Ljk3MXoiLz48cGF0aCBmaWxsPSIjRkYzRDAwIiBkPSJNMzguMDgyLDIyLjMxMmMtMC43MTEtMC41MzktMi41MjktMS4zMjctMy4wNjMtMS4zMjdjLTAuMTQ2LDAtM
|
||||
C40LDAuMjczLTAuNTk4LDAuNjQzIGMtMC4yOTcsMC41NTktMS4xMzEsMS4zMjItMS40NDQsMS4zMjJjLTAuMDU4LDAsMC4xMDEtMC4zODQsMC4zNS0wLjg1MmMwLjExLTAuMjA1LDAuMjA0LTAuNDIzLDAuMjgtMC42MzEgYzAuMTA5LTAuMzAzLDAuMTc4LTAuNTg0LDAuMTc4LTAuNzc2YzAtMC45NTgtMC42NzYtMy4xMTctMS40OTctNS4wNDljLTAuNDM1LTEuMDI0LTAuOTExLTEuOTg1LTEuMzUxLTIuNjY5IGMtMC4yMTUtMC4zMzUtMC4zOTMtMC41ODktMC41NTktMC4
|
||||
3OTJjLTAuMjktMC4zNTEtMC41NTktMC41NTQtMC45NzUtMC43NzljLTAuMjgzLTAuMTUyLTAuNTgtMC4yNy0wLjg5MS0wLjM1NiBjLTAuMDA2LDAtMC4wMTItMC4wMDMtMC4wMTYtMC4wMDNjLTAuMDczLTAuMDIxLTAuMTQ1LTAuMDM5LTAuMjE5LTAuMDU1Yy0wLjAxMi0wLjAwMy0wLjAyMy0wLjAwNS0wLjAzNS0wLjAwOSBjLTAuMDctMC4wMTQtMC4xMzktMC4wMjYtMC4yMTItMC4wMzljLTAuMDE1LTAuMDAzLTAuMDI4LTAuMDAzLTAuMDQ0LTAuMDA2Yy0wLjA3Mi0wL
|
||||
jAxMi0wLjE0Mi0wLjAyMS0wLjIxNS0wLjAzIGMtMC4wMTItMC4wMDEtMC4wMjUtMC4wMDEtMC4wMzctMC4wMDNjLTAuMTYtMC4wMTYtMC4zMjUtMC4wMjctMC40OTUtMC4wMjdjLTAuMDE3LDAtMC4wMzYsMC0wLjA1MywwIGMtMC4xMiwwLTAuMjM5LDAuMDA2LTAuMzYyLDAuMDE0Yy0wLjAzOSwwLjAwMS0wLjA3NiwwLjAwNC0wLjExNCwwLjAwNWMtMC4xMzIsMC4wMTEtMC4yNjcsMC4wMjQtMC40MDIsMC4wNDIgYy0wLjA0OCwwLjAwNi0wLjA5NSwwLjAxMy0wLjE0NCw
|
||||
wLjAxOWMtMC4xMzQsMC4wMTktMC4yNywwLjA0MS0wLjQwOCwwLjA2OGMtMC4wNTUsMC4wMS0wLjExMiwwLjAyNC0wLjE3LDAuMDM2IGMtMC4xMDYsMC4wMjItMC4yMTgsMC4wNDgtMC4zMjksMC4wNzVjLTAuMDQzLDAuMDEtMC4wODMsMC4wMTctMC4xMjYsMC4wMjdjLTEuMDYzLDAuMjcyLTEuNTU4LDAuMzE5LTIuNTY2LDAuMjQ1IGMtNC4xMTctMC4yOTctMy45NTEtMC4zLTQuNjMsMC4wNDdjLTAuMzY4LDAuMTg4LTAuNjI4LDAuMzktMC44NDgsMC43M2MtMC4yOTgsM
|
||||
C40NjItMC41MiwxLjE3Mi0wLjgyOSwyLjQ1MSBjLTAuNTgyLDIuNDAzLTAuNTk1LDMuMTQ2LTAuMDY4LDMuNzczYzAuNTM2LDAuNjM5LDIuMjY1LDEuNDMxLDMuOTksMS44MjdjMi4wNjMsMC40NzQsMy40NjksMC44OTIsMy44NTksMS4xNDkgYzAuMDk3LDAuMDYzLDAuMjA1LDAuMTc4LDAuMzAxLDAuMzEzYzAuMDkxLDAuMTI1LDAuMTcsMC4yNjYsMC4yMTgsMC4zOTRjMC40MzQsMS4xNTcsMC42NjcsMS42MjcsMC45MzEsMS44NjQgYzAuMDY1LDAuMDYsMC4xMjUsMC4
|
||||
xMzEsMC4xNzQsMC4xOTdjMC4wNjYsMC4wOTIsMC4xMDcsMC4xODMsMC4xMDcsMC4yMzljMCwxLjA5Ny03LjgwMy0xLjMzMy05LjgxNC0zLjA1NCBjLTAuNTM4LTAuNDYyLTAuODM3LTAuODQ2LTAuOTY1LTEuMjg4Yy0wLjA3Ny0wLjI3NC0wLjA4Ny0wLjU3MS0wLjA0Ni0wLjkyMmwwLjAyNC0wLjIxMWwwLjA2My0wLjUzNGgtMC4wMDF2LTAuMDAybC0xLjk5OCwwLjA2NiBjLTEuNjg4LDAuMDU2LTIuMTA5LDAuMTE4LTIuNzE1LDAuNDEyYy0yLjA4NiwxLjAwNS0xLjk4N
|
||||
SwyLjY5LDAuMjg4LDQuODVjMS42MzQsMS41NTQsNC4xMTMsMy4wODUsNi44NTMsNC4zMzQgYzIuODI4LDEuMjkzLDUuOTM2LDIuMjgzLDguNjgxLDIuNjg2YzEuMTg4LDAuMTc1LDIuNzEyLDAuMjM3LDQuMTEzLDAuMTkzYzAuNzkxLTAuMDI0LDEuNTQzLTAuMDg0LDIuMTctMC4xOCBjMy4zNjUtMC41MTMsNS42OTUtMS44ODYsNi42NjgtMy45MzRjMC4xMDUtMC4yMjIsMC4xODktMC40MzgsMC4yNTgtMC42NTJDMzkuODE4LDI0LjY1NCwzOS4zNzcsMjMuMjk3LDM4LjA
|
||||
4MiwyMi4zMTJ6IE0yMi4xMjIsMTYuMDE1Yy0xLjQzOCwwLjE1OS0yLjE0MSwwLjM1NS0yLjQwMywwLjY3MWMtMC4xMDEsMC4xMjEtMC4yMDQsMC4xODgtMC4zMjcsMC4xOTdjLTAuMjQ5LDAuMDE3LTAuNTctMC4yMTUtMS4wODktMC43NDIgYy0wLjM2MS0wLjM3MS0wLjU2Ny0wLjYzNy0wLjY2Ny0wLjg2N2MtMC4wNS0wLjExNS0wLjA3My0wLjIyNi0wLjA3My0wLjMzMmMwLTAuMDYxLDAuMDA0LTAuMTIsMC4wMS0wLjE3OCBjMC4wMDEtMC4wMDgsMC4wMDMtMC4wMTYsM
|
||||
C4wMDMtMC4wMjNjMC4wMDctMC4wNDcsMC4wMTYtMC4wOTMsMC4wMjgtMC4xMzljMC4wMDEtMC4wMDksMC4wMDMtMC4wMTUsMC4wMDUtMC4wMjMgYzAuMDE0LTAuMDQ4LDAuMDI5LTAuMDk0LDAuMDQ5LTAuMTM3YzAuMDAzLTAuMDA3LDAuMDA1LTAuMDEzLDAuMDEtMC4wMTljMC4wMTctMC4wMzIsMC4wMzItMC4wNjMsMC4wNTEtMC4wOTMgYzAuMDA3LTAuMDEzLDAuMDE1LTAuMDI0LDAuMDIzLTAuMDM1YzAuMDE0LTAuMDI0LDAuMDMyLTAuMDQ2LDAuMDUtMC4wNjdjMC4
|
||||
wMDctMC4wMDksMC4wMTUtMC4wMTcsMC4wMjMtMC4wMjcgYzAuMDI1LTAuMDI0LDAuMDUxLTAuMDQ3LDAuMDc3LTAuMDY1YzAuMDEyLTAuMDA3LDAuMDIzLTAuMDE1LDAuMDM2LTAuMDJjMC4wMTktMC4wMTQsMC4wMzgtMC4wMjEsMC4wNTgtMC4wMyBjMC4wMTItMC4wMDYsMC4wMjUtMC4wMTEsMC4wMzctMC4wMTVjMC4wMjktMC4wMDgsMC4wNTctMC4wMTYsMC4wODgtMC4wMTljMC4wMDMsMCwwLjAwNi0wLjAwMSwwLjAxLTAuMDAxIGMwLjAzMi0wLjAwMywwLjA2NC0wL
|
||||
jAwMiwwLjA5NywwLjAwM2MwLjAwNywwLjAwMSwwLjAxNSwwLjAwMywwLjAyMywwLjAwNGMwLjAyNiwwLjAwNiwwLjA1MywwLjAxMiwwLjA3OSwwLjAyMSBjMC4wMDcsMC4wMDMsMC4wMTQsMC4wMDYsMC4wMjEsMC4wMDljMC4wMzEsMC4wMTQsMC4wNjIsMC4wMzEsMC4wOTEsMC4wNTFjMC4wMDIsMC4wMDIsMC4wMDQsMC4wMDMsMC4wMDcsMC4wMDYgYzAuMDM2LDAuMDIzLDAuMDcxLDAuMDUsMC4xMDQsMC4wODNjMC42NjgsMC42NTMsMC45LDAuNzE0LDIuMzk0LDAuNjE
|
||||
1YzAuNTQ2LTAuMDM3LDEuMDEyLTAuMDM4LDEuMzk0LTAuMDA3IGMwLjcwOSwwLjA2LDEuMTMxLDAuMjMsMS4yNCwwLjUxNWMwLjAzOCwwLjA5OSwwLjA1LDAuMTgsMC4wMjUsMC4yNUMyMy41MjIsMTUuODA5LDIzLjEyMiwxNS45MDQsMjIuMTIyLDE2LjAxNXogTTI5LjAwMSwxMy4zOCBjLTAuMDEsMC4wMDctMC4wMTksMC4wMTMtMC4wMzEsMC4wMTljMCwwLjAwMS0wLjAwMywwLjAwMy0wLjAwNiwwLjAwNGMtMC41MTEsMC4yNjktMS4zMjUsMC40MjktMi4xNzEsMC4zN
|
||||
TggYy0wLjM0NC0wLjAyNy0wLjUyNi0wLjA4Ny0wLjU0My0wLjE2NGMtMC4wMTItMC4wNTIsMC4wNTUtMC4xMTEsMC4xOTctMC4xNzFjMC4wNy0wLjAzLDAuMTUzLTAuMDYxLDAuMjU2LTAuMDg5IGMwLjU4NC0wLjE2OSwwLjkxLTAuNjA4LDAuNTk0LTAuODA1Yy0wLjMzNy0wLjIxMi0xLjQ5Mi0wLjM0NS0yLjAwNC0wLjIzMWMtMC4yMTcsMC4wNDktMC4zNDIsMC4wNTEtMC4zNzQsMC4wMTMgYy0wLjAwMS0wLjAwMS0wLjAwNC0wLjAwMy0wLjAwNS0wLjAwNmMtMC4wMDk
|
||||
tMC4wMTUtMC4wMDQtMC4wMzUsMC4wMTEtMC4wNjJjMC4wMTItMC4wMTYsMC4wMjYtMC4wMzEsMC4wNDctMC4wNDggYzAsMCwwLjAwMSwwLDAuMDAyLDBjMC4wMTktMC4wMTgsMC4wNDUtMC4wMzIsMC4wNzItMC4wNDZjMC4wMDItMC4wMDMsMC4wMDYtMC4wMDMsMC4wMS0wLjAwNmMwLjAyNy0wLjAxNCwwLjA1Ny0wLjAyNywwLjA5Mi0wLjA0MSBjMC4wMDUtMC4wMDIsMC4wMDgtMC4wMDMsMC4wMTEtMC4wMDVjMC4wMzctMC4wMTQsMC4wNzctMC4wMjgsMC4xMjEtMC4wN
|
||||
DJjMC4wMDEsMCwwLjAwMy0wLjAwMiwwLjAwNS0wLjAwMiBjMC4yNzYtMC4wOSwwLjY4Mi0wLjE2NCwxLjEtMC4yMTNjMC4wMDgtMC4wMDMsMC4wMTQtMC4wMDMsMC4wMjEtMC4wMDNjMC4wNjEtMC4wMDksMC4xMjMtMC4wMTQsMC4xODYtMC4wMiBjMC4wMDktMC4wMDIsMC4wMTktMC4wMDIsMC4wMjctMC4wMDNjMC4wNjEtMC4wMDQsMC4xMTktMC4wMDksMC4xOC0wLjAxM2MwLjAwOSwwLDAuMDE5LTAuMDAyLDAuMDI3LTAuMDAyIGMwLjA2NS0wLjAwMywwLjEzMS0wLjAwNywwLjE5My0wLjAwOWMwLjAwNCwwLDAuMDA2LDAsMC4wMDYsMGMwLjIwNi0wLjAwOCwwLjQtMC4wMDIsMC41NzEsMC4wMTIgYzAuOTQ4LDAuMDg2LDEuNzE2LDAuNDIxLDEuODY4LDAuODEzYzAuMDE1LDAuMDQsMC4wMjQsMC4wOCwwLjAyNywwLjEyM0MyOS41MSwxMi45NzksMjkuMzIsMTMuMjAxLDI5LjAwMSwxMy4zOHoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Red Hat</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="5">
|
||||
<name>Ubuntu</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-ubuntu.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik00MCwyNGMwLDguOC03LjIsMTYtMTYsMTZTOCwzMi44LDgsMjRTMTUuMiw4LDI0LDhTNDAsMTUuMiw0MCwyNHoiLz48cGF0aC
|
||||
BmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMjRjMCAzLjMtMi43IDYtNiA2LTMuMyAwLTYtMi43LTYtNnMyLjctNiA2LTZDMjcuMyAxOCAzMCAyMC43IDMwIDI0ek0xMiAyMS41YzEuNCAwIDIuNSAxLjEgMi41IDIuNXMtMS4xIDIuNS0yLjUgMi41UzkuNSAyNS40IDkuNSAyNCAxMC42IDIxLjUgMTIgMjEuNU0xMiAyMC41Yy0xLjkgMC0zLjUgMS42LTMuNSAzLjVzMS42IDMuNSAzLjUgMy41IDMuNS0xLjYgMy41LTMuNVMxMy45IDIwLjUgMTIgMjAuNXpNMzAgMzEuNWMxLjQg
|
||||
MCAyLjUgMS4xIDIuNSAyLjVzLTEuMSAyLjUtMi41IDIuNS0yLjUtMS4xLTIuNS0yLjVTMjguNiAzMS41IDMwIDMxLjVNMzAgMzAuNWMtMS45IDAtMy41IDEuNi0zLjUgMy41czEuNiAzLjUgMy41IDMuNSAzLjUtMS42IDMuNS0zLjVTMzEuOSAzMC41IDMwIDMwLjV6Ii8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTI0LDRDMTMsNCw0LDEzLDQsMjRzOSwyMCwyMCwyMHMyMC05LDIwLTIwUzM1LDQsMjQsNHogTTMyLjUsMzRjMCwxLjQtMS4xLDIuNS0yLjUsMi41IHMtMi
|
||||
41LTEuMS0yLjUtMi41YzAtMC4yLDAtMC41LDAuMS0wLjdDMjYuNSwzMy44LDI1LjMsMzQsMjQsMzRjLTUuMSwwLTkuMi0zLjgtOS45LTguN2MtMC40LDAuNy0xLjIsMS4yLTIuMSwxLjIgYy0xLjQsMC0yLjUtMS4xLTIuNS0yLjVzMS4xLTIuNSwyLjUtMi41YzAuOSwwLDEuNywwLjUsMi4xLDEuMmMwLjctNC45LDQuOC04LjcsOS45LTguN2MxLjMsMCwyLjUsMC4yLDMuNiwwLjcgYy0wLjEtMC4yLTAuMS0wLjQtMC4xLTAuN2MwLTEuNCwxLjEtMi41LDIuNS0yLjVzMi41
|
||||
LDEuMSwyLjUsMi41YzAsMS4yLTAuOCwyLjItMiwyLjRDMzIuNywxOC4zLDM0LDIxLDM0LDI0cy0xLjMsNS43LTMuNSw3LjYgQzMxLjcsMzEuOCwzMi41LDMyLjgsMzIuNSwzNHoiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMTEuNWMxLjQgMCAyLjUgMS4xIDIuNSAyLjUgMCAxLjQtMS4xIDIuNS0yLjUgMi41cy0yLjUtMS4xLTIuNS0yLjVDMjcuNSAxMi42IDI4LjYgMTEuNSAzMCAxMS41TTMwIDEwLjVjLTEuOSAwLTMuNSAxLjYtMy41IDMuNXMxLjYgMy41ID
|
||||
MuNSAzLjUgMy41LTEuNiAzLjUtMy41UzMxLjkgMTAuNSAzMCAxMC41ek0yNCAyNGMtMi42LTQuMS01LjItOC4xLTcuOC0xMi4yIi8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTE5LjEgMTAuN0gyMS4xVjI1LjFIMTkuMXoiIHRyYW5zZm9ybT0icm90YXRlKC0zMi40NjcgMjAuMTI3IDE3LjkxMSkiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQgMjNIMzguNFYyNUgyNHoiLz48Zz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQsMjRjLTIuNyw0LTUuMyw4LTgsMTIiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMTIuOCAyOUgyNy4yMDAwMDAwMDAwMDAwMDNWMzFIMTIuOHoiIHRyYW5zZm9ybT0icm90YXRlKC01Ni4zMTIgMTkuOTk4IDMwLjAwNikiLz48L2c+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Ubuntu</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="6">
|
||||
<name>Ubuntu server</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-ubuntu.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik00MCwyNGMwLDguOC03LjIsMTYtMTYsMTZTOCwzMi44LDgsMjRTMTUuMiw4LDI0LDhTNDAsMTUuMiw0MCwyNHoiLz48cGF0aC
|
||||
BmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMjRjMCAzLjMtMi43IDYtNiA2LTMuMyAwLTYtMi43LTYtNnMyLjctNiA2LTZDMjcuMyAxOCAzMCAyMC43IDMwIDI0ek0xMiAyMS41YzEuNCAwIDIuNSAxLjEgMi41IDIuNXMtMS4xIDIuNS0yLjUgMi41UzkuNSAyNS40IDkuNSAyNCAxMC42IDIxLjUgMTIgMjEuNU0xMiAyMC41Yy0xLjkgMC0zLjUgMS42LTMuNSAzLjVzMS42IDMuNSAzLjUgMy41IDMuNS0xLjYgMy41LTMuNVMxMy45IDIwLjUgMTIgMjAuNXpNMzAgMzEuNWMxLjQg
|
||||
MCAyLjUgMS4xIDIuNSAyLjVzLTEuMSAyLjUtMi41IDIuNS0yLjUtMS4xLTIuNS0yLjVTMjguNiAzMS41IDMwIDMxLjVNMzAgMzAuNWMtMS45IDAtMy41IDEuNi0zLjUgMy41czEuNiAzLjUgMy41IDMuNSAzLjUtMS42IDMuNS0zLjVTMzEuOSAzMC41IDMwIDMwLjV6Ii8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTI0LDRDMTMsNCw0LDEzLDQsMjRzOSwyMCwyMCwyMHMyMC05LDIwLTIwUzM1LDQsMjQsNHogTTMyLjUsMzRjMCwxLjQtMS4xLDIuNS0yLjUsMi41IHMtMi
|
||||
41LTEuMS0yLjUtMi41YzAtMC4yLDAtMC41LDAuMS0wLjdDMjYuNSwzMy44LDI1LjMsMzQsMjQsMzRjLTUuMSwwLTkuMi0zLjgtOS45LTguN2MtMC40LDAuNy0xLjIsMS4yLTIuMSwxLjIgYy0xLjQsMC0yLjUtMS4xLTIuNS0yLjVzMS4xLTIuNSwyLjUtMi41YzAuOSwwLDEuNywwLjUsMi4xLDEuMmMwLjctNC45LDQuOC04LjcsOS45LTguN2MxLjMsMCwyLjUsMC4yLDMuNiwwLjcgYy0wLjEtMC4yLTAuMS0wLjQtMC4xLTAuN2MwLTEuNCwxLjEtMi41LDIuNS0yLjVzMi41
|
||||
LDEuMSwyLjUsMi41YzAsMS4yLTAuOCwyLjItMiwyLjRDMzIuNywxOC4zLDM0LDIxLDM0LDI0cy0xLjMsNS43LTMuNSw3LjYgQzMxLjcsMzEuOCwzMi41LDMyLjgsMzIuNSwzNHoiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMTEuNWMxLjQgMCAyLjUgMS4xIDIuNSAyLjUgMCAxLjQtMS4xIDIuNS0yLjUgMi41cy0yLjUtMS4xLTIuNS0yLjVDMjcuNSAxMi42IDI4LjYgMTEuNSAzMCAxMS41TTMwIDEwLjVjLTEuOSAwLTMuNSAxLjYtMy41IDMuNXMxLjYgMy41ID
|
||||
MuNSAzLjUgMy41LTEuNiAzLjUtMy41UzMxLjkgMTAuNSAzMCAxMC41ek0yNCAyNGMtMi42LTQuMS01LjItOC4xLTcuOC0xMi4yIi8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTE5LjEgMTAuN0gyMS4xVjI1LjFIMTkuMXoiIHRyYW5zZm9ybT0icm90YXRlKC0zMi40NjcgMjAuMTI3IDE3LjkxMSkiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQgMjNIMzguNFYyNUgyNHoiLz48Zz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQsMjRjLTIuNyw0LTUuMyw4LTgsMTIiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMTIuOCAyOUgyNy4yMDAwMDAwMDAwMDAwMDNWMzFIMTIuOHoiIHRyYW5zZm9ybT0icm90YXRlKC01Ni4zMTIgMTkuOTk4IDMwLjAwNikiLz48L2c+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Ubuntu server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="7">
|
||||
<name>vCenter Server</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-vmware.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTAgNTAiIHdpZHRoPSI1MHB4IiBoZWlnaHQ9IjUwcHgiPjxwYXRoIGQ9Ik0gNDIuNDE0MDYzIDE1IEMgMzguODI0MjE5IDE1IDM2LjU3NDIxOSAxNy41IDM2LjU3NDIxOSAxNy41IEMgMzUuMzc4OTA2IDE1Ljk0MTQwNiAzMy43MzA0NjkgMTUuMDAzOTA2IDMwLjk0MTQwNiAxNS4wMDM5MDYgQyAyNy45OTYwOTQgMTUuMDAzOTA2IDI2LjA0Mjk2OSAxNy41IDI2LjA0Mjk2OSAxNy41IEMgMjQuODQ3NjU2IDE1Ljk0MTQwNiAyMi42ODc1IDE1IDIxIDE1IEMgMTguMzkwNjI1IDE1IDE2LjMyMDMxMyAxNi4xNTIzNDQgMTUuMDU0Njg4IDE5LjA1ODU5NCBMIDEwLjgyMDMxMyAyOC4zMjAzMTMgTCA2LjAzMTI1IDE2LjU1ODU5NCBDIDUuNDI1NzgxIDE1LjIyNjU2MyAzLjkzMzU5NCAxNC42MjUgMi41NDI5NjkgMTUuMjQ2MDk0IEMgMS4xNDg0MzggMTUuODcxMDk0IDAuNjM2NzE5IDE3LjQyNTc4MSAxLjI2NTYyNSAxOC43NTc4MTMgTCA3LjExMzI4MSAzMS45NDUzMTMgQyA4LjAzMTI1IDMzLjk0OTIxOSA5LjAwMzkwNiAzNSAxMC44MjAzMTMgMzUgQyAxMi43NjU2MjUgMzUgMTMuNjA5Mzc1IDMzLjg1NTQ2OSAxNC41MzEyNSAzMS45NDUzMTMgQyAxNC41MzEyNSAzMS45NDUzMTMgMTguNTExNzE5IDIzLjA2MjUgMTkgMjIgQyAxOS40ODgyODEgMjAuOTM3NSAyMC4zMDA3ODEgMjAgMjEuNSAyMCBDIDIyLjg3NSAyMCAyNCAyMS4xMjUgMjQgMjIuNSBMIDI0IDMyLjM3NSBDIDI0IDMzLjgyMDMxMyAyNS4wODU5MzggMzUgMjYuNTIzNDM4IDM1IEMgMjcuOTU3MDMxIDM1IDI5IDMzLjgyMDMxMyAyOSAzMi4zNzUgTCAyOSAyMi41IEMgMjkgMjEuMTI1IDMwLjEyNSAyMCAzMS41IDIwIEMgMzIuODc1IDIwIDM0IDIxLjEyNSAzNCAyMi41IEwgMzQgMzIuNSBDIDM0IDMzLjg3NSAzNS4xMjUgMzUgMzYuNSAzNSBDIDM3Ljg3NSAzNSAzOSAzMy44NzUgMzkgMzIuNSBMIDM5IDIyLjUgQyAzOSAyMS4xMjUgNDAuMTI1IDIwIDQxLjUgMjAgQyA0Mi44NzUgMjAgNDQgMjEuMTI1IDQ0IDIyLjUgTCA0NCAzMi41IEMgNDQgMzMuODc1IDQ1LjEyNSAzNSA0Ni41IDM1IEMgNDcuODc1IDM1IDQ5IDMzLjg3NSA0OSAzMi41IEwgNDkgMjEuMzU1NDY5IEMgNDkgMTcuNjE3MTg4IDQ2LjAxMTcxOSAxNSA0Mi40MTQwNjMgMTUgWiIvPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>vCenter Server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="8">
|
||||
<name>Windows</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-windows.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik02LDZoMTd2MTdINlY2eiIvPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik0yNS4wNDIsMjIuOTU4VjZINDJ2MTYuOTU4SDI1LjA0MnoiLz48cGF0aCBmaWxsPSIjMTk3NmQyIiBkPSJNNiwyNWgxN3YxN0g2VjI1eiIvPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik0yNSw0MlYyNWgxN3YxN0gyNXoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Windows</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="9">
|
||||
<name>Windows server</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-windows-server.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwMGIwZmYiIGQ9Ik0yMCAyNS4wMjZMNS4wMTEgMjUgNS4wMTIgMzcuNzQ0IDIwIDM5LjgxOHpNMjIgMjUuMDNMMjIgNDAuMDk1IDQyLjk5NSA0MyA0MyAyNS4wNjZ6TTIwIDguMjU2TDUgMTAuMzggNS4wMTQgMjMgMjAgMjN6TTIyIDcuOTczTDIyIDIzIDQyLjk5NSAyMyA0Mi45OTUgNXoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Windows server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="1">
|
||||
<name>Arch</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Arch</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="2">
|
||||
<name>Debian</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Debian</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="3">
|
||||
<name>Oracle Linux</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Oracle Linux</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="4">
|
||||
<name>Red Hat</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Red Hat</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="5">
|
||||
<name>Ubuntu</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Ubuntu</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="6">
|
||||
<name>Ubuntu server</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Ubuntu server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="7">
|
||||
<name>vCenter Server</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>vCenter Server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="8">
|
||||
<name>Windows</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Windows</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="9">
|
||||
<name>Windows server</name>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Windows server</friendlyname>
|
||||
</OSFamily>
|
||||
</Set>
|
||||
|
||||
|
||||
|
||||
@@ -4461,9 +4461,6 @@
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<fields_semantic>
|
||||
<image_attribute>logo</image_attribute>
|
||||
</fields_semantic>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
@@ -4473,15 +4470,7 @@
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="logo" xsi:type="AttributeImage">
|
||||
<display_max_width>96</display_max_width>
|
||||
<display_max_height>96</display_max_height>
|
||||
<storage_max_width>128</storage_max_width>
|
||||
<storage_max_height>128</storage_max_height>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<fields/>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
@@ -4489,9 +4478,6 @@
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="logo">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
@@ -4506,9 +4492,6 @@
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="logo">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
@@ -4591,9 +4574,6 @@
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="logo">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
<summary>
|
||||
|
||||
@@ -1104,7 +1104,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
//
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:Model' => 'Device Model',
|
||||
'Class:Model' => 'Model',
|
||||
'Class:Model+' => '',
|
||||
'Class:Model/ComplementaryName' => '%1$s - %2$s',
|
||||
'Class:Model/Attribute:brand_id' => 'Brand',
|
||||
|
||||
@@ -1240,7 +1240,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
//
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:Model' => 'Modèle de matériel',
|
||||
'Class:Model' => 'Modèle',
|
||||
'Class:Model+' => '',
|
||||
'Class:Model/ComplementaryName' => '%1$s - %2$s',
|
||||
'Class:Model/Attribute:brand_id' => 'Marque',
|
||||
|
||||
@@ -19,7 +19,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:FAQ/Attribute:summary+' => '',
|
||||
'Class:FAQ/Attribute:description' => 'Description',
|
||||
'Class:FAQ/Attribute:description+' => '',
|
||||
'Class:FAQ/Attribute:category_id' => 'Catégorie',
|
||||
'Class:FAQ/Attribute:category_id' => 'Categorie',
|
||||
'Class:FAQ/Attribute:category_id+' => '',
|
||||
'Class:FAQ/Attribute:category_name' => 'Nom catégorie',
|
||||
'Class:FAQ/Attribute:category_name+' => '',
|
||||
|
||||
@@ -238,11 +238,6 @@
|
||||
<action id="action:bulk delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="Ticketing">
|
||||
<actions>
|
||||
<action id="stimulus:ev_close">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="UserRequest">
|
||||
<actions>
|
||||
<action id="stimulus:ev_approve">allow</action>
|
||||
|
||||
@@ -307,9 +307,7 @@
|
||||
</field>
|
||||
<field id="servicesubcategory_id" xsi:type="AttributeExternalKey">
|
||||
<filter><![CDATA[SELECT ServiceSubcategory WHERE service_id = :this->service_id AND status != 'obsolete']]></filter>
|
||||
<dependencies>
|
||||
<attribute id="service_id"/>
|
||||
</dependencies>
|
||||
<dependencies/>
|
||||
<sql>servicesubcategory_id</sql>
|
||||
<target_class>ServiceSubcategory</target_class>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
|
||||
@@ -243,7 +243,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'Class:Service/Attribute:description' => 'Popis',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Balíček služeb',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Název rodiny služeb',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Dokumenty',
|
||||
|
||||
@@ -242,7 +242,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'Class:Service/Attribute:description' => 'Beskrivelse',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service familie',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Ydelses familie navn',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Dokument',
|
||||
@@ -500,7 +500,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Beskrivelse',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Kontakt',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Kunde',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -242,7 +242,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'Class:Service/Attribute:description' => 'Beschreibung',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service-Familie',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service-Familien-Name',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Dokumente',
|
||||
|
||||
@@ -268,7 +268,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:Service/Attribute:description' => 'Description',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service Family',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service Family Name',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Documents',
|
||||
@@ -526,7 +526,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Customers',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model',
|
||||
]);
|
||||
|
||||
@@ -268,7 +268,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
||||
'Class:Service/Attribute:description' => 'Description',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service Family',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service Family Name',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Documents',
|
||||
@@ -526,7 +526,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Customers',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model',
|
||||
]);
|
||||
|
||||
@@ -239,7 +239,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'Class:Service/Attribute:description' => 'Descripción',
|
||||
'Class:Service/Attribute:description+' => 'Descripción',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:servicefamily_name+' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:documents_list' => 'Documentos',
|
||||
|
||||
@@ -247,7 +247,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:Service/Attribute:description' => 'Description',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Famille de service',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Obligatoire pour que ce service soit visible dans le portal utilisateur',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nom Famille de service',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Documents',
|
||||
@@ -511,7 +511,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'Il doit y avoir au moins une équipe pour permettre l\'assignation des Tickets',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'Tous les contacts (Equipe ou Personne) pour ce modèle de support',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Clients',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'Tous les clients ayant ce modèle de support',
|
||||
'Class:DeliveryModel/Attribute:customers_list/UI:Links:Create:Button+' => 'Créer un %4$s',
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'Class:Service/Attribute:description' => 'Leírás',
|
||||
'Class:Service/Attribute:description+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Szolgáltatáscsalád',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Szolgáltatáscsalád név',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:documents_list' => 'Dokumentumok',
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'Class:Service/Attribute:description' => 'Descrizione',
|
||||
'Class:Service/Attribute:description+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Famiglia di Servizi',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nome della Famiglia di Servizi',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:documents_list' => 'Documenti',
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'Class:Service/Attribute:description' => '説明',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'サービスファミリ',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'サービスファミリ名',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => '文書',
|
||||
@@ -499,7 +499,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'Class:DeliveryModel/Attribute:description' => '説明',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => '連絡先',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => '顧客',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -243,7 +243,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'Class:Service/Attribute:description' => 'Omschrijving',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Servicecategorie',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Naam servicecategorie',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Documenten',
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'Class:Service/Attribute:description' => 'Opis',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Rodzina usług',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nazwa rodziny usług',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Dokumenty',
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'Class:Service/Attribute:description' => 'Descrição',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Família de serviços',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nome da família de serviços',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Documentos',
|
||||
|
||||
@@ -242,7 +242,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'Class:Service/Attribute:description' => 'Описание',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Пакет услуг',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Пакет услуг',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => 'Документы',
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'Class:Service/Attribute:description' => 'Popis',
|
||||
'Class:Service/Attribute:description+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Kategória služieb',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Názov rodiny služieb',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:documents_list' => 'Dokumenty',
|
||||
@@ -499,7 +499,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Popis',
|
||||
'Class:DeliveryModel/Attribute:description+' => '~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Kontakty',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Zákazníci',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -241,7 +241,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'Class:Service/Attribute:description' => 'Tanımlama',
|
||||
'Class:Service/Attribute:description+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service Family~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service Family Name~~',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:documents_list' => 'Documents~~',
|
||||
@@ -499,7 +499,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description~~',
|
||||
'Class:DeliveryModel/Attribute:description+' => '~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Customers~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -264,7 +264,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'Class:Service/Attribute:description' => '描述',
|
||||
'Class:Service/Attribute:description+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => '服务系列',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => '服务系列名称',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:documents_list' => '文档',
|
||||
|
||||
@@ -218,7 +218,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'Class:Service/Attribute:organization_name' => 'Název poskytovatele',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Balíček služeb',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Název rodiny služeb',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Popis',
|
||||
|
||||
@@ -217,7 +217,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'Class:Service/Attribute:organization_name' => 'Leverandør navn',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service familie',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Ydelses familie navn',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Beskrivelse',
|
||||
@@ -463,7 +463,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Beskrivelse',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Kontakt',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Kunde',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -217,7 +217,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'Class:Service/Attribute:organization_name' => 'Provider-Name',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service-Familie',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service-Familien-Name',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Beschreibung',
|
||||
|
||||
@@ -240,7 +240,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:Service/Attribute:organization_name' => 'Provider Name',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service Family',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service Family Name',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Description',
|
||||
@@ -486,7 +486,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Customers',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model',
|
||||
]);
|
||||
|
||||
@@ -240,7 +240,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
||||
'Class:Service/Attribute:organization_name' => 'Provider Name',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Service Family',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Service Family Name',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Description',
|
||||
@@ -486,7 +486,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Person) for this delivery model',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Customers',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model',
|
||||
]);
|
||||
|
||||
@@ -214,7 +214,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'Class:Service/Attribute:organization_name' => 'Proveedor',
|
||||
'Class:Service/Attribute:organization_name+' => 'Proveedor',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:servicefamily_name+' => 'Familia de Servicios',
|
||||
'Class:Service/Attribute:description' => 'Descripción',
|
||||
|
||||
@@ -214,7 +214,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:Service/Attribute:organization_name' => 'Nom fournisseur',
|
||||
'Class:Service/Attribute:organization_name+' => 'Nom commun',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Famille de service',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Obligatoire pour que ce service soit visible dans le portal utilisateur',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nom Famille de service',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:services_list/UI:Links:Create:Button+' => 'Créer un %4$s',
|
||||
@@ -478,7 +478,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Description',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'Il doit y avoir au moins une équipe pour permettre l\'assignation des Tickets',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'Tous les contacts (Equipe ou Personne) pour ce modèle de support',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Clients',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'Tous les clients ayant ce modèle de support',
|
||||
'Class:DeliveryModel/Attribute:customers_list/UI:Links:Create:Button+' => 'Créer un %4$s',
|
||||
|
||||
@@ -216,7 +216,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'Class:Service/Attribute:organization_name' => 'Szolgáltató név',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Szolgáltatáscsalád',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Szolgáltatáscsalád név',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Leírás',
|
||||
|
||||
@@ -215,7 +215,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'Class:Service/Attribute:organization_name' => 'Nome del Fornitore',
|
||||
'Class:Service/Attribute:organization_name+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Famiglia di Servizi',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nome della Famiglia di Servizi',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:description' => 'Descrizione',
|
||||
|
||||
@@ -215,7 +215,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'Class:Service/Attribute:organization_name' => 'プロバイダー名',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'サービスファミリ',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'サービスファミリ名',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => '説明',
|
||||
@@ -461,7 +461,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'Class:DeliveryModel/Attribute:description' => '説明',
|
||||
'Class:DeliveryModel/Attribute:description+' => '',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => '連絡先',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => '顧客',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -217,7 +217,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'Class:Service/Attribute:organization_name' => 'Naam leverancier',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Servicecategorie',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Naam servicecategorie',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Omschrijving',
|
||||
|
||||
@@ -215,7 +215,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'Class:Service/Attribute:organization_name' => 'Nazwa dostawcy',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Rodzina usług',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nazwa rodziny usług',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Opis',
|
||||
|
||||
@@ -215,7 +215,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'Class:Service/Attribute:organization_name' => 'Nome do provedor',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Família de serviços',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Nome da família de serviços',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Descrição',
|
||||
|
||||
@@ -216,7 +216,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'Class:Service/Attribute:organization_name' => 'Поставщик',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Пакет услуг',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Пакет услуг',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => 'Описание',
|
||||
|
||||
@@ -215,7 +215,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'Class:Service/Attribute:organization_name' => 'Meno poskytovateľa',
|
||||
'Class:Service/Attribute:organization_name+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Kategória služieb',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Názov rodiny služieb',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:description' => 'Popis',
|
||||
@@ -461,7 +461,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'Class:DeliveryModel/Attribute:description' => 'Popis',
|
||||
'Class:DeliveryModel/Attribute:description+' => '~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list' => 'Kontakty',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'There must be at least one team to enable Ticket assignment~~',
|
||||
'Class:DeliveryModel/Attribute:contacts_list+' => 'All the contacts (Teams and Persons) for this delivery model~~',
|
||||
'Class:DeliveryModel/Attribute:customers_list' => 'Zákazníci',
|
||||
'Class:DeliveryModel/Attribute:customers_list+' => 'All the customers having this delivering model~~',
|
||||
]);
|
||||
|
||||
@@ -216,7 +216,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'Class:Service/Attribute:organization_name' => 'Sağlayıcı Adı',
|
||||
'Class:Service/Attribute:organization_name+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_id' => 'Servis Ailesi',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '~~',
|
||||
'Class:Service/Attribute:servicefamily_name' => 'Servis Aile Adı',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '~~',
|
||||
'Class:Service/Attribute:description' => 'Tanımlama',
|
||||
|
||||
@@ -236,7 +236,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'Class:Service/Attribute:organization_name' => '供应商名称',
|
||||
'Class:Service/Attribute:organization_name+' => '',
|
||||
'Class:Service/Attribute:servicefamily_id' => '服务系列',
|
||||
'Class:Service/Attribute:servicefamily_id+' => 'Required for this service to be visible on User Portal~~',
|
||||
'Class:Service/Attribute:servicefamily_id+' => '',
|
||||
'Class:Service/Attribute:servicefamily_name' => '服务系列名称',
|
||||
'Class:Service/Attribute:servicefamily_name+' => '',
|
||||
'Class:Service/Attribute:description' => '描述',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<QueryOQL alias="QueryOQL" id="8">
|
||||
<name>L'agent du Ticket</name>
|
||||
<name>L'agent du ticket</name>
|
||||
<description>Utilisable dans les notifications, pour informer l'agent en charge du ticket.</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Person WHERE id=:this->agent_id]]></oql>
|
||||
@@ -9,8 +9,9 @@
|
||||
<finalclass>QueryOQL</finalclass>
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="4">
|
||||
<name>L'agent du Ticket s'il n'a pas déclenché la notification</name>
|
||||
<description>Utilisable dans les notifications, pour informer l'agent en charge du ticket, sauf si c'est l'agent lui-même qui déclenche la notification.</description>
|
||||
<name>L'agent du ticket s'il n'a pas déclenché la notification</name>
|
||||
<description>Utilisable dans les notifications, pour informer l'agent en charge du ticket, sauf si c'est l'agent lui-même qui déclenche la notification
|
||||
</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Person WHERE id=:this->agent_id AND id != :current_contact_id]]></oql>
|
||||
<fields>id,email</fields>
|
||||
@@ -18,7 +19,7 @@
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="3">
|
||||
<name>Le demandeur et les contacts liés au Ticket</name>
|
||||
<description>Utilisable dans les notifications, pour informer le demandeur ainsi que tous les contacts liés au ticket.</description>
|
||||
<description>Utilisable dans les notifications, pour informer le demandeur ainsi que tout les contacts liés au ticket</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Contact AS C JOIN lnkContactToTicket AS L ON L.contact_id=C.id WHERE L.ticket_id=:this->id
|
||||
UNION SELECT Person WHERE id=:this->caller_id
|
||||
@@ -28,7 +29,7 @@
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="1">
|
||||
<name>Le demandeur du Ticket</name>
|
||||
<description>Utilisable dans les notifications, pour informer le demandeur du ticket.</description>
|
||||
<description>Utilisable dans les notifications, pour informer le demandeur du ticket</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Person WHERE id=:this->caller_id]]></oql>
|
||||
<fields>id,email</fields>
|
||||
@@ -36,7 +37,7 @@
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="2">
|
||||
<name>Les contacts liés au Ticket</name>
|
||||
<description>Utilisable dans les notifications, pour informer tous les contacts liés au ticket.</description>
|
||||
<description>Utilisable dans les notifications, pour informer tout les contacts liés au ticket</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Contact AS C JOIN lnkContactToTicket AS L ON L.contact_id=C.id WHERE L.ticket_id=:this->id]]></oql>
|
||||
<fields>id,email</fields>
|
||||
@@ -44,7 +45,7 @@
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="7">
|
||||
<name>Le manager du demandeur</name>
|
||||
<description>Utilisable dans les notifications, pour informer le manager du demandeur d'un ticket.</description>
|
||||
<description>Utilisable dans les notifications, pour informer le manager du demandeur d'un Ticket</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Person AS manager JOIN Person AS employee ON employee.manager_id = manager.id WHERE employee.id=:this->caller_id]]></oql>
|
||||
<fields>id,email</fields>
|
||||
@@ -53,7 +54,7 @@
|
||||
<QueryOQL alias="QueryOQL" id="9">
|
||||
<name>La personne qui a déclenché la notification</name>
|
||||
<description>Utilisable dans les notifications, pour informer la personne qui a effectué l'action qui a provoqué la notification.
|
||||
Utilisée seule, cette requête retourne la personne liée à l'utilisateur iTop qui l'exécute.
|
||||
Utilisée seule, cette requête retourne la personne liée à l'utilisateur iTop qui l'execute.
|
||||
</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Person WHERE id = :current_contact_id]]></oql>
|
||||
@@ -73,7 +74,7 @@
|
||||
<QueryOQL alias="QueryOQL" id="5">
|
||||
<name>Les membres de l'équipe hors l'agent</name>
|
||||
<description>Utilisable dans les notifications, pour informer les membres de l'équipe en charge du ticket.
|
||||
L'agent lui-même est exclu de cette liste.
|
||||
L'agent lui-même est exclus de cette liste.
|
||||
</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Person AS P JOIN lnkPersonToTeam AS L ON L.person_id=P.id
|
||||
@@ -102,7 +103,7 @@
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="12">
|
||||
<name>Les contacts d'un Service</name>
|
||||
<description>Utilisable dans les notifications, pour informer les contacts liés au service courant.</description>
|
||||
<description>Utilisable dans les notifications, pour informer les contacts liés au Service courant.</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Contact AS C JOIN lnkContactToService AS L ON L.contact_id=C.id
|
||||
WHERE L.service_id = :this->id
|
||||
@@ -112,7 +113,7 @@
|
||||
</QueryOQL>
|
||||
<QueryOQL alias="QueryOQL" id="13">
|
||||
<name>Les contacts d'un Contrat</name>
|
||||
<description>Utilisable dans les notifications, pour informer les contacts liés au contrat courant.</description>
|
||||
<description>Utilisable dans les notifications, pour informer les contacts liés au Contrat courant.</description>
|
||||
<is_template>yes</is_template>
|
||||
<oql><![CDATA[SELECT Contact AS C JOIN lnkContactToContract AS L ON L.contact_id=C.id
|
||||
WHERE L.contract_id = :this->id
|
||||
|
||||
@@ -12,7 +12,8 @@ SetupWebPage::AddModule(
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-structure/2.7.1 || itop-portal/3.0.0', // itop-portal : module_design_itop_design->module_designs->itop-portal
|
||||
'itop-structure/2.7.1',
|
||||
'itop-portal/3.0.0', // module_design_itop_design->module_designs->itop-portal
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
|
||||
@@ -708,7 +708,6 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Triger \'aktualizace objektu\'',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Spustit při aktualizaci objektu [podřízené třídy] dané třídy',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Cílová pole',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -707,7 +707,6 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)~~',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target fields~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -704,7 +704,6 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (bei Objektanpassung)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger bei Objektanpassung einer gegebenen Klasse oder Kindklasse',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Ziel-Felder',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -801,7 +801,6 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target fields',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -784,7 +784,6 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
||||
Dict::Add('EN GB', 'British English', 'British English', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target fields',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -695,7 +695,6 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Disparador (actualizando un objecto)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Disparador al actualizar un objeto de la clase dada [o una clase hija]',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Campos objetivo',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => 'Campos que serán monitorizados',
|
||||
]);
|
||||
|
||||
@@ -746,7 +746,6 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Déclencheur sur la modification d\'un objet',
|
||||
'Class:TriggerOnObjectUpdate+' => '',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'Ce filtre est appliqué après la sauvegarde en base de l\'objet modifié. Il restreint les objets qui vont déclencher les actions.',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Attributs cible',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -702,7 +702,6 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Eseményindító (objektum frissítéskor)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Az adott osztály [egy gyermekosztálya] objektumának frissítésekor elinduló eseményindító',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Célmezők',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -702,7 +702,6 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (alla modifica dell\'oggetto)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger alla modifica dell\'oggetto di [una classe figlia della] classe specificata',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Campi di destinazione',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -706,7 +706,6 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)~~',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target fields~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '~~',
|
||||
]);
|
||||
|
||||
@@ -704,7 +704,6 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (bij het aanpassen van een object)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger bij het aanpassen van een object van de opgegeven klasse (of subklasse ervan)',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Doelvelden',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -704,7 +704,6 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Wyzwalacz (przy aktualizacji obiektu)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Wyzwalanie przy aktualizacji obiektu [klasy potomnej] danej klasy',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Pola docelowe',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -702,7 +702,6 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Gatilho (na atualização do objeto)',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Gatilho na atualização de objeto de [uma classe filha] de uma determinada classe',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Campos de destino',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -707,7 +707,6 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Триггер на обновление объекта',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Триггер на обновление объекта данного или дочернего класса',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Отслеживаемые поля',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => 'Поля объекта, при обновлении которых сработает триггер',
|
||||
]);
|
||||
|
||||
@@ -720,7 +720,6 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)~~',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target fields~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '~~',
|
||||
]);
|
||||
|
||||
@@ -707,7 +707,6 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)~~',
|
||||
'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target fields~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
@@ -739,7 +739,6 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'Class:TriggerOnObjectUpdate' => '触发器 (对象更新时)',
|
||||
'Class:TriggerOnObjectUpdate+' => '指定类型或子类型对象更新时的触发器',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:filter+' => 'This filter is computed after the object update in database. It restricts the objects which can trigger the actions~~',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => '目标字段',
|
||||
'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '',
|
||||
]);
|
||||
|
||||
17
git-split.md
Normal file
17
git-split.md
Normal file
@@ -0,0 +1,17 @@
|
||||
git copy of one file into two files without loosing history
|
||||
|
||||
```
|
||||
git mv foo bar
|
||||
git commit
|
||||
|
||||
SAVED=`git rev-parse HEAD`
|
||||
git reset --hard HEAD^
|
||||
git mv foo copy
|
||||
git commit
|
||||
|
||||
git merge $SAVED # This will generate conflicts
|
||||
git commit -a # Trivially resolved like this
|
||||
|
||||
git mv copy foo
|
||||
git commit
|
||||
```
|
||||
@@ -1,3 +1,19 @@
|
||||
/**
|
||||
* Image renderer plugin for TomSelect
|
||||
*/
|
||||
TomSelect.define('image_renderer', function(options) {
|
||||
this.settings.render.option = function(data, escape) {
|
||||
return `<div class="ibo-input-select-icon--menu--item">
|
||||
<img src="${options['images_resource_path']+escape(data.value)}" alt="${data.text}" />${escape(data.text)}
|
||||
</div>`;
|
||||
};
|
||||
this.settings.render.item = function(data, escape) {
|
||||
return `<div class="ibo-input-select-icon--menu--item">
|
||||
<img src="${options['images_resource_path']+escape(data.value)}" alt="${data.text}"/>${escape(data.text)}
|
||||
</div>`;
|
||||
};
|
||||
});
|
||||
|
||||
class ChoicesElement extends HTMLSelectElement {
|
||||
|
||||
// register the custom element
|
||||
@@ -16,6 +32,14 @@ class ChoicesElement extends HTMLSelectElement {
|
||||
this.plugins.push('remove_button');
|
||||
}
|
||||
|
||||
// plugins
|
||||
if(this.hasAttribute('data-plugins')){
|
||||
const aPlugins = JSON.parse(this.getAttribute('data-plugins'));
|
||||
Array.from(aPlugins).values().forEach(plugin => {
|
||||
this.plugins.push(plugin);
|
||||
});
|
||||
}
|
||||
|
||||
const options = {
|
||||
plugins: this.plugins,
|
||||
wrapperClass: 'ts-wrapper ibo-input-wrapper ibo-input-select-wrapper--with-buttons ibo-input-select-autocomplete-wrapper',
|
||||
@@ -29,7 +53,7 @@ class ChoicesElement extends HTMLSelectElement {
|
||||
};
|
||||
|
||||
if (this.getAttribute('data-tom-select-disable-auto-complete')) {
|
||||
// options.controlInput = null;
|
||||
options.controlInput = null;
|
||||
}
|
||||
if (this.getAttribute('data-tom-select-max-items-selected') && this.getAttribute('data-tom-select-max-items-selected') !== '') {
|
||||
options.maxItems = parseInt(this.getAttribute('data-tom-select-max-items-selected'));
|
||||
@@ -43,3 +67,4 @@ class ChoicesElement extends HTMLSelectElement {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ class TurboStreamEvent extends HTMLElement {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(event);
|
||||
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
|
||||
83
js/layouts/dashboard/dashboard-grid-slot.js
Normal file
83
js/layouts/dashboard/dashboard-grid-slot.js
Normal file
@@ -0,0 +1,83 @@
|
||||
class IboGridSlot extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
connectedCallback() {
|
||||
|
||||
/** @type {string} unique cell id */
|
||||
this.id = '';
|
||||
|
||||
/** @type {number} */
|
||||
this.iPosX = this.getAttribute('gs-x') ? parseInt(this.getAttribute('gs-x'), 10) : 0;
|
||||
|
||||
/** @type {number} */
|
||||
this.iPostY = this.getAttribute('gs-y') ? parseInt(this.getAttribute('gs-y'), 10) : 0;
|
||||
|
||||
/** @type {number} */
|
||||
this.iWidth = this.getAttribute('gs-w') ? parseInt(this.getAttribute('gs-w'), 10) : 1;
|
||||
|
||||
/** @type {number} */
|
||||
this.iHeight = this.getAttribute('gs-h') ? parseInt(this.getAttribute('gs-h'), 10) : 1;
|
||||
|
||||
/** @type {IboDashlet|null} contained dashlet id */
|
||||
this.sDashletId = null;
|
||||
/** @type {IboDashlet|null} contained dashlet element */
|
||||
this.oDashlet = this.querySelector('ibo-dashlet') || null;
|
||||
|
||||
/** @type {Object} freeform metadata */
|
||||
this.meta = {};
|
||||
}
|
||||
|
||||
static MakeNew(oDashletElem, aOptions = {}) {
|
||||
const oSlot = document.createElement('ibo-dashboard-grid-slot');
|
||||
oDashletElem.classList.add("grid-stack-item-content");
|
||||
|
||||
oSlot.appendChild(oDashletElem);
|
||||
oSlot.classList.add("grid-stack-item");
|
||||
oSlot.oDashlet = oDashletElem;
|
||||
|
||||
return oSlot;
|
||||
}
|
||||
|
||||
Serialize(bIncludeHtml = false) {
|
||||
const oDashlet = this.oDashlet;
|
||||
|
||||
const aSlotData = {
|
||||
position_x: this.iPosX,
|
||||
position_y: this.iPostY,
|
||||
width: this.iWidth,
|
||||
height: this.iHeight
|
||||
};
|
||||
|
||||
const aDashletData = oDashlet ? oDashlet.Serialize(bIncludeHtml) : {};
|
||||
|
||||
return {
|
||||
...aSlotData,
|
||||
dashlet: {...aDashletData}
|
||||
};
|
||||
}
|
||||
|
||||
static observedAttributes = ['gs-x', 'gs-y', 'gs-w', 'gs-h'];
|
||||
|
||||
|
||||
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
switch (name) {
|
||||
case 'gs-x':
|
||||
this.iPosX = parseInt(newValue, 10) || 0;
|
||||
break;
|
||||
case 'gs-y':
|
||||
this.iPostY = parseInt(newValue, 10) || 0;
|
||||
break;
|
||||
case 'gs-w':
|
||||
this.iWidth = parseInt(newValue, 10) || 1;
|
||||
break;
|
||||
case 'gs-h':
|
||||
this.iHeight = parseInt(newValue, 10) || 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ibo-dashboard-grid-slot', IboGridSlot);
|
||||
161
js/layouts/dashboard/dashboard-grid.js
Normal file
161
js/layouts/dashboard/dashboard-grid.js
Normal file
@@ -0,0 +1,161 @@
|
||||
class IboGrid extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
||||
/** @type {number} */
|
||||
this.columnsCount = 12;
|
||||
/** @type {boolean} unused yet*/
|
||||
this.bEditable = false;
|
||||
/** @type {GridStack|null} GridStack instance */
|
||||
this.oGrid = null;
|
||||
/** @type {Array<IboGridSlot>} */
|
||||
this.aSlots = [];
|
||||
|
||||
|
||||
this.SetupGrid();
|
||||
}
|
||||
|
||||
SetupGrid() {
|
||||
let aCandidateSlots = Array.from(this.querySelectorAll('ibo-dashboard-grid-slot'));
|
||||
aCandidateSlots.forEach(oSlot => {
|
||||
const aAttrs = ['gs-x', 'gs-y', 'gs-w', 'gs-h', 'id'];
|
||||
aAttrs.forEach(sAttr => {
|
||||
const sVal = oSlot.getAttribute(sAttr) || oSlot.getAttribute('data-'+sAttr);
|
||||
if (sVal !== null) {
|
||||
oSlot.setAttribute(sAttr, sVal);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.oGrid = GridStack.init({
|
||||
column: this.columnsCount,
|
||||
marginTop: 8,
|
||||
marginLeft: 8,
|
||||
marginRight: 0,
|
||||
marginBottom: 0,
|
||||
resizable: {handles: 'all'},
|
||||
disableDrag: true,
|
||||
disableResize: true,
|
||||
float: true
|
||||
}, this);
|
||||
}
|
||||
|
||||
getSlots() {
|
||||
return this.oGrid.getGridItems();
|
||||
}
|
||||
|
||||
SetEditable(bIsEditable) {
|
||||
this.bEditable = bIsEditable;
|
||||
if (this.oGrid !== null) {
|
||||
this.oGrid.enableMove(bIsEditable);
|
||||
this.oGrid.enableResize(bIsEditable);
|
||||
}
|
||||
}
|
||||
|
||||
GetDashletElement(sDashletId) {
|
||||
const aSlots = this.getSlots();
|
||||
|
||||
for (let oSlot of aSlots) {
|
||||
|
||||
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === sDashletId) {
|
||||
return oSlot.oDashlet;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
AddDashlet(sDashlet, aOptions = {}) {
|
||||
// Get the dashlet as an object
|
||||
const oParser = new DOMParser();
|
||||
const oDocument = oParser.parseFromString(sDashlet, 'text/html');
|
||||
const oDashlet = oDocument.body.firstChild;
|
||||
|
||||
const oSlot = IboGridSlot.MakeNew(oDashlet);
|
||||
|
||||
this.append(oSlot);
|
||||
|
||||
let aDefaultOptions = {
|
||||
autoPosition: !(aOptions.hasOwnProperty('x') || aOptions.hasOwnProperty('y')),
|
||||
}
|
||||
this.oGrid.makeWidget(oSlot, Object.assign(aDefaultOptions, aOptions));
|
||||
|
||||
return oDashlet.sDashletId;
|
||||
}
|
||||
|
||||
RefreshDashlet (sDashlet, aOptions = {}) {
|
||||
const oParser = new DOMParser();
|
||||
const oDocument = oParser.parseFromString(sDashlet, 'text/html');
|
||||
const oNewDashlet = oDocument.body.firstElementChild;
|
||||
|
||||
// Can't use oNewDashet.sDashletId as it's not in the DOM yet and connectedCallback hasn't been called yet
|
||||
const oExistingDashlet = this.GetDashletElement(oNewDashlet.getAttribute('data-dashlet-id') );
|
||||
|
||||
// Copy attributes
|
||||
for (const sAttr of oNewDashlet.attributes) {
|
||||
oExistingDashlet.setAttribute(sAttr.name, sAttr.value);
|
||||
}
|
||||
|
||||
// If we refresh a dashlet, its parent slot remains the same, we just need to update its content
|
||||
let oSlotForExistingDashlet = null;
|
||||
const aSlots = this.getSlots();
|
||||
for (let oSlot of aSlots) {
|
||||
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === oNewDashlet.getAttribute('data-dashlet-id')) {
|
||||
oSlotForExistingDashlet = oSlot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// There must be a slot for the existing dashlet
|
||||
if(oSlotForExistingDashlet !== null) {
|
||||
this.oGrid.removeWidget(oSlotForExistingDashlet);
|
||||
oSlotForExistingDashlet.innerHTML = oNewDashlet.outerHTML;
|
||||
this.oGrid.makeWidget(oSlotForExistingDashlet);
|
||||
}
|
||||
}
|
||||
|
||||
CloneDashlet(sDashletId) {
|
||||
const aSlots = this.getSlots();
|
||||
for (let oSlot of aSlots) {
|
||||
|
||||
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === sDashletId) {
|
||||
const sWidth = oSlot.iWidth;
|
||||
const sHeight = oSlot.iHeight;
|
||||
|
||||
// Ask a new rendered dashlet to avoid duplicating IDs
|
||||
// Still we'll copy width and height
|
||||
this.closest('ibo-dashboard')?.AddNewDashlet(oSlot.oDashlet.sType, oSlot.oDashlet.formData, {
|
||||
'w': sWidth,
|
||||
'h': sHeight
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
RemoveDashlet(sDashletId) {
|
||||
const aSlots = this.getSlots();
|
||||
for (let oSlot of aSlots) {
|
||||
if (oSlot.oDashlet && oSlot.oDashlet.sDashletId === sDashletId) {
|
||||
this.oGrid.removeWidget(oSlot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearGrid() {
|
||||
this.oGrid.removeAll();
|
||||
}
|
||||
|
||||
Serialize(bIncludeHtml = false) {
|
||||
const aSlots = this.getSlots();
|
||||
|
||||
return aSlots.reduce((aAccumulator, oSlot) => {
|
||||
aAccumulator[oSlot.oDashlet.sDashletId] = oSlot.Serialize(bIncludeHtml);
|
||||
return aAccumulator;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ibo-dashboard-grid', IboGrid);
|
||||
371
js/layouts/dashboard/dashboard.js
Normal file
371
js/layouts/dashboard/dashboard.js
Normal file
@@ -0,0 +1,371 @@
|
||||
class IboDashboard extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/** @type {string} */
|
||||
this.sId = "";
|
||||
/** @type {string} */
|
||||
this.sTitle = "";
|
||||
/** @type {boolean} unused yet */
|
||||
this.isEditable = false;
|
||||
/** @type {boolean} */
|
||||
this.bEditMode = false;
|
||||
/** @type {boolean} unused yet */
|
||||
this.bAutoRefresh = false;
|
||||
/** @type {number} unused yet */
|
||||
this.iRefreshRate = 0;
|
||||
/** @type {IboGrid|null} */
|
||||
this.oGrid = null;
|
||||
/** @type {string|null} unused yet */
|
||||
this.refreshUrl = null;
|
||||
/** @type {string|null} unused yet */
|
||||
this.csrfToken = null;
|
||||
/** @type {number} Payload schema version */
|
||||
this.schemaVersion = 2;
|
||||
|
||||
/** @type {object|null} Last saved state for cancel functionality, unused yet */
|
||||
this.aLastSavedState = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.sId = this.getAttribute("id");
|
||||
this.bEditMode = (this.getAttribute("data-edit-mode") === "edit");
|
||||
this.SetupGrid();
|
||||
|
||||
this.BindEvents();
|
||||
}
|
||||
|
||||
BindEvents() {
|
||||
document.getElementById('ibo-dashboard-menu-edit-'+this.sId)?.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.ToggleEditMode();
|
||||
document.getElementById('ibo-dashboard-menu-edit-'+this.sId)?.classList.toggle('active', this.GetEditMode());
|
||||
});
|
||||
|
||||
this.querySelector('[data-role="ibo-button"][name="save"]')?.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.Save()
|
||||
});
|
||||
|
||||
this.querySelector('[data-role="ibo-button"][name="cancel"]')?.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
if (this.aLastSavedState) {
|
||||
this.Load(this.aLastSavedState);
|
||||
}
|
||||
this.SetEditMode(false);
|
||||
});
|
||||
|
||||
// TODO 3.3 Add event listener to dashboard toggler to get custom/default dashboard switching
|
||||
// TODO 3.3 require load method that's not finished yet
|
||||
|
||||
// Bind IboDashboard object to these listener so we can access current instance
|
||||
this._ListenToDashletFormSubmission = this._ListenToDashletFormSubmission.bind(this);
|
||||
this._ListenToDashletFormCancellation = this._ListenToDashletFormCancellation.bind(this);
|
||||
}
|
||||
SetupGrid() {
|
||||
if(this.oGrid !== null){
|
||||
return;
|
||||
}
|
||||
|
||||
this.oGrid = this.querySelector('ibo-dashboard-grid');
|
||||
}
|
||||
|
||||
|
||||
GetEditMode() {
|
||||
return this.bEditMode;
|
||||
}
|
||||
|
||||
ToggleEditMode(){
|
||||
this.SetEditMode(!this.bEditMode);
|
||||
}
|
||||
|
||||
SetEditMode(bEditMode) {
|
||||
this.bEditMode = bEditMode;
|
||||
|
||||
this.oGrid.SetEditable(this.bEditMode);
|
||||
if(this.bEditMode){
|
||||
// TODO 3.3 If we are in default dashboard display, change to custom to allow editing
|
||||
// TODO 3.3 Get the custom dashboard and load it, show a tooltip on the dashboard toggler to explain that we switched to custom mode
|
||||
this.aLastSavedState = this.Serialize(true);
|
||||
this.setAttribute("data-edit-mode", "edit");
|
||||
}
|
||||
else{
|
||||
this.setAttribute("data-edit-mode", "view");
|
||||
}
|
||||
}
|
||||
|
||||
AddNewDashlet(sDashletClass, sDashletValues, aDashletOptions = {}) {
|
||||
let sNewDashletUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet&dashlet_class='+encodeURIComponent(sDashletClass);
|
||||
|
||||
if(sDashletValues.length > 0) {
|
||||
sNewDashletUrl += '&values=' + encodeURIComponent(sDashletValues);
|
||||
}
|
||||
|
||||
fetch(sNewDashletUrl)
|
||||
.then(async data => {
|
||||
|
||||
const sDashletId = this.oGrid.AddDashlet(await data.text(), aDashletOptions);
|
||||
|
||||
// TODO 3.3 Either open the dashlet form right away, or just enter edit mode
|
||||
this.EditDashlet(sDashletId);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
RefreshDashlet(oDashlet) {
|
||||
let sGetDashletUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet&dashlet_class=' + encodeURIComponent(oDashlet.sType)
|
||||
+'&dashlet_id=' + encodeURIComponent(oDashlet.sDashletId);
|
||||
|
||||
if(oDashlet.formData.length > 0) {
|
||||
sGetDashletUrl += '&values=' + encodeURIComponent(oDashlet.formData);
|
||||
}
|
||||
|
||||
return fetch(sGetDashletUrl)
|
||||
.then(async data => {
|
||||
|
||||
this.oGrid.RefreshDashlet(await data.text());
|
||||
});
|
||||
}
|
||||
|
||||
HideDashletTogglers() {
|
||||
const aTogglers = document.querySelector('.ibo-dashlet-panel--entries');
|
||||
aTogglers.classList.add('ibo-is-hidden');
|
||||
}
|
||||
|
||||
ShowDashletTogglers() {
|
||||
const aTogglers = document.querySelector('.ibo-dashlet-panel--entries');
|
||||
aTogglers.classList.remove('ibo-is-hidden');
|
||||
}
|
||||
|
||||
SetDashletForm(sFormData) {
|
||||
const oFormContainer = document.querySelector('.ibo-dashlet-panel--form-container');
|
||||
oFormContainer.innerHTML = sFormData;
|
||||
oFormContainer.classList.remove('ibo-is-hidden');
|
||||
}
|
||||
|
||||
ClearDashletForm() {
|
||||
const oFormContainer = document.querySelector('.ibo-dashlet-panel--form-container');
|
||||
oFormContainer.innerHTML = '';
|
||||
oFormContainer.classList.add('ibo-is-hidden');
|
||||
}
|
||||
|
||||
DisableFormButtons() {
|
||||
const aButtons = this.querySelectorAll('.ibo-dashboard--form--actions button');
|
||||
aButtons.forEach( (oButton) => {
|
||||
oButton.setAttribute('disabled', 'disabled');
|
||||
});
|
||||
}
|
||||
|
||||
EnableFormButtons() {
|
||||
const aButtons = this.querySelectorAll('.ibo-dashboard--form--actions button');
|
||||
aButtons.forEach( (oButton) => {
|
||||
oButton.removeAttribute('disabled');
|
||||
});
|
||||
}
|
||||
|
||||
EditDashlet(sDashletId) {
|
||||
const oDashlet = this.oGrid.GetDashletElement(sDashletId);
|
||||
const me = this;
|
||||
|
||||
// Create backdrop to block interactions with other dashlets
|
||||
if(this.oGrid.querySelector('.ibo-dashboard--grid--backdrop') === null) {
|
||||
const oBackdrop = document.createElement("div");
|
||||
oBackdrop.classList.add('ibo-dashboard--grid--backdrop');
|
||||
this.oGrid.append(oBackdrop);
|
||||
}
|
||||
|
||||
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'edit');
|
||||
|
||||
// Disable dashboard buttons so we need to finish this edition first
|
||||
this.DisableFormButtons();
|
||||
|
||||
// Fetch dashlet form from server
|
||||
let sGetashletFormUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.get_dashlet_form&dashlet_class='+encodeURIComponent(oDashlet.sType);
|
||||
|
||||
if(oDashlet.formData.length > 0) {
|
||||
sGetashletFormUrl += '&values=' + encodeURIComponent(oDashlet.formData);
|
||||
}
|
||||
|
||||
fetch(sGetashletFormUrl)
|
||||
.then(async formData => {
|
||||
const sFormData = await formData.text();
|
||||
|
||||
this.HideDashletTogglers();
|
||||
this.SetDashletForm(sFormData);
|
||||
|
||||
// Listen to form submission event and cancellation
|
||||
document.addEventListener('itop:TurboStreamEvent', me._ListenToDashletFormSubmission);
|
||||
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').addEventListener('click', me._ListenToDashletFormCancellation);
|
||||
});
|
||||
}
|
||||
|
||||
_ListenToDashletFormSubmission(event) {
|
||||
const oDashlet = this.querySelector('ibo-dashlet[data-edit-mode="edit"]');
|
||||
const sDashletId = oDashlet.GetDashletId();
|
||||
|
||||
if(event.detail.id === oDashlet.sType + '-turbo-stream-event' && event.detail.valid === "1") {
|
||||
// Remove events
|
||||
document.addEventListener('itop:TurboStreamEvent', this._ListenToDashletFormSubmission);
|
||||
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').removeEventListener('click', this._ListenToDashletFormCancellation);
|
||||
|
||||
// Notify it all went well
|
||||
CombodoToast.OpenToast('Dashlet created/updated', 'success');
|
||||
|
||||
// Clean edit mode
|
||||
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
|
||||
this.ShowDashletTogglers();
|
||||
this.ClearDashletForm();
|
||||
|
||||
// Update local dashlet and refresh it
|
||||
oDashlet.formData = event.detail.view_data;
|
||||
this.RefreshDashlet(oDashlet);
|
||||
|
||||
// Re-enable dashboard buttons
|
||||
this.EnableFormButtons();
|
||||
}
|
||||
}
|
||||
|
||||
_ListenToDashletFormCancellation(event) {
|
||||
const oDashlet = this.querySelector('ibo-dashlet[data-edit-mode="edit"]');
|
||||
const sDashletId = oDashlet.GetDashletId();
|
||||
// Remove events
|
||||
document.addEventListener('itop:TurboStreamEvent', this._ListenToDashletFormSubmission);
|
||||
document.querySelector('.ibo-dashlet-panel--form-container button[name="dashboard_cancel"]').removeEventListener('click', this._ListenToDashletFormCancellation);
|
||||
|
||||
// Clean edit mode
|
||||
this.querySelector('ibo-dashlet[data-dashlet-id="'+sDashletId+'"]').setAttribute('data-edit-mode', 'view');
|
||||
this.ShowDashletTogglers();
|
||||
this.ClearDashletForm();
|
||||
|
||||
// Re-enable dashboard buttons
|
||||
this.EnableFormButtons();
|
||||
|
||||
// TODO 3.3 If this is an addition, remove the previewed dashlet
|
||||
// TODO 3.3 If this is an edition, revert the dashlet to its initial state
|
||||
}
|
||||
|
||||
CloneDashlet(sDashletId) {
|
||||
this.oGrid.CloneDashlet(sDashletId);
|
||||
}
|
||||
|
||||
RemoveDashlet(sDashletId) {
|
||||
this.oGrid.RemoveDashlet(sDashletId);
|
||||
}
|
||||
|
||||
RefreshFromBackend(bCustomDashboard = false) {
|
||||
const sLoadDashboardUrl = GetAbsoluteUrlAppRoot() + `/pages/UI.php?route=dashboard.load&id=${this.sId}&custom=${bCustomDashboard ? 'true' : 'false'}`;
|
||||
fetch(sLoadDashboardUrl)
|
||||
.then(async oResponse => {
|
||||
const oDashletData = await oResponse.json();
|
||||
this.Load(oDashletData);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Serialize(bIncludeHtml = false) {
|
||||
const sDashboardTitle = this.querySelector('.ibo-dashboard--form--inputs input[name="dashboard_title"]').value;
|
||||
const sDashboardRefreshRate = this.querySelector('.ibo-dashboard--form--inputs select[name="refresh_interval"]').value;
|
||||
|
||||
const aSerializedGrid = this.oGrid.Serialize(bIncludeHtml);
|
||||
return {
|
||||
schema_version: this.schemaVersion,
|
||||
id: this.sId,
|
||||
title: sDashboardTitle,
|
||||
refresh: sDashboardRefreshRate,
|
||||
pos_dashlets: aSerializedGrid,
|
||||
_token: ":)"
|
||||
};
|
||||
}
|
||||
|
||||
Save() {
|
||||
// This payload shape is expected by the server
|
||||
const aPayload = this.Serialize();
|
||||
|
||||
let sSaveUrl = GetAbsoluteUrlAppRoot() + '/pages/UI.php?route=dashboard.save&values='+encodeURIComponent(JSON.stringify(aPayload));
|
||||
fetch(sSaveUrl)
|
||||
.then(async data => {
|
||||
const res = await data.json();
|
||||
if(res.status === 'ok') {
|
||||
CombodoToast.OpenToast(res.message, 'success');
|
||||
this.aLastSavedState = this.Serialize(true);
|
||||
this.SetEditMode(false);
|
||||
} else {
|
||||
CombodoToast.OpenToast(res.message, 'error');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Load(aSaveState) {
|
||||
try {
|
||||
// Validate schema version
|
||||
if (aSaveState.schema_version !== this.schemaVersion) {
|
||||
CombodoToast.OpenToast('Somehow, we got an incompatible dashboard schema version.', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update dashboard data
|
||||
this.sId = aSaveState.id;
|
||||
this.sTitle = aSaveState.title || "";
|
||||
this.iRefreshRate = parseInt(aSaveState.refresh, 10) || 0;
|
||||
|
||||
// Update form inputs if they exist
|
||||
const oTitleInput = this.querySelector('.ibo-dashboard--form--inputs input[name="dashboard_title"]');
|
||||
if (oTitleInput) {
|
||||
oTitleInput.value = this.sTitle;
|
||||
}
|
||||
|
||||
const oRefreshSelect = this.querySelector('.ibo-dashboard--form--inputs select[name="refresh_interval"]');
|
||||
if (oRefreshSelect) {
|
||||
oRefreshSelect.value = aSaveState.refresh;
|
||||
}
|
||||
|
||||
// Clear existing grid
|
||||
this.ClearGrid();
|
||||
|
||||
// Load dashlets
|
||||
const aDashletSlots = aSaveState.pos_dashlets || {};
|
||||
|
||||
for (const [sDashletId, aDashletData] of Object.entries(aDashletSlots)) {
|
||||
const iPosX = aDashletData.position_x;
|
||||
const iPosY = aDashletData.position_y;
|
||||
const iWidth = aDashletData.width;
|
||||
const iHeight = aDashletData.height;
|
||||
const aDashlet = aDashletData.dashlet;
|
||||
|
||||
// We store the dashlet component in the HTML, not only the rendered dashlet
|
||||
const sDashetHtml = aDashlet.html;
|
||||
|
||||
// Add dashlet to grid with its position and size
|
||||
this.oGrid.AddDashlet(sDashetHtml, {
|
||||
x: iPosX,
|
||||
y: iPosY,
|
||||
w: iWidth,
|
||||
h: iHeight,
|
||||
autoPosition: false
|
||||
});
|
||||
}
|
||||
|
||||
// Update last saved state
|
||||
this.aLastSavedState = aSaveState;
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading dashboard state:', error);
|
||||
CombodoToast.OpenToast('Error loading dashboard state', 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ClearGrid() {
|
||||
this.oGrid.ClearGrid();
|
||||
}
|
||||
|
||||
DisplayError(sMessage, sSeverity = 'error') {
|
||||
// TODO 3.3: Make this real
|
||||
this.setAttribute("data-edit-mode", "error");
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ibo-dashboard', IboDashboard);
|
||||
68
js/layouts/dashboard/dashlet.js
Normal file
68
js/layouts/dashboard/dashlet.js
Normal file
@@ -0,0 +1,68 @@
|
||||
class IboDashlet extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
/** @type {string} */
|
||||
this.sDashletId = this.GetDashletId();
|
||||
/** @type {string} */
|
||||
this.sType = this.GetDashletType();
|
||||
/** @type {Object} */
|
||||
this.formData = this.GetFormData();
|
||||
/** @type {Object} unused yet */
|
||||
this.meta = {};
|
||||
|
||||
this.BindEvents();
|
||||
}
|
||||
BindEvents() {
|
||||
// Bind any dashlet-specific events here
|
||||
this.querySelector('.ibo-dashlet--actions [data-role="ibo-dashlet-edit"]')?.addEventListener('click', (e) => {
|
||||
this.closest('ibo-dashboard')?.EditDashlet(this.sDashletId);
|
||||
});
|
||||
|
||||
this.querySelector('.ibo-dashlet--actions [data-role="ibo-dashlet-clone"]')?.addEventListener('click', (e) => {
|
||||
this.closest('ibo-dashboard')?.CloneDashlet(this.sDashletId);
|
||||
});
|
||||
|
||||
this.querySelector('.ibo-dashlet--actions [data-role="ibo-dashlet-remove"]')?.addEventListener('click', (e) => {
|
||||
this.closest('ibo-dashboard')?.RemoveDashlet(this.sDashletId);
|
||||
});
|
||||
}
|
||||
|
||||
GetDashletId() {
|
||||
return this.getAttribute('data-dashlet-id');
|
||||
}
|
||||
|
||||
GetDashletType() {
|
||||
return this.getAttribute("data-dashlet-type") || "";
|
||||
}
|
||||
|
||||
GetFormData() {
|
||||
return this.getAttribute("data-form-view-data") || "";
|
||||
}
|
||||
|
||||
static MakeNew(sDashlet) {
|
||||
const oDashlet = document.createElement('ibo-dashlet');
|
||||
oDashlet.innerHTML = sDashlet;
|
||||
|
||||
return oDashlet;
|
||||
}
|
||||
|
||||
Serialize(bIncludeHtml = false) {
|
||||
// TODO 3.3 Should we use getters ?
|
||||
let aDashletData = {
|
||||
id: this.sDashletId,
|
||||
type: this.sType,
|
||||
properties: JSON.parse(this.formData),
|
||||
};
|
||||
|
||||
if(bIncludeHtml) {
|
||||
aDashletData.html = this.outerHTML;
|
||||
}
|
||||
|
||||
return aDashletData;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ibo-dashlet', IboDashlet);
|
||||
@@ -130,6 +130,27 @@ return array(
|
||||
'CheckableExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
|
||||
'Collator' => $vendorDir . '/symfony/polyfill-intl-icu/Resources/stubs/Collator.php',
|
||||
'Combodo\\iTop\\Application\\Branding' => $baseDir . '/sources/Application/Branding.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\Controller\\DashboardController' => $baseDir . '/sources/Application/Dashboard/Controller/DashboardController.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\DashboardException' => $baseDir . '/sources/Application/Dashboard/DashboardException.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashboardFormBlock' => $baseDir . '/sources/Application/Dashboard/FormBlock/DashboardFormBlock.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletFormBlock' => $baseDir . '/sources/Application/Dashboard/FormBlock/DashletFormBlock.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletPropertiesFormBlock' => $baseDir . '/sources/Application/Dashboard/FormBlock/DashletPropertiesFormBlock.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\Layout\\DashboardLayoutGrid' => $baseDir . '/sources/Application/Dashboard/Layout/DashboardLayoutGrid.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletBadge' => $baseDir . '/sources/Application/Dashlet/Core/DashletBadge.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupBy' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupBy.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByBars' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupByBars.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByPie' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupByPie.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByTable' => $baseDir . '/sources/Application/Dashlet/Core/DashletGroupByTable.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderDynamic' => $baseDir . '/sources/Application/Dashlet/Core/DashletHeaderDynamic.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderStatic' => $baseDir . '/sources/Application/Dashlet/Core/DashletHeaderStatic.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletObjectList' => $baseDir . '/sources/Application/Dashlet/Core/DashletObjectList.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletPlainText' => $baseDir . '/sources/Application/Dashlet/Core/DashletPlainText.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletProxy' => $baseDir . '/sources/Application/Dashlet/Core/DashletProxy.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletUnknown' => $baseDir . '/sources/Application/Dashlet/Core/DashletUnknown.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Dashlet' => $baseDir . '/sources/Application/Dashlet/Dashlet.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\DashletException' => $baseDir . '/sources/Application/Dashlet/DashletException.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\DashletFactory' => $baseDir . '/sources/Application/Dashlet/DashletFactory.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Service\\DashletService' => $baseDir . '/sources/Application/Dashlet/Service/DashletService.php',
|
||||
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => $baseDir . '/sources/Application/EventRegister/ApplicationEvents.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => $baseDir . '/sources/Application/Helper/CKEditorHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => $baseDir . '/sources/Application/Helper/ExportHelper.php',
|
||||
@@ -170,6 +191,7 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletFactory' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletHeaderStatic' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletHeaderStatic.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletPlainText' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletPlainText.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletWrapper' => $baseDir . '/sources/Application/UI/Base/Component/Dashlet/DashletWrapper.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTable' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/DataTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableConfig\\DataTableConfig' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/DataTableConfig/DataTableConfig.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableSettings' => $baseDir . '/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php',
|
||||
@@ -270,8 +292,13 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryForm' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryFormFactory' => $baseDir . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGrid' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGrid.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGridSlot' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGridSlot.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletEntry' => $baseDir . '/sources/Application/UI/Base/Layout/DashletPanel/DashletEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanel' => $baseDir . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanelFactory' => $baseDir . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanelFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php',
|
||||
@@ -483,6 +510,7 @@ return array(
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\CheckboxFormBlock' => $baseDir . '/sources/Forms/Block/Base/CheckboxFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFromInputsBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceFromInputsBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceImageFormBlock' => $baseDir . '/sources/Forms/Block/Base/ChoiceImageFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\CollectionBlock' => $baseDir . '/sources/Forms/Block/Base/CollectionBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => $baseDir . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
|
||||
@@ -490,6 +518,7 @@ return array(
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\HiddenFormBlock' => $baseDir . '/sources/Forms/Block/Base/HiddenFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => $baseDir . '/sources/Forms/Block/Base/IntegerFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\NumberFormBlock' => $baseDir . '/sources/Forms/Block/Base/NumberFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\PolymorphicFormBlock' => $baseDir . '/sources/Forms/Block/Base/PolymorphicFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => $baseDir . '/sources/Forms/Block/Base/TextFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => $baseDir . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
|
||||
@@ -557,15 +586,19 @@ return array(
|
||||
'Combodo\\iTop\\PropertyType\\PropertyTypeFactory' => $baseDir . '/sources/PropertyType/PropertyTypeFactory.php',
|
||||
'Combodo\\iTop\\PropertyType\\PropertyTypeService' => $baseDir . '/sources/PropertyType/PropertyTypeService.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\SerializerException' => $baseDir . '/sources/PropertyType/Serializer/SerializerException.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLEncoder' => $baseDir . '/sources/PropertyType/Serializer/XMLEncoder.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\AbstractXMLFormat' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/AbstractXMLFormat.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCSV' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCSV.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCollectionWithId' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCollectionWithId.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFactory' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFactory.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFlatArray' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFlatArray.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatValueAsId' => $baseDir . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatValueAsId.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLNormalizer' => $baseDir . '/sources/PropertyType/Serializer/XMLNormalizer.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLSerializer' => $baseDir . '/sources/PropertyType/Serializer/XMLSerializer.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\AbstractValueType' => $baseDir . '/sources/PropertyType/ValueType/AbstractValueType.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\AbstractBranchValueType' => $baseDir . '/sources/PropertyType/ValueType/Branch/AbstractBranchValueType.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypeCollection' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypeCollection.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePolymorphic' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypePolymorphic.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePropertyTree' => $baseDir . '/sources/PropertyType/ValueType/Branch/ValueTypePropertyTree.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\AbstractLeafValueType' => $baseDir . '/sources/PropertyType/ValueType/Leaf/AbstractLeafValueType.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeAggregateFunction' => $baseDir . '/sources/PropertyType/ValueType/Leaf/ValueTypeAggregateFunction.php',
|
||||
@@ -676,19 +709,6 @@ return array(
|
||||
'DashboardLayoutThreeCols' => $baseDir . '/application/dashboardlayout.class.inc.php',
|
||||
'DashboardLayoutTwoCols' => $baseDir . '/application/dashboardlayout.class.inc.php',
|
||||
'DashboardMenuNode' => $baseDir . '/application/menunode.class.inc.php',
|
||||
'Dashlet' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletBadge' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletEmptyCell' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupBy' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupByBars' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupByPie' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupByTable' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletHeaderDynamic' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletHeaderStatic' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletObjectList' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletPlainText' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletProxy' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'DashletUnknown' => $baseDir . '/application/dashlet.class.inc.php',
|
||||
'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php',
|
||||
'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
|
||||
'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
|
||||
|
||||
@@ -516,6 +516,27 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'CheckableExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
|
||||
'Collator' => __DIR__ . '/..' . '/symfony/polyfill-intl-icu/Resources/stubs/Collator.php',
|
||||
'Combodo\\iTop\\Application\\Branding' => __DIR__ . '/../..' . '/sources/Application/Branding.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\Controller\\DashboardController' => __DIR__ . '/../..' . '/sources/Application/Dashboard/Controller/DashboardController.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\DashboardException' => __DIR__ . '/../..' . '/sources/Application/Dashboard/DashboardException.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashboardFormBlock' => __DIR__ . '/../..' . '/sources/Application/Dashboard/FormBlock/DashboardFormBlock.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletFormBlock' => __DIR__ . '/../..' . '/sources/Application/Dashboard/FormBlock/DashletFormBlock.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\FormBlock\\DashletPropertiesFormBlock' => __DIR__ . '/../..' . '/sources/Application/Dashboard/FormBlock/DashletPropertiesFormBlock.php',
|
||||
'Combodo\\iTop\\Application\\Dashboard\\Layout\\DashboardLayoutGrid' => __DIR__ . '/../..' . '/sources/Application/Dashboard/Layout/DashboardLayoutGrid.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletBadge' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletBadge.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupBy' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupBy.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByBars' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupByBars.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByPie' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupByPie.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletGroupByTable' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletGroupByTable.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderDynamic' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletHeaderDynamic.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletHeaderStatic' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletHeaderStatic.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletObjectList' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletObjectList.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletPlainText' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletPlainText.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletProxy' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletProxy.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Core\\DashletUnknown' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Core/DashletUnknown.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Dashlet' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Dashlet.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\DashletException' => __DIR__ . '/../..' . '/sources/Application/Dashlet/DashletException.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\DashletFactory' => __DIR__ . '/../..' . '/sources/Application/Dashlet/DashletFactory.php',
|
||||
'Combodo\\iTop\\Application\\Dashlet\\Service\\DashletService' => __DIR__ . '/../..' . '/sources/Application/Dashlet/Service/DashletService.php',
|
||||
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => __DIR__ . '/../..' . '/sources/Application/EventRegister/ApplicationEvents.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/CKEditorHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ExportHelper.php',
|
||||
@@ -556,6 +577,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletHeaderStatic' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletHeaderStatic.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletPlainText' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletPlainText.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\Dashlet\\DashletWrapper' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Dashlet/DashletWrapper.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTable' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/DataTable.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableConfig\\DataTableConfig' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/DataTableConfig/DataTableConfig.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Component\\DataTable\\DataTableSettings' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/DataTable/DataTableSettings.php',
|
||||
@@ -656,8 +678,13 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryForm' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\ActivityPanel\\CaseLogEntryForm\\CaseLogEntryFormFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryFormFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGrid' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGrid.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardGridSlot' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardGridSlot.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletEntry' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/DashletPanel/DashletEntry.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanel' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanel.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\DashletPanel\\DashletPanelFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/DashletPanel/DashletPanelFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php',
|
||||
@@ -869,6 +896,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\CheckboxFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/CheckboxFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceFromInputsBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceFromInputsBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\ChoiceImageFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/ChoiceImageFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\CollectionBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/CollectionBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\DateFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\DateTimeFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/DateTimeFormBlock.php',
|
||||
@@ -876,6 +904,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\HiddenFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/HiddenFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\IntegerFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/IntegerFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\NumberFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/NumberFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\PolymorphicFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/PolymorphicFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\TextAreaFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextAreaFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\Base\\TextFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/Base/TextFormBlock.php',
|
||||
'Combodo\\iTop\\Forms\\Block\\DataModel\\AttributeChoiceFormBlock' => __DIR__ . '/../..' . '/sources/Forms/Block/DataModel/AttributeChoiceFormBlock.php',
|
||||
@@ -943,15 +972,19 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\PropertyType\\PropertyTypeFactory' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeFactory.php',
|
||||
'Combodo\\iTop\\PropertyType\\PropertyTypeService' => __DIR__ . '/../..' . '/sources/PropertyType/PropertyTypeService.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\SerializerException' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/SerializerException.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLEncoder' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLEncoder.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\AbstractXMLFormat' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/AbstractXMLFormat.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCSV' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCSV.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatCollectionWithId' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatCollectionWithId.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFactory' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFactory.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatFlatArray' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatFlatArray.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLFormat\\XMLFormatValueAsId' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLFormat/XMLFormatValueAsId.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLNormalizer' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLNormalizer.php',
|
||||
'Combodo\\iTop\\PropertyType\\Serializer\\XMLSerializer' => __DIR__ . '/../..' . '/sources/PropertyType/Serializer/XMLSerializer.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\AbstractValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/AbstractValueType.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\AbstractBranchValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/AbstractBranchValueType.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypeCollection' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypeCollection.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePolymorphic' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypePolymorphic.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Branch\\ValueTypePropertyTree' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Branch/ValueTypePropertyTree.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\AbstractLeafValueType' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/AbstractLeafValueType.php',
|
||||
'Combodo\\iTop\\PropertyType\\ValueType\\Leaf\\ValueTypeAggregateFunction' => __DIR__ . '/../..' . '/sources/PropertyType/ValueType/Leaf/ValueTypeAggregateFunction.php',
|
||||
@@ -1062,19 +1095,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'DashboardLayoutThreeCols' => __DIR__ . '/../..' . '/application/dashboardlayout.class.inc.php',
|
||||
'DashboardLayoutTwoCols' => __DIR__ . '/../..' . '/application/dashboardlayout.class.inc.php',
|
||||
'DashboardMenuNode' => __DIR__ . '/../..' . '/application/menunode.class.inc.php',
|
||||
'Dashlet' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletBadge' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletEmptyCell' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupBy' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupByBars' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupByPie' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletGroupByTable' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletHeaderDynamic' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletHeaderStatic' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletObjectList' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletPlainText' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletProxy' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'DashletUnknown' => __DIR__ . '/../..' . '/application/dashlet.class.inc.php',
|
||||
'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php',
|
||||
'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
|
||||
'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
|
||||
|
||||
16
node_modules/.package-lock.json
generated
vendored
16
node_modules/.package-lock.json
generated
vendored
@@ -186,6 +186,22 @@
|
||||
"delegate": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/gridstack": {
|
||||
"version": "12.4.2",
|
||||
"resolved": "https://registry.npmjs.org/gridstack/-/gridstack-12.4.2.tgz",
|
||||
"integrity": "sha512-aXbJrQpi3LwpYXYOr4UriPM5uc/dPcjK01SdOE5PDpx2vi8tnLhU7yBg/1i4T59UhNkG/RBfabdFUObuN+gMnw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://www.paypal.me/alaind831"
|
||||
},
|
||||
{
|
||||
"type": "venmo",
|
||||
"url": "https://www.venmo.com/adumesny"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jquery": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
|
||||
|
||||
21
node_modules/gridstack/LICENSE
generated
vendored
Normal file
21
node_modules/gridstack/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2025 Alain Dumesny. v0.4.0 and older (c) 2014-2018 Pavel Reznikov, Dylan Weiss
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
565
node_modules/gridstack/README.md
generated
vendored
Normal file
565
node_modules/gridstack/README.md
generated
vendored
Normal file
@@ -0,0 +1,565 @@
|
||||
# gridstack.js
|
||||
|
||||
[](https://www.npmjs.com/package/gridstack)
|
||||
[](https://coveralls.io/github/gridstack/gridstack.js?branch=develop)
|
||||
[](https://www.npmjs.com/package/gridstack)
|
||||
|
||||
Mobile-friendly modern Typescript library for dashboard layout and creation. Making a drag-and-drop, multi-column responsive dashboard has never been easier. Has multiple bindings and works great with [Angular](https://angular.io/) (included), [React](https://reactjs.org/), [Vue](https://vuejs.org/), [Knockout.js](http://knockoutjs.com), [Ember](https://www.emberjs.com/) and others (see [frameworks](#specific-frameworks) section).
|
||||
|
||||
Inspired by no-longer maintained gridster, built with love.
|
||||
|
||||
Check http://gridstackjs.com and [these demos](http://gridstackjs.com/demo/).
|
||||
|
||||
If you find this lib useful, please donate [PayPal](https://www.paypal.me/alaind831) (use **“send to a friend”** to avoid 3% fee) or [Venmo](https://www.venmo.com/adumesny) (adumesny) and help support it!
|
||||
|
||||
[](https://www.paypal.me/alaind831)
|
||||
[](https://www.venmo.com/adumesny)
|
||||
|
||||
Join us on Slack: [https://gridstackjs.slack.com](https://join.slack.com/t/gridstackjs/shared_invite/zt-3978nsff6-HDNE_N45DydP36NBSV9JFQ)
|
||||
|
||||
<!-- [](https://gridstackjs.slack.com) -->
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
|
||||
|
||||
- [Demo and API Documentation](#demo-and-api-documentation)
|
||||
- [Usage](#usage)
|
||||
- [Install](#install)
|
||||
- [Include](#include)
|
||||
- [Basic usage](#basic-usage)
|
||||
- [Requirements](#requirements)
|
||||
- [Specific frameworks](#specific-frameworks)
|
||||
- [Extend Library](#extend-library)
|
||||
- [Extend Engine](#extend-engine)
|
||||
- [Change grid columns](#change-grid-columns)
|
||||
- [Custom columns CSS (OLD, not needed with v12+)](#custom-columns-css-old-not-needed-with-v12)
|
||||
- [Override resizable/draggable options](#override-resizabledraggable-options)
|
||||
- [Touch devices support](#touch-devices-support)
|
||||
- [Migrating](#migrating)
|
||||
- [Migrating to v0.6](#migrating-to-v06)
|
||||
- [Migrating to v1](#migrating-to-v1)
|
||||
- [Migrating to v2](#migrating-to-v2)
|
||||
- [Migrating to v3](#migrating-to-v3)
|
||||
- [Migrating to v4](#migrating-to-v4)
|
||||
- [Migrating to v5](#migrating-to-v5)
|
||||
- [Migrating to v6](#migrating-to-v6)
|
||||
- [Migrating to v7](#migrating-to-v7)
|
||||
- [Migrating to v8](#migrating-to-v8)
|
||||
- [Migrating to v9](#migrating-to-v9)
|
||||
- [Migrating to v10](#migrating-to-v10)
|
||||
- [Migrating to v11](#migrating-to-v11)
|
||||
- [Migrating to v12](#migrating-to-v12)
|
||||
- [jQuery Application](#jquery-application)
|
||||
- [Changes](#changes)
|
||||
- [Usage Trend](#usage-trend)
|
||||
- [The Team](#the-team)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
|
||||
# Demo and API Documentation
|
||||
|
||||
Please visit http://gridstackjs.com and [these demos](http://gridstackjs.com/demo/), and complete [API documentation](https://gridstack.github.io/gridstack.js/doc/html/) ([markdown](https://github.com/gridstack/gridstack.js/tree/master/doc/API.md))
|
||||
|
||||
# Usage
|
||||
|
||||
## Install
|
||||
[](https://www.npmjs.com/package/gridstack)
|
||||
|
||||
```js
|
||||
yarn add gridstack
|
||||
// or
|
||||
npm install --save gridstack
|
||||
```
|
||||
|
||||
## Include
|
||||
|
||||
ES6 or Typescript
|
||||
|
||||
```js
|
||||
import 'gridstack/dist/gridstack.min.css';
|
||||
import { GridStack } from 'gridstack';
|
||||
```
|
||||
|
||||
Alternatively (single combined file, notice the -all.js) in html
|
||||
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<script src="node_modules/gridstack/dist/gridstack-all.js"></script>
|
||||
```
|
||||
|
||||
**Note**: IE support was dropped in v2, but restored in v4.4 by an external contributor (I have no interest in testing+supporting obsolete browser so this likely will break again in the future) and DROPPED again in v12 (css variable needed).
|
||||
You can use the es5 files and polyfill (larger) for older browser instead. For example:
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<script src="node_modules/gridstack/dist/es5/gridstack-poly.js"></script>
|
||||
<script src="node_modules/gridstack/dist/es5/gridstack-all.js"></script>
|
||||
```
|
||||
|
||||
|
||||
## Basic usage
|
||||
|
||||
creating items dynamically...
|
||||
|
||||
```js
|
||||
// ...in your HTML
|
||||
<div class="grid-stack"></div>
|
||||
|
||||
// ...in your script
|
||||
var grid = GridStack.init();
|
||||
grid.addWidget({w: 2, content: 'item 1'});
|
||||
```
|
||||
|
||||
... or creating from list
|
||||
|
||||
```js
|
||||
// using serialize data instead of .addWidget()
|
||||
const serializedData = [
|
||||
{x: 0, y: 0, w: 2, h: 2},
|
||||
{x: 2, y: 3, w: 3, content: 'item 2'},
|
||||
{x: 1, y: 3}
|
||||
];
|
||||
|
||||
grid.load(serializedData);
|
||||
```
|
||||
|
||||
... or DOM created items
|
||||
|
||||
```js
|
||||
// ...in your HTML
|
||||
<div class="grid-stack">
|
||||
<div class="grid-stack-item">
|
||||
<div class="grid-stack-item-content">Item 1</div>
|
||||
</div>
|
||||
<div class="grid-stack-item" gs-w="2">
|
||||
<div class="grid-stack-item-content">Item 2 wider</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// ...in your script
|
||||
GridStack.init();
|
||||
```
|
||||
|
||||
...or see list of all [API and options](https://github.com/gridstack/gridstack.js/tree/master/doc) available.
|
||||
|
||||
see [stackblitz sample](https://stackblitz.com/edit/gridstack-demo) as running example too.
|
||||
|
||||
## Requirements
|
||||
|
||||
GridStack no longer requires external dependencies as of v1 (lodash was removed in v0.5 and jquery API in v1). v3 is a complete HTML5 re-write removing need for jquery. v6 is native mouse and touch event for mobile support, and no longer have jquery-ui version. All you need to include now is `gridstack-all.js` and `gridstack.min.css` (layouts are done using CSS column based %).
|
||||
|
||||
## Specific frameworks
|
||||
|
||||
search for ['gridstack' under NPM](https://www.npmjs.com/search?q=gridstack&ranking=popularity) for latest, more to come...
|
||||
|
||||
- **Angular**: we ship out of the box an Angular wrapper - see <a href="https://github.com/gridstack/gridstack.js/tree/master/angular" target="_blank">Angular Component</a>.
|
||||
- **Angular9**: [lb-gridstack](https://github.com/pfms84/lb-gridstack) Note: very old v0.3 gridstack instance so recommend for **concept ONLY if you wish to use directive instead**. Code has **not been vented** at as I use components.
|
||||
- **AngularJS**: [gridstack-angular](https://github.com/kdietrich/gridstack-angular)
|
||||
- **Ember**: [ember-gridstack](https://github.com/yahoo/ember-gridstack)
|
||||
- **knockout**: see [demo](https://gridstackjs.com/demo/knockout.html) using component, but check [custom bindings ticket](https://github.com/gridstack/gridstack.js/issues/465) which is likely better approach.
|
||||
- **Rails**: [gridstack-js-rails](https://github.com/randoum/gridstack-js-rails)
|
||||
- **React**: work in progress to have wrapper code: see <a href="https://github.com/gridstack/gridstack.js/tree/master/react" target="_blank">React Component</a>. But also see [demo](https://gridstackjs.com/demo/react.html) with [src](https://github.com/gridstack/gridstack.js/tree/master/demo/react.html), or [react-gridstack-example](https://github.com/Inder2108/react-gridstack-example/tree/master/src/App.js), or read on what [hooks to use](https://github.com/gridstack/gridstack.js/issues/735#issuecomment-329888796)
|
||||
- **Vue**: see [demo](https://gridstackjs.com/demo/vue3js.html) with [v3 src](https://github.com/gridstack/gridstack.js/tree/master/demo/vue3js.html) or [v2 src](https://github.com/gridstack/gridstack.js/tree/master/demo/vue2js.html)
|
||||
- **Aurelia**: [aurelia-gridstack](https://github.com/aurelia-ui-toolkits/aurelia-gridstack), see [demo](https://aurelia-ui-toolkits.github.io/aurelia-gridstack/)
|
||||
|
||||
## Extend Library
|
||||
|
||||
You can easily extend or patch gridstack with code like this:
|
||||
|
||||
```js
|
||||
// extend gridstack with our own custom method
|
||||
GridStack.prototype.printCount = function() {
|
||||
console.log('grid has ' + this.engine.nodes.length + ' items');
|
||||
};
|
||||
|
||||
let grid = GridStack.init();
|
||||
|
||||
// you can now call
|
||||
grid.printCount();
|
||||
```
|
||||
|
||||
## Extend Engine
|
||||
|
||||
You can now (5.1+) easily create your own layout engine to further customize your usage. Here is a typescript example
|
||||
|
||||
```ts
|
||||
import { GridStack, GridStackEngine, GridStackNode, GridStackMoveOpts } from 'gridstack';
|
||||
|
||||
class CustomEngine extends GridStackEngine {
|
||||
|
||||
/** refined this to move the node to the given new location */
|
||||
public override moveNode(node: GridStackNode, o: GridStackMoveOpts): boolean {
|
||||
// keep the same original X and Width and let base do it all...
|
||||
o.x = node.x;
|
||||
o.w = node.w;
|
||||
return super.moveNode(node, o);
|
||||
}
|
||||
}
|
||||
|
||||
GridStack.registerEngine(CustomEngine); // globally set our custom class
|
||||
```
|
||||
|
||||
## Change grid columns
|
||||
|
||||
GridStack makes it very easy if you need [1-12] columns out of the box (default is 12), but you always need **2 things** if you need to customize this:
|
||||
|
||||
1) Change the `column` grid option when creating a grid to your number N
|
||||
```js
|
||||
GridStack.init( {column: N} );
|
||||
```
|
||||
|
||||
NOTE: step 2 is OLD and not needed with v12+ which uses CSS variables instead of classes
|
||||
|
||||
2) also include `gridstack-extra.css` if **N < 12** (else custom CSS - see next). Without these, things will not render/work correctly.
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<link href="node_modules/gridstack/dist/gridstack-extra.min.css" rel="stylesheet"/>
|
||||
|
||||
<div class="grid-stack">...</div>
|
||||
```
|
||||
|
||||
Note: class `.grid-stack-N` will automatically be added and we include `gridstack-extra.min.css` which defines CSS for grids with custom [2-11] columns. Anything more and you'll need to generate the SASS/CSS yourself (see next).
|
||||
|
||||
See example: [2 grids demo](http://gridstack.github.io/gridstack.js/demo/two.html) with 6 columns
|
||||
|
||||
## Custom columns CSS (OLD, not needed with v12+)
|
||||
|
||||
NOTE: step is OLD and not needed with v12+ which uses CSS variables instead of classes
|
||||
|
||||
If you need > 12 columns or want to generate the CSS manually you will need to generate CSS rules for `.grid-stack-item[gs-w="X"]` and `.grid-stack-item[gs-x="X"]`.
|
||||
|
||||
For instance for 4-column grid you need CSS to be:
|
||||
|
||||
```css
|
||||
.gs-4 > .grid-stack-item[gs-x="1"] { left: 25% }
|
||||
.gs-4 > .grid-stack-item[gs-x="2"] { left: 50% }
|
||||
.gs-4 > .grid-stack-item[gs-x="3"] { left: 75% }
|
||||
|
||||
.gs-4 > .grid-stack-item { width: 25% }
|
||||
.gs-4 > .grid-stack-item[gs-w="2"] { width: 50% }
|
||||
.gs-4 > .grid-stack-item[gs-w="3"] { width: 75% }
|
||||
.gs-4 > .grid-stack-item[gs-w="4"] { width: 100% }
|
||||
```
|
||||
|
||||
Better yet, here is a SCSS code snippet, you can use sites like [sassmeister.com](https://www.sassmeister.com/) to generate the CSS for you instead:
|
||||
|
||||
```scss
|
||||
$columns: 20;
|
||||
@function fixed($float) {
|
||||
@return round($float * 1000) / 1000; // total 2+3 digits being %
|
||||
}
|
||||
.gs-#{$columns} > .grid-stack-item {
|
||||
|
||||
width: fixed(100% / $columns);
|
||||
|
||||
@for $i from 1 through $columns - 1 {
|
||||
&[gs-x='#{$i}'] { left: fixed((100% / $columns) * $i); }
|
||||
&[gs-w='#{$i+1}'] { width: fixed((100% / $columns) * ($i+1)); }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
you can also use the SCSS [src/gridstack-extra.scss](https://github.com/gridstack/gridstack.js/tree/master/src/gridstack-extra.scss) included in NPM package and modify to add more columns.
|
||||
|
||||
Sample gulp command for 30 columns:
|
||||
```js
|
||||
gulp.src('node_modules/gridstack/dist/src/gridstack-extra.scss')
|
||||
.pipe(replace('$start: 2 !default;','$start: 30;'))
|
||||
.pipe(replace('$end: 11 !default;','$end: 30;'))
|
||||
.pipe(sass({outputStyle: 'compressed'}))
|
||||
.pipe(rename({extname: '.min.css'}))
|
||||
.pipe(gulp.dest('dist/css'))
|
||||
```
|
||||
|
||||
## Override resizable/draggable options
|
||||
|
||||
You can override default `resizable`/`draggable` options. For instance to enable other then bottom right resizing handle
|
||||
you can init gridstack like:
|
||||
|
||||
```js
|
||||
GridStack.init({
|
||||
resizable: {
|
||||
handles: 'e,se,s,sw,w'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Touch devices support
|
||||
|
||||
gridstack v6+ now support mobile out of the box, with the addition of native touch event (along with mouse event) for drag&drop and resize.
|
||||
Older versions (3.2+) required the jq version with added touch punch, but doesn't work well with nested grids.
|
||||
|
||||
This option is now the default:
|
||||
|
||||
```js
|
||||
let options = {
|
||||
alwaysShowResizeHandle: 'mobile' // true if we're on mobile devices
|
||||
};
|
||||
GridStack.init(options);
|
||||
```
|
||||
|
||||
See [example](http://gridstack.github.io/gridstack.js/demo/mobile.html).
|
||||
|
||||
# Migrating
|
||||
## Migrating to v0.6
|
||||
|
||||
starting in 0.6.x `change` event are no longer sent (for pretty much most nodes!) when an item is just added/deleted unless it also changes other nodes (was incorrect and causing inefficiencies). You may need to track `added|removed` [events](https://github.com/gridstack/gridstack.js/tree/master/doc#events) if you didn't and relied on the old broken behavior.
|
||||
|
||||
## Migrating to v1
|
||||
|
||||
v1.0.0 removed Jquery from the API and external dependencies, which will require some code changes. Here is a list of the changes:
|
||||
|
||||
0. see previous step if not on v0.6 already
|
||||
|
||||
1. your code only needs to `import GridStack from 'gridstack'` or include `gridstack.all.js` and `gristack.css` (don't include other JS) and is recommended you do that as internal dependencies will change over time. If you are jquery based, see [jquery app](#jquery-application) section.
|
||||
|
||||
2. code change:
|
||||
|
||||
**OLD** initializing code + adding a widget + adding an event:
|
||||
```js
|
||||
// initialization returned Jquery element, requiring second call to get GridStack var
|
||||
var grid = $('.grid-stack').gridstack(opts?).data('gridstack');
|
||||
|
||||
// returned Jquery element
|
||||
grid.addWidget($('<div><div class="grid-stack-item-content"> test </div></div>'), undefined, undefined, 2, undefined, true);
|
||||
|
||||
// jquery event handler
|
||||
$('.grid-stack').on('added', function(e, items) {/* items contains info */});
|
||||
|
||||
// grid access after init
|
||||
var grid = $('.grid-stack').data('gridstack');
|
||||
```
|
||||
**NEW**
|
||||
```js
|
||||
// element identifier defaults to '.grid-stack', returns the grid
|
||||
// Note: for Typescript use window.GridStack.init() until next native 2.x TS version
|
||||
var grid = GridStack.init(opts?, element?);
|
||||
|
||||
// returns DOM element
|
||||
grid.addWidget('<div><div class="grid-stack-item-content"> test </div></div>', {width: 2});
|
||||
// Note: in 3.x it's ever simpler
|
||||
// grid.addWidget({w:2, content: 'test'})
|
||||
|
||||
// event handler
|
||||
grid.on('added', function(e, items) {/* items contains info */});
|
||||
|
||||
// grid access after init
|
||||
var grid = el.gridstack; // where el = document.querySelector('.grid-stack') or other ways...
|
||||
```
|
||||
Other rename changes
|
||||
|
||||
```js
|
||||
`GridStackUI` --> `GridStack`
|
||||
`GridStackUI.GridStackEngine` --> `GridStack.Engine`
|
||||
`grid.container` (jquery grid wrapper) --> `grid.el` // (grid DOM element)
|
||||
`grid.grid` (GridStackEngine) --> `grid.engine`
|
||||
`grid.setColumn(N)` --> `grid.column(N)` and `grid.column()` // to get value, old API still supported though
|
||||
```
|
||||
|
||||
Recommend looking at the [many samples](./demo) for more code examples.
|
||||
|
||||
## Migrating to v2
|
||||
|
||||
make sure to read v1 migration first!
|
||||
|
||||
v2 is a Typescript rewrite of 1.x, removing all jquery events, using classes and overall code cleanup to support ES6 modules. Your code might need to change from 1.x
|
||||
|
||||
1. In general methods that used no args (getter) vs setter can't be used in TS when the arguments differ (set/get are also not function calls so API would have changed). Instead we decided to have <b>all set methods return</b> `GridStack` to they can be chain-able (ex: `grid.float(true).cellHeight(10).column(6)`). Also legacy methods that used to take many parameters will now take a single object (typically `GridStackOptions` or `GridStackWidget`).
|
||||
|
||||
```js
|
||||
`addWidget(el, x, y, width, height)` --> `addWidget(el, {with: 2})`
|
||||
// Note: in 2.1.x you can now just do addWidget({with: 2, content: "text"})
|
||||
`float()` --> `getFloat()` // to get value
|
||||
`cellHeight()` --> `getCellHeight()` // to get value
|
||||
`verticalMargin` --> `margin` // grid options and API that applies to all 4 sides.
|
||||
`verticalMargin()` --> `getMargin()` // to get value
|
||||
```
|
||||
|
||||
2. event signatures are generic and not jquery-ui dependent anymore. `gsresizestop` has been removed as `resizestop|dragstop` are now called **after** the DOM attributes have been updated.
|
||||
|
||||
3. `oneColumnMode` would trigger when `window.width` < 768px by default. We now check for grid width instead (more correct and supports nesting). You might need to adjust grid `oneColumnSize` or `disableOneColumnMode`.
|
||||
|
||||
**Note:** 2.x no longer support legacy IE11 and older due to using more compact ES6 output and typecsript native code. You will need to stay at 1.x
|
||||
|
||||
## Migrating to v3
|
||||
|
||||
make sure to read v2 migration first!
|
||||
|
||||
v3 has a new HTML5 drag&drop plugging (63k total, all native code), while still allowing you to use the legacy jquery-ui version instead (188k), or a new static grid version (34k, no user drag&drop but full API support). You will need to decide which version to use as `gridstack.all.js` no longer exist (same is now `gridstack-jq.js`) - see [include info](#include).
|
||||
|
||||
**NOTE**: HTML5 version is almost on parity with the old jquery-ui based drag&drop. the `containment` (prevent a child from being dragged outside it's parent) and `revert` (not clear what it is for yet) are not yet implemented in initial release of v3.0.0.<br>
|
||||
Also mobile devices don't support h5 `drag` events (will need to handle `touch`) whereas v3.2 jq version now now supports out of the box (see [v3.2 release](https://github.com/gridstack/gridstack.js/releases/tag/v3.2.0))
|
||||
|
||||
Breaking changes:
|
||||
|
||||
1. include (as mentioned) need to change
|
||||
|
||||
2. `GridStack.update(el, opt)` now takes single `GridStackWidget` options instead of only supporting (x,y,w,h) BUT legacy call in JS will continue working the same for now. That method is a complete re-write and does the right constrain and updates now for all the available params.
|
||||
|
||||
3. `locked()`, `move()`, `resize()`, `minWidth()`, `minHeight()`, `maxWidth()`, `maxHeight()` methods are hidden from Typescript (JS can still call for now) as they are just 1 liner wrapper around `update(el, opt)` anyway and will go away soon. (ex: `move(el, x, y)` => `update(el, {x, y})`)
|
||||
|
||||
4. item attribute like `data-gs-min-width` is now `gs-min-w`. We removed 'data-' from all attributes, and shorten 'width|height' to just 'w|h' to require less typing and more efficient (2k saved in .js alone!).
|
||||
|
||||
5. `GridStackWidget` used in most API `width|height|minWidth|minHeight|maxWidth|maxHeight` are now shorter `w|h|minW|minH|maxW|maxH` as well
|
||||
|
||||
## Migrating to v4
|
||||
|
||||
make sure to read v3 migration first!
|
||||
|
||||
v4 is a complete re-write of the collision and drag in/out heuristics to fix some very long standing request & bugs. It also greatly improved usability. Read the release notes for more detail.
|
||||
|
||||
**Unlikely** Breaking Changes (internal usage):
|
||||
|
||||
1. `removeTimeout` was removed (feedback over trash will be immediate - actual removal still on mouse up)
|
||||
|
||||
2. the following `GridStackEngine` methods changed (used internally, doesn't affect `GridStack` public API)
|
||||
|
||||
```js
|
||||
// moved to 3 methods with new option params to support new code and pixel coverage check
|
||||
`collision()` -> `collide(), collideAll(), collideCoverage()`
|
||||
`moveNodeCheck(node, x, y, w, h)` -> `moveNodeCheck(node, opt: GridStackMoveOpts)`
|
||||
`isNodeChangedPosition(node, x, y, w, h)` -> `changedPosConstrain(node, opt: GridStackMoveOpts)`
|
||||
`moveNode(node, x, y, w, h, noPack)` -> `moveNode(node, opt: GridStackMoveOpts)`
|
||||
```
|
||||
|
||||
3. removed old obsolete (v0.6-v1 methods/attrs) `getGridHeight()`, `verticalMargin`, `data-gs-current-height`,
|
||||
`locked()`, `maxWidth()`, `minWidth()`, `maxHeight()`, `minHeight()`, `move()`, `resize()`
|
||||
|
||||
|
||||
## Migrating to v5
|
||||
|
||||
make sure to read v4 migration first!
|
||||
|
||||
v5 does not have any breaking changes from v4, but a focus on nested grids in h5 mode:
|
||||
You can now drag in/out of parent into nested child, with new API parameters values. See the release notes.
|
||||
|
||||
## Migrating to v6
|
||||
|
||||
the API did not really change from v5, but a complete re-write of Drag&Drop to use native `mouseevent` (instead of HTML draggable=true which is buggy on Mac Safari, and doesn't work on mobile devices) and `touchevent` (mobile), and we no longer have jquery ui option (wasn't working well for nested grids, didn't want to maintain legacy lib).
|
||||
|
||||
The main difference is you only need to include gridstack.js and get D&D (desktop and mobile) out of the box for the same size as h5 version.
|
||||
|
||||
## Migrating to v7
|
||||
|
||||
New addition, no API breakage per say. See release notes about creating sub-grids on the fly.
|
||||
|
||||
## Migrating to v8
|
||||
|
||||
Possible breaking change if you use nested grid JSON format, or original Angular wrapper, or relied on specific CSS paths. Also target is now ES2020 (see release notes).
|
||||
* `GridStackOptions.subGrid` -> `GridStackOptions.subGridOpts` rename. We now have `GridStackWidget.subGridOpts` vs `GridStackNode.subGrid` (was both types which is error prone)
|
||||
* `GridStackOptions.addRemoveCB` -> `GridStack.addRemoveCB` is now global instead of grid option
|
||||
* removed `GridStackOptions.dragInOptions` since `GridStack.setupDragIn()` has it replaced since 4.0
|
||||
* remove `GridStackOptions.minWidth` obsolete since 5.1, use `oneColumnSize` instead
|
||||
* CSS rules removed `.grid-stack` prefix for anything already gs based, 12 column (default) now uses `.gs-12`, extra.css is less than 1/4th it original size!, `gs-min|max_w|h` attribute no longer written (but read)
|
||||
|
||||
## Migrating to v9
|
||||
|
||||
New addition - see release notes about `sizeToContent` feature.
|
||||
Possible break:
|
||||
* `GridStack.onParentResize()` is now called `onResize()` as grid now directly track size change, no longer involving parent per say to tell us anything. Note sure why it was public.
|
||||
|
||||
## Migrating to v10
|
||||
|
||||
we now support much richer responsive behavior with `GridStackOptions.columnOpts` including any breakpoint width:column pairs, or automatic column sizing.
|
||||
|
||||
breaking change:
|
||||
* `disableOneColumnMode`, `oneColumnSize` have been removed (thought we temporary convert if you have them). use `columnOpts: { breakpoints: [{w:768, c:1}] }` for the same behavior.
|
||||
* 1 column mode switch is no longer by default (`columnOpts` is not defined) as too many new users had issues. Instead set it explicitly (see above).
|
||||
* `oneColumnModeDomSort` has been removed. Planning to support per column layouts at some future times. TBD
|
||||
|
||||
## Migrating to v11
|
||||
|
||||
* All instances of `el.innerHTML = 'some content'` have been removed for security reason as it opens up some potential for accidental XSS.
|
||||
|
||||
* Side panel drag&drop complete rewrite.
|
||||
|
||||
* new lazy loading option
|
||||
|
||||
**Breaking change:**
|
||||
|
||||
* V11 add new `GridStack.renderCB` that is called for you to create the widget content (entire GridStackWidget is passed so you can use id or some other field as logic) while GS creates the 2 needed parent divs + classes, unlike `GridStack.addRemoveCB` which doesn't create anything for you. Both can be handy for Angular/React/Vue frameworks.
|
||||
* `addWidget(w: GridStackWidget)` is now the only supported format, no more string content passing. You will need to create content yourself as shown below, OR use `GridStack.createWidgetDivs()` to create parent divs, do the innerHtml, then call `makeWidget(el)` instead.
|
||||
* if your code relies on `GridStackWidget.content` with real HTML (like a few demos) it is up to you to do this:
|
||||
```ts
|
||||
// NOTE: REAL apps would sanitize-html or DOMPurify before blinding setting innerHTML. see #2736
|
||||
GridStack.renderCB = function(el: HTMLElement, w: GridStackNode) {
|
||||
el.innerHTML = w.content;
|
||||
};
|
||||
|
||||
// now you can create widgets like this again
|
||||
let gridWidget = grid.addWidget({x, y, w, h, content: '<div>My html content</div>'});
|
||||
```
|
||||
|
||||
**Potential breaking change:**
|
||||
|
||||
* BIG overall to how sidepanel helper drag&drop is done:
|
||||
1. `clone()` helper is now passed full HTML element dragged, not an event on `grid-stack-item-content` so you can clone or set attr at the top.
|
||||
2. use any class/structure you want for side panel items (see two.html)
|
||||
3. `GridStack.setupDragIn()` now support associating a `GridStackWidget` for each sidepanel that will be used to define what to create on drop!
|
||||
4. if no `GridStackWidget` is defined, the helper will now be inserted as is, and NOT original sidepanel item.
|
||||
5. support DOM gs- attr as well as gridstacknode JSON (see two.html) alternatives.
|
||||
|
||||
## Migrating to v12
|
||||
|
||||
* column and cell height code has been re-writen to use browser CSS variables, and we no longer need a tons of custom CSS classes!
|
||||
this fixes a long standing issue where people forget to include the right CSS for non 12 columns layouts, and a big speedup in many cases (many columns, or small cellHeight values).
|
||||
|
||||
**Potential breaking change:**
|
||||
* `gridstack-extra.min.css` no longer exist, nor is custom column CSS classes needed. API/options hasn't changed.
|
||||
* (v12.1) `ES5` folder content has been removed - was for IE support, which has been dropped.
|
||||
* (v12.1) nested grid events are now sent to the main grid. You might have to adjust your workaround of this missing feature. nested.html demo has been adjusted.
|
||||
|
||||
# jQuery Application
|
||||
|
||||
This is **old and no longer apply to v6+**. You'll need to use v5.1.1 and before
|
||||
|
||||
```js
|
||||
import 'gridstack/dist/gridstack.min.css';
|
||||
import { GridStack } from 'gridstack';
|
||||
import 'gridstack/dist/jq/gridstack-dd-jqueryui';
|
||||
```
|
||||
**Note**: `jquery` & `jquery-ui` are imported by name, so you will have to specify their location in your webpack (or equivalent) config file,
|
||||
which means you can possibly bring your own version
|
||||
```js
|
||||
alias: {
|
||||
'jquery': 'gridstack/dist/jq/jquery.js',
|
||||
'jquery-ui': 'gridstack/dist/jq/jquery-ui.js',
|
||||
'jquery.ui': 'gridstack/dist/jq/jquery-ui.js',
|
||||
'jquery.ui.touch-punch': 'gridstack/dist/jq/jquery.ui.touch-punch.js',
|
||||
},
|
||||
```
|
||||
Alternatively (single combined file) in html
|
||||
|
||||
```html
|
||||
<link href="node_modules/gridstack/dist/gridstack.min.css" rel="stylesheet"/>
|
||||
<!-- HTML5 drag&drop (70k) -->
|
||||
<script src="node_modules/gridstack/dist/gridstack-h5.js"></script>
|
||||
<!-- OR jquery-ui drag&drop (195k) -->
|
||||
<script src="node_modules/gridstack/dist/gridstack-jq.js"></script>
|
||||
<!-- OR static grid (40k) -->
|
||||
<script src="node_modules/gridstack/dist/gridstack-static.js"></script>
|
||||
```
|
||||
|
||||
We have a native HTML5 drag'n'drop through the plugin system (default), but the jquery-ui version can be used instead. It will bundle `jquery` (3.5.1) + `jquery-ui` (1.13.1 minimal drag|drop|resize) + `jquery-ui-touch-punch` (1.0.8 for mobile support) in `gridstack-jq.js`.
|
||||
|
||||
**NOTE: in v4, v3**: we ES6 module import jquery & jquery-ui by name, so you need to specify location of those .js files, which means you might be able to bring your own version as well. See the include instructions.
|
||||
|
||||
**NOTE: in v1.x** IFF you want to use gridstack-jq instead and your app needs to bring your own JQ version, you should **instead** include `gridstack-poly.min.js` (optional IE support) + `gridstack.min.js` + `gridstack.jQueryUI.min.js` after you import your JQ libs. But note that there are issue with jQuery and ES6 import (see [1306](https://github.com/gridstack/gridstack.js/issues/1306)).
|
||||
|
||||
As for events, you can still use `$(".grid-stack").on(...)` for the version that uses jquery-ui for things we don't support.
|
||||
|
||||
# Changes
|
||||
|
||||
View our change log [here](https://github.com/gridstack/gridstack.js/tree/master/doc/CHANGES.md).
|
||||
|
||||
# Usage Trend
|
||||
|
||||
[Usage Trend of gridstack](https://npm-compare.com/gridstack#timeRange=THREE_YEARS)
|
||||
|
||||
<a href="https://npm-compare.com/gridstack#timeRange=THREE_YEARS" target="_blank">
|
||||
<img src="https://npm-compare.com/img/npm-trend/THREE_YEARS/gridstack.png" width="70%" alt="NPM Usage Trend of gridstack" />
|
||||
</a>
|
||||
|
||||
# The Team
|
||||
|
||||
gridstack.js is currently maintained by [Alain Dumesny](https://github.com/adumesny), before that [Dylan Weiss](https://github.com/radiolips), originally created by [Pavel Reznikov](https://github.com/troolee). We appreciate [all contributors](https://github.com/gridstack/gridstack.js/graphs/contributors) for help.
|
||||
69
node_modules/gridstack/dist/dd-base-impl.d.ts
generated
vendored
Normal file
69
node_modules/gridstack/dist/dd-base-impl.d.ts
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* dd-base-impl.ts 12.4.2
|
||||
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Type for event callback functions used in drag & drop operations.
|
||||
* Can return boolean to indicate if the event should continue propagation.
|
||||
*/
|
||||
export type EventCallback = (event: Event) => boolean | void;
|
||||
/**
|
||||
* Abstract base class for all drag & drop implementations.
|
||||
* Provides common functionality for event handling, enable/disable state,
|
||||
* and lifecycle management used by draggable, droppable, and resizable implementations.
|
||||
*/
|
||||
export declare abstract class DDBaseImplement {
|
||||
/**
|
||||
* Returns the current disabled state.
|
||||
* Note: Use enable()/disable() methods to change state as other operations need to happen.
|
||||
*/
|
||||
get disabled(): boolean;
|
||||
/**
|
||||
* Register an event callback for the specified event.
|
||||
*
|
||||
* @param event - Event name to listen for
|
||||
* @param callback - Function to call when event occurs
|
||||
*/
|
||||
on(event: string, callback: EventCallback): void;
|
||||
/**
|
||||
* Unregister an event callback for the specified event.
|
||||
*
|
||||
* @param event - Event name to stop listening for
|
||||
*/
|
||||
off(event: string): void;
|
||||
/**
|
||||
* Enable this drag & drop implementation.
|
||||
* Subclasses should override to perform additional setup.
|
||||
*/
|
||||
enable(): void;
|
||||
/**
|
||||
* Disable this drag & drop implementation.
|
||||
* Subclasses should override to perform additional cleanup.
|
||||
*/
|
||||
disable(): void;
|
||||
/**
|
||||
* Destroy this drag & drop implementation and clean up resources.
|
||||
* Removes all event handlers and clears internal state.
|
||||
*/
|
||||
destroy(): void;
|
||||
/**
|
||||
* Trigger a registered event callback if one exists and the implementation is enabled.
|
||||
*
|
||||
* @param eventName - Name of the event to trigger
|
||||
* @param event - DOM event object to pass to the callback
|
||||
* @returns Result from the callback function, if any
|
||||
*/
|
||||
triggerEvent(eventName: string, event: Event): boolean | void;
|
||||
}
|
||||
/**
|
||||
* Interface for HTML elements extended with drag & drop options.
|
||||
* Used to associate DD configuration with DOM elements.
|
||||
*/
|
||||
export interface HTMLElementExtendOpt<T> {
|
||||
/** The HTML element being extended */
|
||||
el: HTMLElement;
|
||||
/** The drag & drop options/configuration */
|
||||
option: T;
|
||||
/** Method to update the options and return the DD implementation */
|
||||
updateOption(T: any): DDBaseImplement;
|
||||
}
|
||||
70
node_modules/gridstack/dist/dd-base-impl.js
generated
vendored
Normal file
70
node_modules/gridstack/dist/dd-base-impl.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* dd-base-impl.ts 12.4.2
|
||||
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
/**
|
||||
* Abstract base class for all drag & drop implementations.
|
||||
* Provides common functionality for event handling, enable/disable state,
|
||||
* and lifecycle management used by draggable, droppable, and resizable implementations.
|
||||
*/
|
||||
export class DDBaseImplement {
|
||||
constructor() {
|
||||
/** @internal */
|
||||
this._eventRegister = {};
|
||||
}
|
||||
/**
|
||||
* Returns the current disabled state.
|
||||
* Note: Use enable()/disable() methods to change state as other operations need to happen.
|
||||
*/
|
||||
get disabled() { return this._disabled; }
|
||||
/**
|
||||
* Register an event callback for the specified event.
|
||||
*
|
||||
* @param event - Event name to listen for
|
||||
* @param callback - Function to call when event occurs
|
||||
*/
|
||||
on(event, callback) {
|
||||
this._eventRegister[event] = callback;
|
||||
}
|
||||
/**
|
||||
* Unregister an event callback for the specified event.
|
||||
*
|
||||
* @param event - Event name to stop listening for
|
||||
*/
|
||||
off(event) {
|
||||
delete this._eventRegister[event];
|
||||
}
|
||||
/**
|
||||
* Enable this drag & drop implementation.
|
||||
* Subclasses should override to perform additional setup.
|
||||
*/
|
||||
enable() {
|
||||
this._disabled = false;
|
||||
}
|
||||
/**
|
||||
* Disable this drag & drop implementation.
|
||||
* Subclasses should override to perform additional cleanup.
|
||||
*/
|
||||
disable() {
|
||||
this._disabled = true;
|
||||
}
|
||||
/**
|
||||
* Destroy this drag & drop implementation and clean up resources.
|
||||
* Removes all event handlers and clears internal state.
|
||||
*/
|
||||
destroy() {
|
||||
delete this._eventRegister;
|
||||
}
|
||||
/**
|
||||
* Trigger a registered event callback if one exists and the implementation is enabled.
|
||||
*
|
||||
* @param eventName - Name of the event to trigger
|
||||
* @param event - DOM event object to pass to the callback
|
||||
* @returns Result from the callback function, if any
|
||||
*/
|
||||
triggerEvent(eventName, event) {
|
||||
if (!this.disabled && this._eventRegister && this._eventRegister[eventName])
|
||||
return this._eventRegister[eventName](event);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=dd-base-impl.js.map
|
||||
1
node_modules/gridstack/dist/dd-base-impl.js.map
generated
vendored
Normal file
1
node_modules/gridstack/dist/dd-base-impl.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dd-base-impl.js","sourceRoot":"","sources":["../src/dd-base-impl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;GAIG;AACH,MAAM,OAAgB,eAAe;IAArC;QASE,gBAAgB;QACN,mBAAc,GAEpB,EAAE,CAAC;IAwDT,CAAC;IAnEC;;;OAGG;IACH,IAAW,QAAQ,KAAgB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAS3D;;;;;OAKG;IACI,EAAE,CAAC,KAAa,EAAE,QAAuB;QAC9C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;IACxC,CAAC;IAED;;;;OAIG;IACI,GAAG,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED;;;OAGG;IACI,MAAM;QACX,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;;OAGG;IACI,OAAO;QACZ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED;;;OAGG;IACI,OAAO;QACZ,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;;;;;OAMG;IACI,YAAY,CAAC,SAAiB,EAAE,KAAY;QACjD,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;YACzE,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;CACF","sourcesContent":["/**\n * dd-base-impl.ts 12.4.2\n * Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license\n */\n\n/**\n * Type for event callback functions used in drag & drop operations.\n * Can return boolean to indicate if the event should continue propagation.\n */\nexport type EventCallback = (event: Event) => boolean|void;\n\n/**\n * Abstract base class for all drag & drop implementations.\n * Provides common functionality for event handling, enable/disable state,\n * and lifecycle management used by draggable, droppable, and resizable implementations.\n */\nexport abstract class DDBaseImplement {\n /**\n * Returns the current disabled state.\n * Note: Use enable()/disable() methods to change state as other operations need to happen.\n */\n public get disabled(): boolean { return this._disabled; }\n\n /** @internal */\n protected _disabled: boolean; // initial state to differentiate from false\n /** @internal */\n protected _eventRegister: {\n [eventName: string]: EventCallback;\n } = {};\n\n /**\n * Register an event callback for the specified event.\n *\n * @param event - Event name to listen for\n * @param callback - Function to call when event occurs\n */\n public on(event: string, callback: EventCallback): void {\n this._eventRegister[event] = callback;\n }\n\n /**\n * Unregister an event callback for the specified event.\n *\n * @param event - Event name to stop listening for\n */\n public off(event: string): void {\n delete this._eventRegister[event];\n }\n\n /**\n * Enable this drag & drop implementation.\n * Subclasses should override to perform additional setup.\n */\n public enable(): void {\n this._disabled = false;\n }\n\n /**\n * Disable this drag & drop implementation.\n * Subclasses should override to perform additional cleanup.\n */\n public disable(): void {\n this._disabled = true;\n }\n\n /**\n * Destroy this drag & drop implementation and clean up resources.\n * Removes all event handlers and clears internal state.\n */\n public destroy(): void {\n delete this._eventRegister;\n }\n\n /**\n * Trigger a registered event callback if one exists and the implementation is enabled.\n *\n * @param eventName - Name of the event to trigger\n * @param event - DOM event object to pass to the callback\n * @returns Result from the callback function, if any\n */\n public triggerEvent(eventName: string, event: Event): boolean|void {\n if (!this.disabled && this._eventRegister && this._eventRegister[eventName])\n return this._eventRegister[eventName](event);\n }\n}\n\n/**\n * Interface for HTML elements extended with drag & drop options.\n * Used to associate DD configuration with DOM elements.\n */\nexport interface HTMLElementExtendOpt<T> {\n /** The HTML element being extended */\n el: HTMLElement;\n /** The drag & drop options/configuration */\n option: T;\n /** Method to update the options and return the DD implementation */\n updateOption(T): DDBaseImplement;\n}\n"]}
|
||||
20
node_modules/gridstack/dist/dd-draggable.d.ts
generated
vendored
Normal file
20
node_modules/gridstack/dist/dd-draggable.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* dd-draggable.ts 12.4.2
|
||||
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
|
||||
import { GridItemHTMLElement, DDDragOpt } from './types';
|
||||
type DDDragEvent = 'drag' | 'dragstart' | 'dragstop';
|
||||
export declare class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt<DDDragOpt> {
|
||||
el: GridItemHTMLElement;
|
||||
option: DDDragOpt;
|
||||
helper: HTMLElement;
|
||||
constructor(el: GridItemHTMLElement, option?: DDDragOpt);
|
||||
on(event: DDDragEvent, callback: (event: DragEvent) => void): void;
|
||||
off(event: DDDragEvent): void;
|
||||
enable(): void;
|
||||
disable(forDestroy?: boolean): void;
|
||||
destroy(): void;
|
||||
updateOption(opts: DDDragOpt): DDDraggable;
|
||||
}
|
||||
export {};
|
||||
367
node_modules/gridstack/dist/dd-draggable.js
generated
vendored
Normal file
367
node_modules/gridstack/dist/dd-draggable.js
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* dd-draggable.ts 12.4.2
|
||||
* Copyright (c) 2021-2025 Alain Dumesny - see GridStack root license
|
||||
*/
|
||||
import { DDManager } from './dd-manager';
|
||||
import { Utils } from './utils';
|
||||
import { DDBaseImplement } from './dd-base-impl';
|
||||
import { isTouch, touchend, touchmove, touchstart, pointerdown, DDTouch } from './dd-touch';
|
||||
// make sure we are not clicking on known object that handles mouseDown
|
||||
const skipMouseDown = 'input,textarea,button,select,option,[contenteditable="true"],.ui-resizable-handle';
|
||||
// let count = 0; // TEST
|
||||
class DDDraggable extends DDBaseImplement {
|
||||
constructor(el, option = {}) {
|
||||
super();
|
||||
this.el = el;
|
||||
this.option = option;
|
||||
/** @internal */
|
||||
this.dragTransform = {
|
||||
xScale: 1,
|
||||
yScale: 1,
|
||||
xOffset: 0,
|
||||
yOffset: 0
|
||||
};
|
||||
// get the element that is actually supposed to be dragged by
|
||||
const handleName = option?.handle?.substring(1);
|
||||
const n = el.gridstackNode;
|
||||
this.dragEls = !handleName || el.classList.contains(handleName) ? [el] : (n?.subGrid ? [el.querySelector(option.handle) || el] : Array.from(el.querySelectorAll(option.handle)));
|
||||
if (this.dragEls.length === 0) {
|
||||
this.dragEls = [el];
|
||||
}
|
||||
// create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions)
|
||||
this._mouseDown = this._mouseDown.bind(this);
|
||||
this._mouseMove = this._mouseMove.bind(this);
|
||||
this._mouseUp = this._mouseUp.bind(this);
|
||||
this._keyEvent = this._keyEvent.bind(this);
|
||||
this.enable();
|
||||
}
|
||||
on(event, callback) {
|
||||
super.on(event, callback);
|
||||
}
|
||||
off(event) {
|
||||
super.off(event);
|
||||
}
|
||||
enable() {
|
||||
if (this.disabled === false)
|
||||
return;
|
||||
super.enable();
|
||||
this.dragEls.forEach(dragEl => {
|
||||
dragEl.addEventListener('mousedown', this._mouseDown);
|
||||
if (isTouch) {
|
||||
dragEl.addEventListener('touchstart', touchstart);
|
||||
dragEl.addEventListener('pointerdown', pointerdown);
|
||||
// dragEl.style.touchAction = 'none'; // not needed unlike pointerdown doc comment
|
||||
}
|
||||
});
|
||||
this.el.classList.remove('ui-draggable-disabled');
|
||||
}
|
||||
disable(forDestroy = false) {
|
||||
if (this.disabled === true)
|
||||
return;
|
||||
super.disable();
|
||||
this.dragEls.forEach(dragEl => {
|
||||
dragEl.removeEventListener('mousedown', this._mouseDown);
|
||||
if (isTouch) {
|
||||
dragEl.removeEventListener('touchstart', touchstart);
|
||||
dragEl.removeEventListener('pointerdown', pointerdown);
|
||||
}
|
||||
});
|
||||
if (!forDestroy)
|
||||
this.el.classList.add('ui-draggable-disabled');
|
||||
}
|
||||
destroy() {
|
||||
if (this.dragTimeout)
|
||||
window.clearTimeout(this.dragTimeout);
|
||||
delete this.dragTimeout;
|
||||
if (this.mouseDownEvent)
|
||||
this._mouseUp(this.mouseDownEvent);
|
||||
this.disable(true);
|
||||
delete this.el;
|
||||
delete this.helper;
|
||||
delete this.option;
|
||||
super.destroy();
|
||||
}
|
||||
updateOption(opts) {
|
||||
Object.keys(opts).forEach(key => this.option[key] = opts[key]);
|
||||
return this;
|
||||
}
|
||||
/** @internal call when mouse goes down before a dragstart happens */
|
||||
_mouseDown(e) {
|
||||
// if real brower event (trusted:true vs false for our simulated ones) and we didn't correctly clear the last touch event, clear things up
|
||||
if (DDTouch.touchHandled && e.isTrusted)
|
||||
DDTouch.touchHandled = false;
|
||||
// don't let more than one widget handle mouseStart
|
||||
if (DDManager.mouseHandled)
|
||||
return;
|
||||
if (e.button !== 0)
|
||||
return true; // only left click
|
||||
// make sure we are not clicking on known object that handles mouseDown, or ones supplied by the user
|
||||
if (!this.dragEls.find(el => el === e.target) && e.target.closest(skipMouseDown))
|
||||
return true;
|
||||
if (this.option.cancel) {
|
||||
if (e.target.closest(this.option.cancel))
|
||||
return true;
|
||||
}
|
||||
this.mouseDownEvent = e;
|
||||
delete this.dragging;
|
||||
delete DDManager.dragElement;
|
||||
delete DDManager.dropElement;
|
||||
// document handler so we can continue receiving moves as the item is 'fixed' position, and capture=true so WE get a first crack
|
||||
document.addEventListener('mousemove', this._mouseMove, { capture: true, passive: true }); // true=capture, not bubble
|
||||
document.addEventListener('mouseup', this._mouseUp, true);
|
||||
if (isTouch) {
|
||||
e.currentTarget.addEventListener('touchmove', touchmove);
|
||||
e.currentTarget.addEventListener('touchend', touchend);
|
||||
}
|
||||
e.preventDefault();
|
||||
// preventDefault() prevents blur event which occurs just after mousedown event.
|
||||
// if an editable content has focus, then blur must be call
|
||||
if (document.activeElement)
|
||||
document.activeElement.blur();
|
||||
DDManager.mouseHandled = true;
|
||||
return true;
|
||||
}
|
||||
/** @internal method to call actual drag event */
|
||||
_callDrag(e) {
|
||||
if (!this.dragging)
|
||||
return;
|
||||
const ev = Utils.initEvent(e, { target: this.el, type: 'drag' });
|
||||
if (this.option.drag) {
|
||||
this.option.drag(ev, this.ui());
|
||||
}
|
||||
this.triggerEvent('drag', ev);
|
||||
}
|
||||
/** @internal called when the main page (after successful mousedown) receives a move event to drag the item around the screen */
|
||||
_mouseMove(e) {
|
||||
// console.log(`${count++} move ${e.x},${e.y}`)
|
||||
const s = this.mouseDownEvent;
|
||||
this.lastDrag = e;
|
||||
if (this.dragging) {
|
||||
this._dragFollow(e);
|
||||
// delay actual grid handling drag until we pause for a while if set
|
||||
if (DDManager.pauseDrag) {
|
||||
const pause = Number.isInteger(DDManager.pauseDrag) ? DDManager.pauseDrag : 100;
|
||||
if (this.dragTimeout)
|
||||
window.clearTimeout(this.dragTimeout);
|
||||
this.dragTimeout = window.setTimeout(() => this._callDrag(e), pause);
|
||||
}
|
||||
else {
|
||||
this._callDrag(e);
|
||||
}
|
||||
}
|
||||
else if (Math.abs(e.x - s.x) + Math.abs(e.y - s.y) > 3) {
|
||||
/**
|
||||
* don't start unless we've moved at least 3 pixels
|
||||
*/
|
||||
this.dragging = true;
|
||||
DDManager.dragElement = this;
|
||||
// if we're dragging an actual grid item, set the current drop as the grid (to detect enter/leave)
|
||||
const grid = this.el.gridstackNode?.grid;
|
||||
if (grid) {
|
||||
DDManager.dropElement = grid.el.ddElement.ddDroppable;
|
||||
}
|
||||
else {
|
||||
delete DDManager.dropElement;
|
||||
}
|
||||
this.helper = this._createHelper();
|
||||
this._setupHelperContainmentStyle();
|
||||
this.dragTransform = Utils.getValuesFromTransformedElement(this.helperContainment);
|
||||
this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment);
|
||||
this._setupHelperStyle(e);
|
||||
const ev = Utils.initEvent(e, { target: this.el, type: 'dragstart' });
|
||||
if (this.option.start) {
|
||||
this.option.start(ev, this.ui());
|
||||
}
|
||||
this.triggerEvent('dragstart', ev);
|
||||
// now track keyboard events to cancel or rotate
|
||||
document.addEventListener('keydown', this._keyEvent);
|
||||
}
|
||||
// e.preventDefault(); // passive = true. OLD: was needed otherwise we get text sweep text selection as we drag around
|
||||
return true;
|
||||
}
|
||||
/** @internal call when the mouse gets released to drop the item at current location */
|
||||
_mouseUp(e) {
|
||||
document.removeEventListener('mousemove', this._mouseMove, true);
|
||||
document.removeEventListener('mouseup', this._mouseUp, true);
|
||||
if (isTouch && e.currentTarget) { // destroy() during nested grid call us again wit fake _mouseUp
|
||||
e.currentTarget.removeEventListener('touchmove', touchmove, true);
|
||||
e.currentTarget.removeEventListener('touchend', touchend, true);
|
||||
}
|
||||
if (this.dragging) {
|
||||
delete this.dragging;
|
||||
delete this.el.gridstackNode?._origRotate;
|
||||
document.removeEventListener('keydown', this._keyEvent);
|
||||
// reset the drop target if dragging over ourself (already parented, just moving during stop callback below)
|
||||
if (DDManager.dropElement?.el === this.el.parentElement) {
|
||||
delete DDManager.dropElement;
|
||||
}
|
||||
this.helperContainment.style.position = this.parentOriginStylePosition || null;
|
||||
if (this.helper !== this.el)
|
||||
this.helper.remove(); // hide now
|
||||
this._removeHelperStyle();
|
||||
const ev = Utils.initEvent(e, { target: this.el, type: 'dragstop' });
|
||||
if (this.option.stop) {
|
||||
this.option.stop(ev); // NOTE: destroy() will be called when removing item, so expect NULL ptr after!
|
||||
}
|
||||
this.triggerEvent('dragstop', ev);
|
||||
// call the droppable method to receive the item
|
||||
if (DDManager.dropElement) {
|
||||
DDManager.dropElement.drop(e);
|
||||
}
|
||||
}
|
||||
delete this.helper;
|
||||
delete this.mouseDownEvent;
|
||||
delete DDManager.dragElement;
|
||||
delete DDManager.dropElement;
|
||||
delete DDManager.mouseHandled;
|
||||
e.preventDefault();
|
||||
}
|
||||
/** @internal call when keys are being pressed - use Esc to cancel, R to rotate */
|
||||
_keyEvent(e) {
|
||||
const n = this.el.gridstackNode;
|
||||
const grid = n?.grid || DDManager.dropElement?.el?.gridstack;
|
||||
if (e.key === 'Escape') {
|
||||
if (n && n._origRotate) {
|
||||
n._orig = n._origRotate;
|
||||
delete n._origRotate;
|
||||
}
|
||||
grid?.cancelDrag();
|
||||
this._mouseUp(this.mouseDownEvent);
|
||||
}
|
||||
else if (n && grid && (e.key === 'r' || e.key === 'R')) {
|
||||
if (!Utils.canBeRotated(n))
|
||||
return;
|
||||
n._origRotate = n._origRotate || { ...n._orig }; // store the real orig size in case we Esc after doing rotation
|
||||
delete n._moving; // force rotate to happen (move waits for >50% coverage otherwise)
|
||||
grid.setAnimation(false) // immediate rotate so _getDragOffset() gets the right dom size below
|
||||
.rotate(n.el, { top: -this.dragOffset.offsetTop, left: -this.dragOffset.offsetLeft })
|
||||
.setAnimation();
|
||||
n._moving = true;
|
||||
this.dragOffset = this._getDragOffset(this.lastDrag, n.el, this.helperContainment);
|
||||
this.helper.style.width = this.dragOffset.width + 'px';
|
||||
this.helper.style.height = this.dragOffset.height + 'px';
|
||||
Utils.swap(n._orig, 'w', 'h');
|
||||
delete n._rect;
|
||||
this._mouseMove(this.lastDrag);
|
||||
}
|
||||
}
|
||||
/** @internal create a clone copy (or user defined method) of the original drag item if set */
|
||||
_createHelper() {
|
||||
let helper = this.el;
|
||||
if (typeof this.option.helper === 'function') {
|
||||
helper = this.option.helper(this.el);
|
||||
}
|
||||
else if (this.option.helper === 'clone') {
|
||||
helper = Utils.cloneNode(this.el);
|
||||
}
|
||||
if (!helper.parentElement) {
|
||||
Utils.appendTo(helper, this.option.appendTo === 'parent' ? this.el.parentElement : this.option.appendTo);
|
||||
}
|
||||
this.dragElementOriginStyle = DDDraggable.originStyleProp.map(prop => this.el.style[prop]);
|
||||
return helper;
|
||||
}
|
||||
/** @internal set the fix position of the dragged item */
|
||||
_setupHelperStyle(e) {
|
||||
this.helper.classList.add('ui-draggable-dragging');
|
||||
this.el.gridstackNode?.grid?.el.classList.add('grid-stack-dragging');
|
||||
// TODO: set all at once with style.cssText += ... ? https://stackoverflow.com/questions/3968593
|
||||
const style = this.helper.style;
|
||||
style.pointerEvents = 'none'; // needed for over items to get enter/leave
|
||||
// style.cursor = 'move'; // TODO: can't set with pointerEvents=none ! (no longer in CSS either as no-op)
|
||||
style.width = this.dragOffset.width + 'px';
|
||||
style.height = this.dragOffset.height + 'px';
|
||||
style.willChange = 'left, top';
|
||||
style.position = 'fixed'; // let us drag between grids by not clipping as parent .grid-stack is position: 'relative'
|
||||
this._dragFollow(e); // now position it
|
||||
style.transition = 'none'; // show up instantly
|
||||
setTimeout(() => {
|
||||
if (this.helper) {
|
||||
style.transition = null; // recover animation
|
||||
}
|
||||
}, 0);
|
||||
return this;
|
||||
}
|
||||
/** @internal restore back the original style before dragging */
|
||||
_removeHelperStyle() {
|
||||
this.helper.classList.remove('ui-draggable-dragging');
|
||||
this.el.gridstackNode?.grid?.el.classList.remove('grid-stack-dragging');
|
||||
const node = this.helper?.gridstackNode;
|
||||
// don't bother restoring styles if we're gonna remove anyway...
|
||||
if (!node?._isAboutToRemove && this.dragElementOriginStyle) {
|
||||
const helper = this.helper;
|
||||
// don't animate, otherwise we animate offseted when switching back to 'absolute' from 'fixed'.
|
||||
// TODO: this also removes resizing animation which doesn't have this issue, but others.
|
||||
// Ideally both would animate ('move' would immediately restore 'absolute' and adjust coordinate to match,
|
||||
// then trigger a delay (repaint) to restore to final dest with animate) but then we need to make sure 'resizestop'
|
||||
// is called AFTER 'transitionend' event is received (see https://github.com/gridstack/gridstack.js/issues/2033)
|
||||
const transition = this.dragElementOriginStyle['transition'] || null;
|
||||
helper.style.transition = this.dragElementOriginStyle['transition'] = 'none'; // can't be NULL #1973
|
||||
DDDraggable.originStyleProp.forEach(prop => helper.style[prop] = this.dragElementOriginStyle[prop] || null);
|
||||
setTimeout(() => helper.style.transition = transition, 50); // recover animation from saved vars after a pause (0 isn't enough #1973)
|
||||
}
|
||||
delete this.dragElementOriginStyle;
|
||||
return this;
|
||||
}
|
||||
/** @internal updates the top/left position to follow the mouse */
|
||||
_dragFollow(e) {
|
||||
const containmentRect = { left: 0, top: 0 };
|
||||
// if (this.helper.style.position === 'absolute') { // we use 'fixed'
|
||||
// const { left, top } = this.helperContainment.getBoundingClientRect();
|
||||
// containmentRect = { left, top };
|
||||
// }
|
||||
const style = this.helper.style;
|
||||
const offset = this.dragOffset;
|
||||
style.left = (e.clientX + offset.offsetLeft - containmentRect.left) * this.dragTransform.xScale + 'px';
|
||||
style.top = (e.clientY + offset.offsetTop - containmentRect.top) * this.dragTransform.yScale + 'px';
|
||||
}
|
||||
/** @internal */
|
||||
_setupHelperContainmentStyle() {
|
||||
this.helperContainment = this.helper.parentElement;
|
||||
if (this.helper.style.position !== 'fixed') {
|
||||
this.parentOriginStylePosition = this.helperContainment.style.position;
|
||||
if (getComputedStyle(this.helperContainment).position.match(/static/)) {
|
||||
this.helperContainment.style.position = 'relative';
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/** @internal */
|
||||
_getDragOffset(event, el, parent) {
|
||||
// in case ancestor has transform/perspective css properties that change the viewpoint
|
||||
let xformOffsetX = 0;
|
||||
let xformOffsetY = 0;
|
||||
if (parent) {
|
||||
xformOffsetX = this.dragTransform.xOffset;
|
||||
xformOffsetY = this.dragTransform.yOffset;
|
||||
}
|
||||
const targetOffset = el.getBoundingClientRect();
|
||||
return {
|
||||
left: targetOffset.left,
|
||||
top: targetOffset.top,
|
||||
offsetLeft: -event.clientX + targetOffset.left - xformOffsetX,
|
||||
offsetTop: -event.clientY + targetOffset.top - xformOffsetY,
|
||||
width: targetOffset.width * this.dragTransform.xScale,
|
||||
height: targetOffset.height * this.dragTransform.yScale
|
||||
};
|
||||
}
|
||||
/** @internal TODO: set to public as called by DDDroppable! */
|
||||
ui() {
|
||||
const containmentEl = this.el.parentElement;
|
||||
const containmentRect = containmentEl.getBoundingClientRect();
|
||||
const offset = this.helper.getBoundingClientRect();
|
||||
return {
|
||||
position: {
|
||||
top: (offset.top - containmentRect.top) * this.dragTransform.yScale,
|
||||
left: (offset.left - containmentRect.left) * this.dragTransform.xScale
|
||||
}
|
||||
/* not used by GridStack for now...
|
||||
helper: [this.helper], //The object arr representing the helper that's being dragged.
|
||||
offset: { top: offset.top, left: offset.left } // Current offset position of the helper as { top, left } object.
|
||||
*/
|
||||
};
|
||||
}
|
||||
}
|
||||
/** @internal properties we change during dragging, and restore back */
|
||||
DDDraggable.originStyleProp = ['width', 'height', 'transform', 'transform-origin', 'transition', 'pointerEvents', 'position', 'left', 'top', 'minWidth', 'willChange'];
|
||||
export { DDDraggable };
|
||||
//# sourceMappingURL=dd-draggable.js.map
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user