Explorar o código

exported acl struct from Storage

Piotr Labudda %!s(int64=8) %!d(string=hai) anos
pai
achega
342a6362f9

+ 2 - 519
SE/se-lib/Route/Storage.php

@@ -621,8 +621,8 @@ jQuery(document).on('p5UIBtnAjax:Storage:checkObjectInstallAjax:ajaxLoaded', fun
 							UI::h('div', ['class' => "p5UI__dropdown-content"], [
 								UI::h('input', ['type' => "text", 'placeholder' => "Search..", 'class' => "p5UI__dropdown-input", 'onkeyup' => "p5_Storage_actions_filterInput(this)"], null),
 								UI::h('a', [ 'href' => $item['reinstallLink'] ], "reinstall"),
-								UI::h('a', [ 'href' => $this->getLink('tableStruct', [ 'idStorage' => $idStorage, 'table' => $item['name'] ]) ], "struktura tabeli (TableAcl)"),
-								UI::h('a', [ 'href' => $this->getLink('objectStruct', [ 'idStorage' => $idStorage, 'namespace' => $item['namespace'] ]) ], "struktura obiektu (AntAcl)"),
+								UI::h('a', [ 'href' => Router::getRoute('Storage_AclStruct')->getLink('tableStruct', [ 'idStorage' => $idStorage, 'table' => $item['name'] ]) ], "struktura tabeli (TableAcl)"),
+								UI::h('a', [ 'href' => Router::getRoute('Storage_AclStruct')->getLink('', [ 'idStorage' => $idStorage, 'namespace' => $item['namespace'] ]) ], "struktura obiektu (AntAcl)"),
 								UI::h('a', [ 'href' => $this->getLink('rawInfo', [ 'idStorage' => $idStorage, 'table' => $item['name'] ]) ], "raw info"),
 								UI::h('a', [ 'href' => Router::getRoute('ViewTableAjax')->getLink('', ['namespace' => $item['namespace']]) ], "view table"),
 								UI::h('a', [ 'href' => Router::getRoute('ViewObject')->getLink('', ['namespace' => $item['namespace']]) ], "view object"),
@@ -687,523 +687,6 @@ jQuery(document).on('p5UIBtnAjax:Storage:checkObjectInstallAjax:ajaxLoaded', fun
 		UI::dol();
 	}
 
-	public function objectStructAction() {
-		UI::gora();
-		UI::menu();
-		$this->navView();
-		UI::startTag('div', [ 'class' => 'container-fluid' ]);
-		try {
-			$namespace = V::get('namespace', '', $_GET);
-			if (empty($namespace)) throw new Exception("Missing param namespace");
-
-			if ('setFieldRefConfig' === V::get('_postTask', '', $_POST)) {
-				$field = V::get('field', '', $_POST);
-				$source = V::get('source', '', $_POST);
-				switch ($source) {
-					case 'view':
-						$refSelect = ACL::generateRefSelectSqlByFlatRelationCache($namespace, $field);
-						ACL::setRefSource($namespace, $field, 'view', $refSelect);
-						break;
-					case 'table': ACL::setRefSource($namespace, $field, 'table'); break;
-				}
-			}
-			if ('preview' === V::get('_postTask', '', $_POST)) {
-				try {
-					$item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
-					$localFields = array_filter($item['field'], function ($field) {
-						return $field['isLocal'];
-					});
-					$refFields = array_filter($item['field'], function ($field) {
-						return 'ref:' === substr($field['xsdType'], 0, 4);
-					});
-					$activeRefFields = array_filter($refFields, function ($field) {
-						$refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
-						return (1 == DB::getPDO()->fetchValue("
-							select t.isObjectActive
-							from `CRM_#CACHE_ACL_OBJECT` t
-							where t.`namespace` = '{$refNamespace}'
-						"));
-					});
-					$query = [ 'cols' => array_merge(
-						array_map(
-							function ($field) {
-								return $field['fieldNamespace'];
-							}, $localFields
-						),
-						array_map(
-							function ($field) {
-								return "{$field['fieldNamespace']}/*";
-							}, $activeRefFields
-						)
-					) ];
-					DBG::nicePrint($query, '$query');
-
-					$previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
-						'limit' => 3
-					]);
-					DBG::nicePrint($previewItems, 'items with ref limit 3');
-				} catch (Exception $e) {
-					DBG::log($e);
-					UI::alert('danger', $e->getMessage());
-				}
-			}
-
-			$item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
-			usort($item['field'], function ($a, $b) {
-				if ($a['fieldNamespace'] > $b['fieldNamespace']) return 1;
-				if ($a['fieldNamespace'] < $b['fieldNamespace']) return -1;
-				return 0;
-			});
-			$thisGetLink = array($this, 'getLink');
-			{ // not installed ref
-				$refFields = array_filter($item['field'], function ($field) {
-					return 'ref:' === substr($field['xsdType'], 0, 4);
-				});
-				UI::table([
-					'caption' => UI::h('span', [], "Obiekty powiązane (TODO backRef)"),
-					'rows' => array_map(function ($field) use ($thisGetLink) {
-						$refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
-						$isInstalled = (1 == DB::getPDO()->fetchValue("
-							select t.isObjectActive
-							from `CRM_#CACHE_ACL_OBJECT` t
-							where t.`namespace` = '{$refNamespace}'
-						"));
-						$refSource = null;
-						if ($isInstalled) {
-							try {
-								$refTable = ACL::getRefTable($field['objectNamespace'], $field['fieldNamespace']);
-								DBG::log($refTable, 'array', "getRefTable('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
-								$refSource = ACL::getRefSource($field['objectNamespace'], $field['fieldNamespace']);
-								DBG::log($refSource, 'array', "ACL::getRefSource('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
-							} catch (Exception $e) {
-								DBG::log($e);
-							}
-						}
-						return [
-							'fieldName' => $field['fieldNamespace'],
-							// 'xsdType' => $field['xsdType'], // always === "ref:{$field['fieldNamespace']}"
-							'ref object' => UI::h('a', [
-								'class' => "btn btn-xs btn-link",
-								'href' => $thisGetLink('objectStruct', [ 'namespace' => $refNamespace ])
-							], "objectStruct ({$refNamespace})"),
-							'ref source' => UI::h('div', [],
-								(null === $refSource)
-								? [ "ref object not installed" ] // TODO: link to install? is table struct
-								: [
-										// UI::hButtonAjax("Tabela ref", "setFieldRefConfig", [
-										// 	'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
-										// 	'href' => $thisGetLink('setFieldRefConfig'),
-										// 	'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'table' ]
-										// ]),
-										// UI::hButtonAjax("Widok (cache)", "setFieldRefConfig", [
-										// 	'title' => "Według flat_relation_cache",
-										// 	'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
-										// 	'href' => $thisGetLink('setFieldRefConfig'),
-										// 	'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'view' ]
-										// ]),
-										UI::hButtonPost("Tabela ref", [
-											'title' => "Według wygenerowanej tabeli REF",
-											'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
-											// 'href' => $thisGetLink('setFieldRefConfig'),
-											'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'table' ]
-										]),
-										UI::hButtonPost("Widok (cache)", [
-											'title' => "Według flat_relation_cache",
-											'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
-											// 'href' => $thisGetLink('setFieldRefConfig'),
-											'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'view' ]
-										]),
-									]
-							),
-							'@class' => ($isInstalled) ? "success" : "danger",
-						]; // TODO: link to install object
-					}, $refFields)
-				]);
-			}
-			UI::table([
-				'caption' => UI::h('span', [], [
-					UI::h('span', [ 'style' => "margin-right:6px;color:#000" ], "Struktura obiektu '{$item['namespace']}'"),
-					' &nbsp; ',
-					( ($item['idZasob'] > 0)
-						? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "[{$item['idZasob']}]")
-						: UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
-							UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
-								'class' => "btn btn-xs btn-primary",
-								'href' => $this->getLink('addAclObjectToZasobyAjax'),
-								'data' => [
-									'idStorage' => $item['idDatabase'],
-									'namespace' => $item['namespace'],
-								]
-							])
-						])
-					),
-					' &nbsp; ',
-					( ($item['isObjectActive'] > 0)
-						? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
-						: UI::h('span', [ 'title' => "Namespace not active" ], [
-							($item['idZasob'] > 0)
-							? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
-									'class' => "btn btn-xs btn-primary",
-									'href' => $this->getLink('activateObjectAjax'),
-									'data' => [
-										'namespace' => $item['namespace'],
-									]
-								])
-							: '',
-						])
-					),
-					' &nbsp; ',
-					UI::h('a', [
-						'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
-						'class' => "btn btn-sm btn-link"
-					], "Przeglądaj tabelę"),
-					( ($item['idZasob'] > 0)
-						? UI::h('a', [
-								'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
-								'class' => "btn btn-sm btn-link",
-								'title' => "Struktura tabeli w drzewie zasobów"
-							], "Zasoby")
-						: ''
-					),
-					( ($item['idZasob'] > 0)
-						? UI::h('a', [
-								'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
-								'class' => "btn btn-sm btn-link",
-								'title' => "Procesy dla aktualnie przeglądanej tabeli"
-							], "Procesy")
-						: ''
-					),
-					UI::h('a', [
-						'href' => $this->getLink('objectReinstall', ['namespace' => $item['namespace']]),
-						'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
-						'title' => "Zainstaluje ponownie obiekt"
-					], "reinstall object"),
-					UI::h('a', [
-						'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
-						'class' => "btn btn-sm btn-link",
-						'title' => "Uprawnienia - analiza użycia komórek w procesach"
-					], "Uprawnienia (analiza użycia)"),
-					UI::hButtonPost("(podgląd z relacjami)", [
-						'data' => [
-							'_postTask' => 'preview'
-						],
-						'class' => 'btn btn-sm btn-link', 'style' => "font-style:italic",
-						'title' => "Podgląd kilku ostatnich obiektów wraz z relacjami"
-					]),
-				]),
-				'rows' => array_map(function ($field) use ($item, $thisGetLink) {
-					$tblItem = []; foreach ($field as $k => $v) $tblItem[$k] = $v;
-					$tblItem['namespace'] = UI::h('span', [], [
-						UI::h('span', ['style' => "color:#aaa"], substr($field['namespace'], 0, strlen($field['objectNamespace']) + 1)),
-						UI::h('span', ['style' => "color:#000"], substr($field['namespace'], strlen($field['objectNamespace']) + 1)),
-					]);
-					$tblItem['idZasob'] = ($field['idZasob'] > 0)
-						? $field['idZasob']
-						: (
-								($item['idZasob'] > 0)
-								? UI::hButtonAjax("+ do zasobów", 'addFieldToZasobyAjax', [
-										'class' => "btn btn-xs btn-primary",
-										'href' => $thisGetLink('addFieldToZasobyAjax'),
-										'data' => [
-											'namespace' => $item['namespace'],
-											'fieldNamespace' => $field['namespace'],
-										]
-									])
-								: UI::h('span', ['title'=>"Brak Nr zasobu dla obiektu", 'class'=>"btn btn-xs btn-danger"], "Brak nr zasobu obiektu")
-							)
-					;
-					unset($tblItem['objectNamespace']);
-					unset($tblItem['fieldNamespace']);
-					return $tblItem;
-				}, $item['field'])
-			]);
-			UI::hButtonAjaxOnResponse('addFieldToZasobyAjax', /* payload, n */ "
-				if (!payload.type) return false
-				if (payload.body && payload.body.id && payload.body.id > 0) { // if ('success' == payload.type) {
-					n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
-				}
-				jQuery.notify(payload.msg, payload.type)
-			");
-			UI::hButtonAjaxOnResponse('addAclObjectToZasobyAjax', /* payload, n */ "
-				if (!payload.type) return false
-				if ('success' === payload.type || 'info' === payload.type) {
-					if (payload.body && payload.body.id && payload.body.id > 0) {
-						n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
-					} else {
-						console.log('TODO: addAclObjectToZasobyAjax unknown response', payload);
-					}
-					window.location.reload()
-				}
-			");
-			UI::hButtonAjaxOnResponse('activateObjectAjax', /* payload, n */ "
-				jQuery.notify(payload.msg, payload.type)
-				if (!payload.type) return false
-				if ('success' === payload.type || 'info' === payload.type) {
-					if (payload.body && payload.body.isObjectActive && payload.body.isObjectActive > 0) {
-						n.parentNode.replaceChild(document.createTextNode('Active'), n)
-					} else {
-						console.log('TODO: activateObjectAjax unknown response', payload);
-					}
-				}
-			");
-			if ($item['isObjectActive']) {
-				echo UI::hButtonAjax("Dodaj podstawowy proces dla obiektu '{$item['namespace']}' - read only (TODO)", 'addObjectBaseProcesAjax', [
-					'class' => "btn btn-xs btn-default",
-					'href' => $this->getLink('addObjectBaseProcesAjax'),
-					'data' => [ 'namespace' => $item['namespace'] ]
-				]);
-				UI::hButtonAjaxOnResponse('addObjectBaseProcesAjax', /* payload, n */ "
-					jQuery.notify(payload.msg, payload.type)
-				");
-			}
-			DBG::nicePrint($item, '$item');
-		} catch (Exception $e) {
-			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
-			DBG::log($e);
-		}
-		UI::endTag('div'); // .container-fluid
-		UI::dol();
-	}
-
-	public function tableStructAction() {
-		UI::gora();
-		UI::menu();
-		$this->navView();
-		try {
-			$idStorage = V::get('idStorage', 0, $_REQUEST, 'int');
-			if (empty($idStorage)) throw new Exception("Missing id storage");
-			$storageList = $this->getStorageList();
-			if (empty($storageList)) throw new Exception("No storage defined");
-			if (!array_key_exists($idStorage, $storageList)) throw new Exception("Storage not exists");
-			$tblName = V::get('table', '', $_REQUEST, 'word');
-			if (empty($tblName)) throw new Exception("No table name");
-
-			$storagePdo = DB::getStorage($idStorage);
-			$tblStruct = $storagePdo->getTableStruct($tblName);
-
-			$idTable = $this->fetchTableId($idStorage, $tblName);
-			if ($idTable <= 0) {
-				UI::alert('warning', "Zasob tabela '{$tblName}' nie istnieje");// TODO: add p5UI btn
-				DBG::table("tblStruct", $tblStruct, __CLASS__, __FUNCTION__, __LINE__);
-				throw new Exception("Zasob tabela '{$tblName}' nie istnieje");
-			}
-
-			$cellZasobList = array();
-			foreach (DB::getPDO()->fetchAllByKey("
-					select z.ID, z.`DESC`, z.`TYPE` as ZASOB_TYPE, z.A_STATUS
-					from CRM_LISTA_ZASOBOW z
-					where z.PARENT_ID = '{$idTable}'
-				", $key = 'DESC') as $ind => $row) {
-				$cellZasobList[strtolower($ind)] = $row;
-			}
-
-			$emptyItem = array();
-			$emptyItem['name'] = '';
-			$emptyItem['id_zasob'] = '';
-			$emptyItem['zasob_type'] = '';
-			$emptyItem['uwagi'] = '';
-
-			$emptyItem['type'] = '';
-			$emptyItem['is_nullable'] = '';
-			$emptyItem['default_value'] = '';
-			$emptyItem['default_is_null'] = '';
-			$emptyItem['max_length'] = '';
-			$emptyItem['num_precision'] = '';
-			$emptyItem['num_scale'] = '';
-			$emptyItem['char_encoding'] = '';
-			$emptyItem['char_collation'] = '';
-			$emptyItem['extra'] = '';
-			$emptyItem['raw_storage_type'] = '';
-
-			$tableList = array();
-			foreach ($tblStruct as $row) {
-				$cellName = $row['name'];
-				$tblItem = V::cloneArray($emptyItem);
-				$tblItem['name'] = $cellName;
-				foreach ($row as $fldName => $fldVal) {
-					if (array_key_exists($fldName, $tblItem)) $tblItem[$fldName] = $fldVal;
-				}
-				$tblItem['uwagi'] = '';
-				$lowerCellName = strtolower($cellName);
-				$tblZasob = V::get($lowerCellName, '', $cellZasobList);
-				if ($tblZasob) {
-					$cellZasobList[$lowerCellName]['_checked'] = true;
-					$tblItem['id_zasob'] = $tblZasob['ID'];
-					$tblItem['zasob_type'] = $tblZasob['ZASOB_TYPE'];
-				} else {
-					$tblItem['uwagi'] .= '!Zasob';//'TODO: ADD ZASOB';
-					$ajaxAddZasobLink = Request::getPathUri() . "index.php?_route=Storage&_task=addCellToZasoby&idStorage={$idStorage}&tblName={$tblName}&cellName={$cellName}";
-					$onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addCellToZasoby', { href: '{$ajaxAddZasobLink}' })";
-					$tblItem['id_zasob'] = '<a onclick="'.$onClick.'" class="btn btn-xs btn-primary" href="#">TODO: ADD ZASOB</a>';
-				}
-				$tableList[] = $tblItem;
-			}
-			foreach ($cellZasobList as $cellName => $row) {
-				if ('URL_ACTION' == $row['ZASOB_TYPE']) continue;
-				if (!$row['_checked']) {
-					$tblItem = V::cloneArray($emptyItem);
-					$tblItem['name'] = $cellName;
-					$tblItem['id_zasob'] = $row['ID'];
-					$tblItem['zasob_type'] = $row['ZASOB_TYPE'];
-					$tblItem['uwagi'] = '!DB';//'TODO: nie istnieje w bazie danych';
-					$tableList[] = $tblItem;
-				}
-			}
-			usort($tableList, function($rowA, $rowB) {
-				$a = $rowA['name']; $b = $rowB['name'];
-				if ('ID' == $a) return -1;
-				if ('ID' == $b) return 1;
-				if ($a == $b) return 0;
-				$a1 = substr($a, 0, 1); $b1 = substr($b, 0, 1);
-				if (('_' == $a1 || '_' == $b1) && $a1 != $b1) {
-					return ($a1 < $b1) ? 1 : -1;
-				}
-				return ($a < $b) ? -1 : 1;
-			});
-			UI::table([
-				'caption' => UI::h('span', [], [
-					"Komórki [{$idTable}] ",
-					UI::h('a', [
-						'href' => "index.php?_route=ViewTableAjax&namespace=default_db/{$tblName}",
-						'class' => "btn btn-md btn-link"
-					], "Przeglądaj tabelę"),
-					UI::h('a', [
-						'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$idTable}&filtr_ids=%2B&filtr_ob=%2B",
-						'class' => "btn btn-md btn-link",
-						'title' => "Struktura aktualnie przeglądanej tabeli"
-					], "Zasoby"),
-					UI::h('a', [
-						'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$idTable}",
-						'class' => "btn btn-md btn-link",
-						'title' => "Procesy dla aktualnie przeglądanej tabeli"
-					], "Procesy"),
-					UI::h('a', [
-						'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => "default_db/{$tblName}" ]),
-						'class' => "btn btn-md btn-link",
-						'title' => "Uprawnienia - analiza użycia komórek w procesach"
-					], "Uprawnienia (analiza użycia)"),
-				]),
-				'cols' => array_keys($emptyItem),
-				'rows' => $tableList
-			]);
-			echo UI::h('script', [], "
-				jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:click', function(e, n, payload) {
-					console.log('event p5UIBtnAjax:Storage:addCellToZasoby:click', n, payload);
-				});
-				jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', function(e, n, payload) {
-					console.log('event p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', n, payload);
-					if ('success' == payload.type && payload.body && payload.body.id > 0) {
-						var cellUwagiJQNode = jQuery(n).parents('td').next('td');
-						cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
-						jQuery(n).parents('td').text(payload.body.id);
-						jQuery(n).remove();
-					}
-					jQuery.notify(payload.msg, payload.type);
-				});
-			");
-			$ajaxAddZasobLink = Request::getPathUri() . "index.php?_route=Storage&_task=addGeomEtykietaCells&idStorage={$idStorage}&tblName={$tblName}";
-			$onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addGeomEtykietaCells', { href: '{$ajaxAddZasobLink}' })";
-			UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj komórki etykiet", true);
-			echo "<i>(<code>`etykieta_x`</code>, <code>`etykieta_y`</code>, <code>`etykieta_obrot`</code>)</i>";
-			echo UI::h('script', [], "
-				jQuery(document).on('p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', function(e, n, payload) {
-					console.log('event p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', n, payload);
-					if ('success' == payload.type && payload.body && payload.body.id > 0) {
-						var cellUwagiJQNode = jQuery(n).parents('td').next('td');
-						cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
-						jQuery(n).parents('td').text(payload.body.id);
-						jQuery(n).remove();
-					}
-					jQuery.notify(payload.msg, payload.type);
-				});
-			");
-
-
-			$tableActions = array_filter($cellZasobList, function ($row) {
-				return ('URL_ACTION' == $row['ZASOB_TYPE']);
-			});
-			UI::table([
-				'caption' => "tableActions",
-				// 'cols' => array_keys($emptyItem),
-				'rows' => array_map(function ($item) {
-					$sqlIdAction = DB::getPDO()->quote($item['ID'], PDO::PARAM_INT);
-					$args = DB::getPDO()->fetchAll("
-						select z.`DESC`
-								, a.ID as ALIAS_ID, a.`DESC` as ALIAS_DESC, a.OPIS as ALIAS_OPIS
-						from CRM_LISTA_ZASOBOW z
-							left join CRM_LISTA_ZASOBOW a on(a.ID = z.ALIAS_ID)
-						where z.PARENT_ID = {$sqlIdAction}
-							and z.`TYPE` = 'PARAM_IN'
-					");
-					$definitionArgs = DB::getPDO()->fetchAll("
-						select p.ID, p.`DESC`
-						from CRM_LISTA_ZASOBOW z
-							join CRM_LISTA_ZASOBOW d on(d.ID = z.ALIAS_ID)
-							left join CRM_LISTA_ZASOBOW p on(p.PARENT_ID = d.ID)
-						where z.ID = {$sqlIdAction}
-							and p.`TYPE` = 'PARAM_IN'
-					");
-					$flatDefinitionArgs = implode(";", array_map(function ($arg) {
-						return "{$arg['ID']}={$arg['DESC']}";
-					}, $definitionArgs));
-					return [
-						'label' => DB::getPDO()->fetchValue(" select z.OPIS from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdAction} ") . " " .
-							UI::h('i', [
-								'class' => "glyphicon glyphicon-pencil",
-								'style' => "cursor:pointer",
-								'onClick' => "return Storage__tableStruct__editActionLabel(this, {$sqlIdAction})"], ''),
-						'args' => implode("<br>&", array_map(function ($item) {
-							return (NULL === $item['ALIAS_ID'])
-								? $item['DESC']
-								: "{$item['DESC']}=" . '{$row["' . $item['ALIAS_DESC'] . '"]}';// TODO: add rmParam btn
-						}, $args)) . " " .
-							UI::h('i', [
-								'class' => "glyphicon glyphicon-plus-sign",
-								'style' => "cursor:pointer",
-								'title' => "Dodaj PARAM_IN",
-								'onClick' => "return Storage__tableStruct__addParamAction(this, {$sqlIdAction}, '{$flatDefinitionArgs}')"], ''),
-						// 'args_info' => '<pre>' . var_export($args, true) . '</pre>',
-						'ID' => $item['ID'],
-						'DESC' => $item['DESC'],
-						'A_STATUS' => $item['A_STATUS'],
-						'definition args' => implode("", array_map(function ($item) {
-							return '<div style="white-space:nowrap">' . "[{$item['ID']}] {$item['DESC']}" . '</div>';
-						}, $definitionArgs)),
-					];
-				}, $tableActions)
-			]);
-			echo UI::h('button', [
-				'onClick'=>"Storage__tableStruct__addAction()",
-				'class'=>"btn btn-xs btn-default"
-			], "Dodaj Akcję");
-			echo UI::h('link', ['rel'=>"stylesheet", 'type'=>"text/css", 'href'=>"static/sweetalert2.min.css"]);
-			echo UI::h('script', ['src'=>"static/sweetalert2.min.js"]);
-			echo UI::h('style', [], "
-				.swal2-radio.p5-swal-radio-as-list { text-align:left }
-				.swal2-radio.p5-swal-radio-as-list > label { display:block; margin-left:20px }
-			");
-			UI::inlineJS(__FILE__ . '.tableActions.js', [
-				'ID_STORAGE' => $idStorage,
-				'TABLE_NAME' => $tblName,
-				'FETCH_URL' => Request::getPathUri() . 'index.php?_route=Storage&_task=fetchActionListAjax',
-				'ADD_ACTION_URL' => Request::getPathUri() . 'index.php?_route=Storage&_task=addActionAjax'
-			]);
-			echo '<hr>';
-
-			$ajaxAddBaseProcesLink = Request::getPathUri() . "index.php?_route=Storage&_task=addTableBaseProces&idStorage={$idStorage}&tblName={$tblName}";
-			$onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addTableBaseProces', { href: '{$ajaxAddBaseProcesLink}' })";
-			UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj podstawowy proces dla tabeli '{$tblName}' - read only", true);
-			echo UI::h('script', [], "
-				jQuery(document).on('p5UIBtnAjax:Storage:addTableBaseProces:ajaxLoaded', function(e, n, payload) {
-					jQuery.notify(payload.msg, payload.type);
-				});
-			");
-		} catch (Exception $e) {
-			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
-		}
-		UI::dol();
-	}
-
 	public function fetchActionListAjaxAction() {
 		Response::sendTryCatchJson(array($this, 'fetchActionListAjax'), $args = 'JSON_FROM_REQUEST_BODY');
 	}

+ 545 - 0
SE/se-lib/Route/Storage/AclStruct.php

@@ -0,0 +1,545 @@
+<?php
+
+Lib::loadClass('RouteBase');
+Lib::loadClass('Router');
+Lib::loadClass('Response');
+Lib::loadClass('UI');
+Lib::loadClass('SchemaFactory');
+
+class Route_Storage_AclStruct extends RouteBase {
+
+	public function handleAuth() {
+		if (!User::logged()) {
+			User::authByRequest();
+		}
+	}
+
+	public function defaultAction() { // objectStructAction
+		UI::gora();
+		UI::menu();
+		// Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
+		UI::startTag('div', [ 'class' => 'container-fluid' ]);
+		try {
+			$namespace = V::get('namespace', '', $_GET);
+			if (empty($namespace)) throw new Exception("Missing param namespace");
+
+			if ('setFieldRefConfig' === V::get('_postTask', '', $_POST)) {
+				$field = V::get('field', '', $_POST);
+				$source = V::get('source', '', $_POST);
+				switch ($source) {
+					case 'view':
+						$refSelect = ACL::generateRefSelectSqlByFlatRelationCache($namespace, $field);
+						ACL::setRefSource($namespace, $field, 'view', $refSelect);
+						break;
+					case 'table': ACL::setRefSource($namespace, $field, 'table'); break;
+				}
+			}
+			if ('preview' === V::get('_postTask', '', $_POST)) {
+				try {
+					$item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
+					$localFields = array_filter($item['field'], function ($field) {
+						return $field['isLocal'];
+					});
+					$refFields = array_filter($item['field'], function ($field) {
+						return 'ref:' === substr($field['xsdType'], 0, 4);
+					});
+					$activeRefFields = array_filter($refFields, function ($field) {
+						$refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
+						return (1 == DB::getPDO()->fetchValue("
+							select t.isObjectActive
+							from `CRM_#CACHE_ACL_OBJECT` t
+							where t.`namespace` = '{$refNamespace}'
+						"));
+					});
+					$query = [ 'cols' => array_merge(
+						array_map(
+							function ($field) {
+								return $field['fieldNamespace'];
+							}, $localFields
+						),
+						array_map(
+							function ($field) {
+								return "{$field['fieldNamespace']}/*";
+							}, $activeRefFields
+						)
+					) ];
+					DBG::nicePrint($query, '$query');
+
+					$previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
+						'limit' => 3
+					]);
+					DBG::nicePrint($previewItems, 'items with ref limit 3');
+				} catch (Exception $e) {
+					DBG::log($e);
+					UI::alert('danger', $e->getMessage());
+				}
+			}
+
+			$item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
+			usort($item['field'], function ($a, $b) {
+				if ($a['fieldNamespace'] > $b['fieldNamespace']) return 1;
+				if ($a['fieldNamespace'] < $b['fieldNamespace']) return -1;
+				return 0;
+			});
+
+			echo UI::h('details', ['style'=>"margin-bottom:24px; padding:0 10px; background-color:#eee", 'open' => "open"], [
+				UI::h('summary', ['style'=>"font-size:1.4em; line-height:2em; cursor:pointer; outline:none"], [
+					"Struktura obiektu '{$namespace}' ",
+					// UI::h('small', ['style'=>"font-size:0.8em; font-style:italic; color:#aaa"], " więcej...")
+				]),
+				UI::h('div', ['style'=>"padding:4px 24px; border-top:1px solid #fff"], [
+					UI::h('span', ['style'=>"margin-right:12px"], [
+						( ($item['idZasob'] > 0)
+						? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "Nr zasobu [{$item['idZasob']}]")
+						: UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
+								UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
+									'class' => "btn btn-xs btn-primary",
+									'href' => Router::getRoute('Storage')->getLink('addAclObjectToZasobyAjax'),
+									'data' => [
+										'idStorage' => $item['idDatabase'],
+										'namespace' => $item['namespace'],
+									]
+								])
+							])
+						),
+					]),
+					UI::h('span', ['style'=>"margin:0 12px"], [
+						( ($item['isObjectActive'] > 0)
+							? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
+							: UI::h('span', [ 'title' => "Namespace not active" ], [
+								($item['idZasob'] > 0)
+								? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
+										'class' => "btn btn-xs btn-primary",
+										'href' => Router::getRoute('Storage')->getLink('activateObjectAjax'),
+										'data' => [
+											'namespace' => $item['namespace'],
+										]
+									])
+								: '',
+							])
+						),
+					]),
+					UI::h('a', [
+						'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
+						'class' => "btn btn-sm btn-link"
+					], "Przeglądaj tabelę"),
+					( ($item['idZasob'] > 0)
+						? UI::h('a', [
+								'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
+								'class' => "btn btn-sm btn-link",
+								'title' => "Struktura tabeli w drzewie zasobów"
+							], "Zasoby")
+						: ''
+					),
+					( ($item['idZasob'] > 0)
+						? UI::h('a', [
+								'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
+								'class' => "btn btn-sm btn-link",
+								'title' => "Procesy dla aktualnie przeglądanej tabeli"
+							], "Procesy")
+						: ''
+					),
+					UI::h('a', [
+						'href' => Router::getRoute('Storage')->getLink('objectReinstall', ['namespace' => $item['namespace']]),
+						'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
+						'title' => "Zainstaluje ponownie obiekt"
+					], "reinstall object"),
+					UI::h('a', [
+						'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
+						'class' => "btn btn-sm btn-link",
+						'title' => "Uprawnienia - analiza użycia komórek w procesach"
+					], "Uprawnienia (analiza użycia)"),
+					UI::hButtonPost("(podgląd z relacjami)", [
+						'data' => [
+							'_postTask' => 'preview'
+						],
+						'class' => 'btn btn-sm btn-link', 'style' => "font-style:italic",
+						'title' => "Podgląd kilku ostatnich obiektów wraz z relacjami"
+					]),
+				])
+			]);
+
+			$thisGetLink = [Router::getRoute('Storage'), 'getLink'];
+			{ // not installed ref
+				$refFields = array_filter($item['field'], function ($field) {
+					return 'ref:' === substr($field['xsdType'], 0, 4);
+				});
+				UI::table([
+					'caption' => UI::h('span', [], "Obiekty powiązane (TODO backRef)"),
+					'rows' => array_map(function ($field) use ($thisGetLink) {
+						$refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
+						$isInstalled = (1 == DB::getPDO()->fetchValue("
+							select t.isObjectActive
+							from `CRM_#CACHE_ACL_OBJECT` t
+							where t.`namespace` = '{$refNamespace}'
+						"));
+						$refSource = null;
+						if ($isInstalled) {
+							try {
+								$refTable = ACL::getRefTable($field['objectNamespace'], $field['fieldNamespace']);
+								DBG::log($refTable, 'array', "getRefTable('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
+								$refSource = ACL::getRefSource($field['objectNamespace'], $field['fieldNamespace']);
+								DBG::log($refSource, 'array', "ACL::getRefSource('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
+							} catch (Exception $e) {
+								DBG::log($e);
+							}
+						}
+						return [
+							'fieldName' => $field['fieldNamespace'],
+							// 'xsdType' => $field['xsdType'], // always === "ref:{$field['fieldNamespace']}"
+							'ref object' => UI::h('a', [
+								'class' => "btn btn-xs btn-link",
+								'href' => $thisGetLink('objectStruct', [ 'namespace' => $refNamespace ])
+							], "objectStruct ({$refNamespace})"),
+							'ref source' => UI::h('div', [],
+								(null === $refSource)
+								? [ "ref object not installed" ] // TODO: link to install? is table struct
+								: [
+										// UI::hButtonAjax("Tabela ref", "setFieldRefConfig", [
+										// 	'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
+										// 	'href' => $thisGetLink('setFieldRefConfig'),
+										// 	'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'table' ]
+										// ]),
+										// UI::hButtonAjax("Widok (cache)", "setFieldRefConfig", [
+										// 	'title' => "Według flat_relation_cache",
+										// 	'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
+										// 	'href' => $thisGetLink('setFieldRefConfig'),
+										// 	'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'view' ]
+										// ]),
+										UI::hButtonPost("Tabela ref", [
+											'title' => "Według wygenerowanej tabeli REF",
+											'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
+											// 'href' => $thisGetLink('setFieldRefConfig'),
+											'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'table' ]
+										]),
+										UI::hButtonPost("Widok (cache)", [
+											'title' => "Według flat_relation_cache",
+											'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
+											// 'href' => $thisGetLink('setFieldRefConfig'),
+											'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'view' ]
+										]),
+									]
+							),
+							'@class' => ($isInstalled) ? "success" : "danger",
+						]; // TODO: link to install object
+					}, $refFields)
+				]);
+			}
+			UI::table([
+				'caption' => UI::h('span', [], [
+					UI::h('span', [ 'style' => "margin-right:6px;color:#000" ], "Struktura obiektu '{$item['namespace']}'"),
+				]),
+				'rows' => array_map(function ($field) use ($item, $thisGetLink) {
+					$tblItem = []; foreach ($field as $k => $v) $tblItem[$k] = $v;
+					$tblItem['namespace'] = UI::h('span', [], [
+						UI::h('span', ['style' => "color:#aaa"], substr($field['namespace'], 0, strlen($field['objectNamespace']) + 1)),
+						UI::h('span', ['style' => "color:#000"], substr($field['namespace'], strlen($field['objectNamespace']) + 1)),
+					]);
+					$tblItem['idZasob'] = ($field['idZasob'] > 0)
+						? $field['idZasob']
+						: (
+								($item['idZasob'] > 0)
+								? UI::hButtonAjax("+ do zasobów", 'addFieldToZasobyAjax', [
+										'class' => "btn btn-xs btn-primary",
+										'href' => $thisGetLink('addFieldToZasobyAjax'),
+										'data' => [
+											'namespace' => $item['namespace'],
+											'fieldNamespace' => $field['namespace'],
+										]
+									])
+								: UI::h('span', ['title'=>"Brak Nr zasobu dla obiektu", 'class'=>"btn btn-xs btn-danger"], "Brak nr zasobu obiektu")
+							)
+					;
+					unset($tblItem['objectNamespace']);
+					unset($tblItem['fieldNamespace']);
+					return $tblItem;
+				}, $item['field'])
+			]);
+			UI::hButtonAjaxOnResponse('addFieldToZasobyAjax', /* payload, n */ "
+				if (!payload.type) return false
+				if (payload.body && payload.body.id && payload.body.id > 0) { // if ('success' == payload.type) {
+					n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
+				}
+				jQuery.notify(payload.msg, payload.type)
+			");
+			UI::hButtonAjaxOnResponse('addAclObjectToZasobyAjax', /* payload, n */ "
+				if (!payload.type) return false
+				if ('success' === payload.type || 'info' === payload.type) {
+					if (payload.body && payload.body.id && payload.body.id > 0) {
+						n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
+					} else {
+						console.log('TODO: addAclObjectToZasobyAjax unknown response', payload);
+					}
+					window.location.reload()
+				}
+			");
+			UI::hButtonAjaxOnResponse('activateObjectAjax', /* payload, n */ "
+				jQuery.notify(payload.msg, payload.type)
+				if (!payload.type) return false
+				if ('success' === payload.type || 'info' === payload.type) {
+					if (payload.body && payload.body.isObjectActive && payload.body.isObjectActive > 0) {
+						n.parentNode.replaceChild(document.createTextNode('Active'), n)
+					} else {
+						console.log('TODO: activateObjectAjax unknown response', payload);
+					}
+				}
+			");
+			if ($item['isObjectActive']) {
+				echo UI::hButtonAjax("Dodaj podstawowy proces dla obiektu '{$item['namespace']}' - read only (TODO)", 'addObjectBaseProcesAjax', [
+					'class' => "btn btn-xs btn-default",
+					'href' => Router::getRoute('Storage')->getLink('addObjectBaseProcesAjax'),
+					'data' => [ 'namespace' => $item['namespace'] ]
+				]);
+				UI::hButtonAjaxOnResponse('addObjectBaseProcesAjax', /* payload, n */ "
+					jQuery.notify(payload.msg, payload.type)
+				");
+			}
+			DBG::nicePrint($item, '$item');
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+			DBG::log($e);
+		}
+		UI::endTag('div'); // .container-fluid
+		UI::dol();
+	}
+
+	public function tableStructAction() {
+		UI::gora();
+		UI::menu();
+		// Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
+		try {
+			$idStorage = V::get('idStorage', 0, $_REQUEST, 'int');
+			if (empty($idStorage)) throw new Exception("Missing id storage");
+			$storageList = Router::getRoute('Storage')->getStorageList();
+			if (empty($storageList)) throw new Exception("No storage defined");
+			if (!array_key_exists($idStorage, $storageList)) throw new Exception("Storage not exists");
+			$tblName = V::get('table', '', $_REQUEST, 'word');
+			if (empty($tblName)) throw new Exception("No table name");
+
+			$storagePdo = DB::getStorage($idStorage);
+			$tblStruct = $storagePdo->getTableStruct($tblName);
+
+			$idTable = Router::getRoute('Storage')->fetchTableId($idStorage, $tblName);
+			if ($idTable <= 0) {
+				UI::alert('warning', "Zasob tabela '{$tblName}' nie istnieje");// TODO: add p5UI btn
+				DBG::table("tblStruct", $tblStruct, __CLASS__, __FUNCTION__, __LINE__);
+				throw new Exception("Zasob tabela '{$tblName}' nie istnieje");
+			}
+
+			$cellZasobList = array();
+			foreach (DB::getPDO()->fetchAllByKey("
+					select z.ID, z.`DESC`, z.`TYPE` as ZASOB_TYPE, z.A_STATUS
+					from CRM_LISTA_ZASOBOW z
+					where z.PARENT_ID = '{$idTable}'
+				", $key = 'DESC') as $ind => $row) {
+				$cellZasobList[strtolower($ind)] = $row;
+			}
+
+			$emptyItem = array();
+			$emptyItem['name'] = '';
+			$emptyItem['id_zasob'] = '';
+			$emptyItem['zasob_type'] = '';
+			$emptyItem['uwagi'] = '';
+
+			$emptyItem['type'] = '';
+			$emptyItem['is_nullable'] = '';
+			$emptyItem['default_value'] = '';
+			$emptyItem['default_is_null'] = '';
+			$emptyItem['max_length'] = '';
+			$emptyItem['num_precision'] = '';
+			$emptyItem['num_scale'] = '';
+			$emptyItem['char_encoding'] = '';
+			$emptyItem['char_collation'] = '';
+			$emptyItem['extra'] = '';
+			$emptyItem['raw_storage_type'] = '';
+
+			$tableList = array();
+			foreach ($tblStruct as $row) {
+				$cellName = $row['name'];
+				$tblItem = V::cloneArray($emptyItem);
+				$tblItem['name'] = $cellName;
+				foreach ($row as $fldName => $fldVal) {
+					if (array_key_exists($fldName, $tblItem)) $tblItem[$fldName] = $fldVal;
+				}
+				$tblItem['uwagi'] = '';
+				$lowerCellName = strtolower($cellName);
+				$tblZasob = V::get($lowerCellName, '', $cellZasobList);
+				if ($tblZasob) {
+					$cellZasobList[$lowerCellName]['_checked'] = true;
+					$tblItem['id_zasob'] = $tblZasob['ID'];
+					$tblItem['zasob_type'] = $tblZasob['ZASOB_TYPE'];
+				} else {
+					$tblItem['uwagi'] .= '!Zasob';//'TODO: ADD ZASOB';
+					$ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addCellToZasoby', [ 'idStorage' => $idStorage, 'tblName' => $tblName, 'cellName' => $cellName]);
+					$onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addCellToZasoby', { href: '{$ajaxAddZasobLink}' })";
+					$tblItem['id_zasob'] = '<a onclick="'.$onClick.'" class="btn btn-xs btn-primary" href="#">TODO: ADD ZASOB</a>';
+				}
+				$tableList[] = $tblItem;
+			}
+			foreach ($cellZasobList as $cellName => $row) {
+				if ('URL_ACTION' == $row['ZASOB_TYPE']) continue;
+				if (!$row['_checked']) {
+					$tblItem = V::cloneArray($emptyItem);
+					$tblItem['name'] = $cellName;
+					$tblItem['id_zasob'] = $row['ID'];
+					$tblItem['zasob_type'] = $row['ZASOB_TYPE'];
+					$tblItem['uwagi'] = '!DB';//'TODO: nie istnieje w bazie danych';
+					$tableList[] = $tblItem;
+				}
+			}
+			usort($tableList, function($rowA, $rowB) {
+				$a = $rowA['name']; $b = $rowB['name'];
+				if ('ID' == $a) return -1;
+				if ('ID' == $b) return 1;
+				if ($a == $b) return 0;
+				$a1 = substr($a, 0, 1); $b1 = substr($b, 0, 1);
+				if (('_' == $a1 || '_' == $b1) && $a1 != $b1) {
+					return ($a1 < $b1) ? 1 : -1;
+				}
+				return ($a < $b) ? -1 : 1;
+			});
+			UI::table([
+				'caption' => UI::h('span', [], [
+					"Komórki [{$idTable}] ",
+					UI::h('a', [
+						'href' => "index.php?_route=ViewTableAjax&namespace=default_db/{$tblName}",
+						'class' => "btn btn-md btn-link"
+					], "Przeglądaj tabelę"),
+					UI::h('a', [
+						'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$idTable}&filtr_ids=%2B&filtr_ob=%2B",
+						'class' => "btn btn-md btn-link",
+						'title' => "Struktura aktualnie przeglądanej tabeli"
+					], "Zasoby"),
+					UI::h('a', [
+						'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$idTable}",
+						'class' => "btn btn-md btn-link",
+						'title' => "Procesy dla aktualnie przeglądanej tabeli"
+					], "Procesy"),
+					UI::h('a', [
+						'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => "default_db/{$tblName}" ]),
+						'class' => "btn btn-md btn-link",
+						'title' => "Uprawnienia - analiza użycia komórek w procesach"
+					], "Uprawnienia (analiza użycia)"),
+				]),
+				'cols' => array_keys($emptyItem),
+				'rows' => $tableList
+			]);
+			echo UI::h('script', [], "
+				jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:click', function(e, n, payload) {
+					console.log('event p5UIBtnAjax:Storage:addCellToZasoby:click', n, payload);
+				});
+				jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', function(e, n, payload) {
+					console.log('event p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', n, payload);
+					if ('success' == payload.type && payload.body && payload.body.id > 0) {
+						var cellUwagiJQNode = jQuery(n).parents('td').next('td');
+						cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
+						jQuery(n).parents('td').text(payload.body.id);
+						jQuery(n).remove();
+					}
+					jQuery.notify(payload.msg, payload.type);
+				});
+			");
+			$ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addGeomEtykietaCells', [ 'idStorage' => $idStorage, 'tblName' => $tblName]);
+			$onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addGeomEtykietaCells', { href: '{$ajaxAddZasobLink}' })";
+			UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj komórki etykiet", true);
+			echo "<i>(<code>`etykieta_x`</code>, <code>`etykieta_y`</code>, <code>`etykieta_obrot`</code>)</i>";
+			echo UI::h('script', [], "
+				jQuery(document).on('p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', function(e, n, payload) {
+					console.log('event p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', n, payload);
+					if ('success' == payload.type && payload.body && payload.body.id > 0) {
+						var cellUwagiJQNode = jQuery(n).parents('td').next('td');
+						cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
+						jQuery(n).parents('td').text(payload.body.id);
+						jQuery(n).remove();
+					}
+					jQuery.notify(payload.msg, payload.type);
+				});
+			");
+
+
+			$tableActions = array_filter($cellZasobList, function ($row) {
+				return ('URL_ACTION' == $row['ZASOB_TYPE']);
+			});
+			UI::table([
+				'caption' => "tableActions",
+				// 'cols' => array_keys($emptyItem),
+				'rows' => array_map(function ($item) {
+					$sqlIdAction = DB::getPDO()->quote($item['ID'], PDO::PARAM_INT);
+					$args = DB::getPDO()->fetchAll("
+						select z.`DESC`
+								, a.ID as ALIAS_ID, a.`DESC` as ALIAS_DESC, a.OPIS as ALIAS_OPIS
+						from CRM_LISTA_ZASOBOW z
+							left join CRM_LISTA_ZASOBOW a on(a.ID = z.ALIAS_ID)
+						where z.PARENT_ID = {$sqlIdAction}
+							and z.`TYPE` = 'PARAM_IN'
+					");
+					$definitionArgs = DB::getPDO()->fetchAll("
+						select p.ID, p.`DESC`
+						from CRM_LISTA_ZASOBOW z
+							join CRM_LISTA_ZASOBOW d on(d.ID = z.ALIAS_ID)
+							left join CRM_LISTA_ZASOBOW p on(p.PARENT_ID = d.ID)
+						where z.ID = {$sqlIdAction}
+							and p.`TYPE` = 'PARAM_IN'
+					");
+					$flatDefinitionArgs = implode(";", array_map(function ($arg) {
+						return "{$arg['ID']}={$arg['DESC']}";
+					}, $definitionArgs));
+					return [
+						'label' => DB::getPDO()->fetchValue(" select z.OPIS from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdAction} ") . " " .
+							UI::h('i', [
+								'class' => "glyphicon glyphicon-pencil",
+								'style' => "cursor:pointer",
+								'onClick' => "return Storage__tableStruct__editActionLabel(this, {$sqlIdAction})"], ''),
+						'args' => implode("<br>&", array_map(function ($item) {
+							return (NULL === $item['ALIAS_ID'])
+								? $item['DESC']
+								: "{$item['DESC']}=" . '{$row["' . $item['ALIAS_DESC'] . '"]}';// TODO: add rmParam btn
+						}, $args)) . " " .
+							UI::h('i', [
+								'class' => "glyphicon glyphicon-plus-sign",
+								'style' => "cursor:pointer",
+								'title' => "Dodaj PARAM_IN",
+								'onClick' => "return Storage__tableStruct__addParamAction(this, {$sqlIdAction}, '{$flatDefinitionArgs}')"], ''),
+						// 'args_info' => '<pre>' . var_export($args, true) . '</pre>',
+						'ID' => $item['ID'],
+						'DESC' => $item['DESC'],
+						'A_STATUS' => $item['A_STATUS'],
+						'definition args' => implode("", array_map(function ($item) {
+							return '<div style="white-space:nowrap">' . "[{$item['ID']}] {$item['DESC']}" . '</div>';
+						}, $definitionArgs)),
+					];
+				}, $tableActions)
+			]);
+			echo UI::h('button', [
+				'onClick'=>"Storage__tableStruct__addAction()",
+				'class'=>"btn btn-xs btn-default"
+			], "Dodaj Akcję");
+			echo UI::h('link', ['rel'=>"stylesheet", 'type'=>"text/css", 'href'=>"static/sweetalert2.min.css"]);
+			echo UI::h('script', ['src'=>"static/sweetalert2.min.js"]);
+			echo UI::h('style', [], "
+				.swal2-radio.p5-swal-radio-as-list { text-align:left }
+				.swal2-radio.p5-swal-radio-as-list > label { display:block; margin-left:20px }
+			");
+			UI::inlineJS(__FILE__ . '.tableActions.js', [
+				'ID_STORAGE' => $idStorage,
+				'TABLE_NAME' => $tblName,
+				'FETCH_URL' => Router::getRoute('Storage')->getLink('fetchActionListAjax'),
+				'ADD_ACTION_URL' => Router::getRoute('Storage')->getLink('addActionAjax')
+			]);
+			echo '<hr>';
+
+			$ajaxAddBaseProcesLink = Router::getRoute('Storage')->getLink('addTableBaseProces', [ 'idStorage' => $idStorage, 'tblName' => $tblName ]);
+			$onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addTableBaseProces', { href: '{$ajaxAddBaseProcesLink}' })";
+			UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj podstawowy proces dla tabeli '{$tblName}' - read only", true);
+			echo UI::h('script', [], "
+				jQuery(document).on('p5UIBtnAjax:Storage:addTableBaseProces:ajaxLoaded', function(e, n, payload) {
+					jQuery.notify(payload.msg, payload.type);
+				});
+			");
+		} catch (Exception $e) {
+			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
+		}
+		UI::dol();
+	}
+
+}

+ 2 - 2
SE/se-lib/Route/Storage/AclUsage.php

@@ -40,8 +40,8 @@ class Route_Storage_AclUsage extends RouteBase {
 					UI::h('p', [], [
 						"struktura: ",
 						($acl instanceof AntAclBase)
-						? UI::h('a', [ 'href' => Router::getRoute('Storage')->getLink('objectStruct', [ 'idStorage' => $acl->getDatabaseID(), 'namespace' => $acl->getNamespace() ]) ], "struktura obiektu (AntAcl)")
-						: UI::h('a', [ 'href' => Router::getRoute('Storage')->getLink('tableStruct', [ 'idStorage' => $acl->getDatabaseID(), 'table' => $acl->getRootTableName() ]) ], "struktura tabeli (TableAcl)")
+						? UI::h('a', [ 'href' => Router::getRoute('Storage_AclStruct')->getLink('', [ 'idStorage' => $acl->getDatabaseID(), 'namespace' => $acl->getNamespace() ]) ], "struktura obiektu (AntAcl)")
+						: UI::h('a', [ 'href' => Router::getRoute('Storage_AclStruct')->getLink('tableStruct', [ 'idStorage' => $acl->getDatabaseID(), 'table' => $acl->getRootTableName() ]) ], "struktura tabeli (TableAcl)")
 					]),
 				])
 			]);