Parcourir la source

removed ViewObject - mved test instances code to ViewTableAjax &DBG_INST=1

Piotr Labudda il y a 8 ans
Parent
commit
dac8d59704

+ 0 - 1
SE/se-lib/Route/Storage.php

@@ -228,7 +228,6 @@ class Route_Storage extends RouteBase {
 								UI::h('a', [ 'href' => $item['reinstallLink'] ], "reinstall"),
 								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"),
 								// 'xsd' => UI::h('a', [ 'href' => Router::getRoute('Storage_TestXsd')->getLink('', [ 'idStorage' => $idStorage ]) ], "xsd"),
 								UI::h('a', [ 'href' => "wfs-data.php/default_db/?SERVICE=WFS&VERSION=1.0.0&SRSNAME=EPSG:3003&REQUEST=DescribeFeatureType&TYPENAME={$typeName}" ], "wfs DescribeFeatureType"),
 								UI::h('a', [ 'href' => "wfs-data.php/default_db/?SERVICE=WFS&VERSION=1.0.0&SRSNAME=EPSG:3003&REQUEST=DescribeFeatureTypeAdvanced&TYPENAME={$typeName}" ], "wfs DescribeFeatureTypeAdvanced"),

+ 0 - 1124
SE/se-lib/Route/ViewObject.php

@@ -1,1124 +0,0 @@
-<?php
-
-Lib::loadClass('RouteBase');
-Lib::loadClass('ProcesHelper');
-Lib::loadClass('TableAjax');
-// Lib::loadClass('Request');
-Lib::loadClass('Response');
-Lib::loadClass('UI');
-Lib::loadClass('Api_WfsNs');
-Lib::loadClass('Core_AclHelper');
-Lib::loadClass('Route_UrlAction');
-Lib::loadClass('Router');
-Lib::loadClass('Typespecial');
-Lib::loadClass('UserProfile');
-Lib::loadClass('P5');
-Lib::loadClass('Route_ViewTableAjax');
-
-class Route_ViewObject extends Route_ViewTableAjax {
-
-	public function getTableAjaxWidget($acl, $backRefFilter = []) {
-		$syncUrl = Request::getPathUri() . 'index.php?_route=ViewObject&namespace=' . $acl->getNamespace();
-		$tbl = new TableAjax($acl);
-		// $tbl->showProcesInitFiltr = true; // TODO: activate when ready
-		$tblLabel = $acl->getNamespace();
-		if ('default_db' == $acl->getSourceName()) {
-			$tblLabel = array();
-			DBG::nicePrint($acl->getID(), '$acl->getID()');
-			$zasobObj = ProcesHelper::getZasobTableInfo($acl->getID());
-			DBG::nicePrint($zasobObj, '$zasobObj');
-			$sqlId = $acl->getID();
-			if (!$sqlId) throw new Exception("Missing zasob id!");
-			$zasobItem = DB::getPDO()->fetchFirst("
-				select z.ID, z.`DESC`, z.DESC_PL, z.OPIS
-				from CRM_LISTA_ZASOBOW z
-				where z.ID = {$sqlId}
-					and z.`TYPE` = 'TABELA'
-			");
-			DBG::nicePrint($zasobItem, '$zasobItem');
-			// if (!$zasobObj) throw new Exception("Zasob TABELA ID=" . $acl->getID() . " nie istnieje");
-			// if (!empty($zasobObj->DESC_PL)) $tblLabel []= $zasobObj->DESC_PL;
-			// if (!empty($zasobObj->OPIS))    $tblLabel []= $zasobObj->OPIS;
-			if (!$zasobItem) throw new Exception("Zasob TABELA ID=" . $acl->getID() . " nie istnieje");
-			if (!empty($zasobItem['DESC_PL'])) $tblLabel []= $zasobItem['DESC_PL'];
-			if (!empty($zasobItem['OPIS']))    $tblLabel []= $zasobItem['OPIS'];
-			$tblLabel = implode(" - ", $tblLabel);
-		}
-		$tbl->setSyncUrl($syncUrl);
-		$tbl->setLabel($tblLabel);
-		$tbl->addRowFunction('edit');
-		$tbl->addRowFunction('hist');
-		$tbl->addRowFunction('files');
-		$tbl->addRowFunction('cp');
-		$tbl->addRowFunction('msgs');
-		return $tbl;
-	}
-
-	public function defaultAction() {
-		UI::gora();
-		UI::menu();
-		try {
-			$namespace = V::get('namespace', '', $_GET, 'word');
-			if (!$namespace) {
-				$typeName = V::get('typeName', '', $_GET, 'word');
-				if (!$typeName) throw new Exception("Wrong param typeName");
-				$namespace = Api_WfsNs::getBaseWfsUri() . '/' . str_replace(':', '/', $typeName);
-			}
-			$acl = P5::getAclByNamespace($namespace, $forceTblAclInit = ('1' == V::get('_force', '', $_GET)));
-
-			$forceFilterInit = array();
-			$filterInit = new stdClass();
-			$filterInit->currSortCol = $acl->getPrimaryKeyField();
-			$filterInit->currSortFlip = 'desc';
-			foreach ($_GET as $k => $v) {
-				if (strlen($k) > 3 && substr($k, 0, 2) == 'f_' && !empty($v)) {// filter prefix
-					$filterInit->$k = $v;
-				}
-				else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_' && !empty($v)) {// special filter prefix
-					$filterInit->$k = $v;
-				}
-				else if (strlen($k) > 4 && substr($k, 0, 3) == 'ff_' && !empty($v)) {// force filter prefix
-					$fldName = substr($k, 3);
-					$forceFilterInit[$fldName] = $v;
-				}
-			}
-
-			$tbl = $this->getTableAjaxWidget($acl);
-			$tbl->setFilterInit($filterInit);
-			if (!empty($forceFilterInit)) $tbl->setForceFilterInit($forceFilterInit);
-			if (V::get('DBG_INST', '', $_GET)) { // TODO: TEST namespace
-				$siblings = ACL::getNamespaceSiblings($namespace);
-				DBG::nicePrint($siblings, '$siblings');
-				$filtrInstance = V::get('f_instance', [], $_POST, 'array');
-				DBG::nicePrint($filtrInstance, '$filtrInstance');
-				$sibling = 'default_db/CRM_PROCES/PROCES_INIT'; DBG::nicePrint(array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'YES'], ('YES' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : []), "merge {$sibling} YES");
-				$sibling = 'default_db/CRM_PROCES/PROCES_INIT'; DBG::nicePrint(array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'NO'], ('NO' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : []), "merge {$sibling} NO");
-
-				$_ = array(UI, 'h');
-				echo $_('form', ['method' => "POST", 'style' => "width:600px; border:1px solid #ddd; border-radius:2px"], [
-					$_('div', ['style' => "background-color:#ddd"], "Test Filtr instancji"),
-					$_('div', ['style' => "padding:8px"], array_map(function ($sibling) use ($filtrInstance, $_) {
-						return $_('div', [], [
-							$_('label', ['style' => "margin:0 8px"], [
-								$_('input', array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'YES'], ('YES' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : [])),
-								" TAK "
-							]),
-							$_('label', ['style' => "margin:0 8px"], [
-								$_('input', array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'NO'], ('NO' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : [])),
-								" NIE "
-							]),
-							$_('label', ['style' => "margin:0 8px"], [
-								$_('input', ['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'x']),
-								" pomiń "
-							]),
-							// $_('button', ['onClick'=>"this.form.f_instance['{$sibling}'].value = ''; return false"], "odznacz"),
-							$_('button', ['onClick'=>"console.log(this.form.elements['f_instance[{$sibling}]']); this.form.elements['f_instance[{$sibling}]'].value = 'x'; return false"], "odznacz"),
-							" - {$sibling}"
-						]);
-					}, $siblings)),
-					$_('div', [], [
-						$_('input', ['type'=>"hidden", 'name'=>'_route', 'value'=>"ViewObject"]),
-						$_('input', ['type'=>"hidden", 'name'=>'namespace', 'value'=>$namespace]),
-						$_('input', ['type'=>"submit", 'value'=>"Filtruj - TEST"]),
-					]),
-				]);
-				DBG::nicePrint($_POST, '$_POST');
-				{
-					$args = $_POST;
-					$fIsInstance = [];
-					$fIsNotInstance = [];
-					if (!empty($args['f_instance'])) {
-						foreach ($args['f_instance'] as $inst => $selected) {
-							if ('YES' === $selected) {
-								$fIsInstance[] = $inst;
-							} else if ('NO' === $selected) {
-								$fIsNotInstance[] = $inst;
-							}
-						}
-					}
-				}
-				$queryFeatures = $acl->buildQuery([
-					// TODO: 'propertyName' => "*,@instance",
-					'f_is_instance' => $fIsInstance,
-					'f_is_not_instance' => $fIsNotInstance,
-					'@instances' => '1',
-					'limit' => 10
-				]);
-				// $total = $queryFeatures->getTotal();
-				$items = $queryFeatures->getItems();
-
-				$rootNamespace = $acl->getRootNamespace();
-				DBG::nicePrint($rootNamespace, '$rootNamespace');
-				$jsRenderFunName = 'render_dropdown_instances_' . substr(md5(time()), 0, 6);
-				DBG::nicePrint($jsRenderFunName, '$jsRenderFunName');
-				UI::table([
-					'rows' => array_map(function($row) use ($namespace, $siblings, $rootNamespace, $jsRenderFunName) {
-						return [
-							'ID' => $row['ID'],
-							'DESC' => $row['DESC'],
-							'TYPE' => $row['TYPE'],
-							'Typ' => UI::h('div', ['class'=>"p5UI__dropdown-wrap"], [
-								UI::h('button', [
-									// 'onClick' => "p5UI__dropdown(event, this, 'left bottom')",
-									'onClick' => "p5UI__dropdown(event, this, 'left bottom', {$jsRenderFunName}({$row['ID']}))",
-									'class' => "btn btn-xs btn-default p5UI__dropdown-btn"
-								], [
-									UI::h('i', ['class' => "glyphicon glyphicon-tags", 'title' => "Ustaw typ danych (instancje)"]),
-								]),
-								UI::h('div', ['class' => "p5UI__dropdown-content"]
-									, array_merge(
-										[
-											UI::h('input', ['type' => "text", 'placeholder' => "Search..", 'class' => "p5UI__dropdown-input", 'onkeyup' => "p5_ViewObject_instances_filterInput(this)"], null),
-										]
-										, array_map(function ($sibling) use ($row, $namespace, $rootNamespace) {
-											return UI::h('div', ['label'=>$sibling, 'style'=>"padding:4px 0"], [
-												UI::h('button', array_merge(['class' => "btn btn-xs btn-default",
-													'style' => "margin:0 4px 0 0",
-													'title' => "Ustaw instancje '{$sibling}'",
-													'onClick' => "return p5_ViewObject_instance_set(this, '{$row['ID']}', '{$sibling}', 'yes')"],
-													(in_array($sibling, explode(',', $row['@instances']))) ? ['disabled' => "disabled"] : []
-												), "+"),
-												UI::h('button', ['class' => "btn btn-xs btn-default",
-													'style' => "margin:0 4px 0 0",
-													'title' => "Usuń instancje '{$sibling}'",
-													'onClick' => "return p5_ViewObject_instance_set(this, '{$row['ID']}', '{$sibling}', 'no')"], "-"),
-												UI::h('span', [], substr($sibling, strlen($rootNamespace) + 1)),
-											]);
-										}, $siblings)
-									)
-								)
-							]),
-							'instancesList' => implode(', ', ACL::getFeatureNamespaces($namespace, $row['ID'])),
-						];
-					}, $items)
-				]);
-				echo UI::h('style', ['type' => "text/css"], "
-					.p5UI__dropdown-content { min-width:400px; border:1px solid #ccc; background-color: #fff; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2) }
-					.p5UI__dropdown-content .p5UI__dropdown-item { display:block; color:#000; padding:4px; text-decoration:none }
-					.p5UI__dropdown-content .p5UI__dropdown-item:hover { background-color:#ebebeb }
-				");
-				echo UI::h('script', ['src'=>"static/vendor.js", 'type'=>"text/javascript"]);
-				$jsArgs = [
-					'SET_INSTANCE_URL' => $this->getLink('setInstanceAjax'),
-					'NAMESPACE' => $namespace,
-					'DBG' => DBG::isActive() ? 'true' : 'false',
-				];
-
-				UI::inlineJS(__FILE__ . '.instancesDropdown.js', [
-					'JS_GLOBAL_FUNCTION_NAME' => $jsRenderFunName,
-					'NAMESPACE' => $namespace,
-					'SET_INSTANCE_URL' => $this->getLink('setInstanceAjax'),
-					'DBG' => DBG::isActive() ? 1 : 0,
-					'INITIAL_DROPDOWN_DATA' => [
-						// 'allowed_instances' => $siblings,
-						'allowed_instances' => array_map(function ($sibling) use ($rootNamespace) {
-							return [
-								'namespace' => $sibling,
-								'label' => substr($sibling, strlen($rootNamespace) + 1)
-							];
-						}, $siblings),
-						'items' => array_map(function($row) use ($namespace, $siblings, $rootNamespace, $jsRenderFunName) {
-							return [
-								'pk' => $row['ID'], // TODO: $primaryKeyField
-								'instances' => explode(',', $row['@instances']),
-							];
-						}, $items)
-					],
-				]);
-				echo UI::h('script', [], "
-					var SET_INSTANCE_URL = '{$jsArgs['SET_INSTANCE_URL']}'
-					var NAMESPACE = '{$jsArgs['NAMESPACE']}'
-					function p5_ViewObject_instance_set(n, pk, sibling, toConnect) {
-						console.log('p5_ViewObject_instance_set pk('+pk+'), sibling('+sibling+'), toConnect('+toConnect+'), n', n);
-						window.fetch(SET_INSTANCE_URL, {
-							method: 'POST',
-							headers: { 'Content-Type': 'application/json' },
-							credentials: 'same-origin',
-							body: JSON.stringify({
-								namespace: NAMESPACE,
-								primaryKey: pk,
-								instance: sibling,
-								toConnect: toConnect,
-							})
-						}).then(function (response) {
-							return response.json()
-						}).then(function (response) {
-							p5UI__notifyAjaxCallback(response)
-							console.log(response) // TODO: render list
-						})
-					}
-				");
-				echo UI::h('script', [], "
-					function p5_ViewObject_instances_filterInput(n) {
-						var input, filter, ul, li, a, i, div;
-						input = n // .id-myInput
-						filter = input.value.toUpperCase()
-						div = n.parentNode // .id-myDropdown
-						a = div.getElementsByTagName('div')
-						for (i = 0; i < a.length; i++) {
-							if (a[i].getAttribute('label') && a[i].getAttribute('label').toUpperCase().indexOf(filter) > -1) {
-								a[i].style.display = 'block'
-							} else {
-								a[i].style.display = 'none'
-							}
-						}
-					}
-				");
-				echo '<hr style="margin-top:300px">';
-				exit;
-			}
-			echo $tbl->render();
-
-			if (DBG::isActive() && V::get('DBG_ACL', '', $_GET)) {// test load perms
-				Lib::loadClass('DebugExecutionTime');
-				$dbgExecTime = new DebugExecutionTime();
-				$dbgExecTime->activate();
-				$dbgExecTime->log('start');
-				UI::startContainer(['style'=>'border:1px solid red']);
-				UI::tag('p', null, "TEST - load perms from db");
-				$idTable = $acl->getID();
-				UI::tag('p', null, "DBG idTable({$idTable})");
-				if ($idTable > 0) {
-					$dbgExecTime->log('before sql');
-					$aclTableRows = DB::getPDO()->fetchAll("select * from `CRM_PROCES_idx_TABLE_TO_PROCES_PERMS_VIEW` where ID_TABLE = {$idTable}");
-					$dbgExecTime->log('after sql', ['sql']);
-					UI::table(['caption' => "from CRM_PROCES_idx_TABLE_TO_PROCES_PERMS_VIEW", 'rows' => $aclTableRows]);
-					$csvIdProces = array();
-					foreach ($aclTableRows as $row) {
-						if (!in_array($row['ID_PROCES'], $csvIdProces)) $csvIdProces[] = $row['ID_PROCES'];
-					}
-				}
-
-				$tableName = $acl->getName();
-				$databaseName = DB::getPDO()->getDatabaseName();
-				UI::table([
-					'caption' => "Cell to process",
-					'rows' => array_map(
-						function ($row) use ($aclTableRows, $idTable) {
-							$row['proces'] = array();
-							$row['id_zasob'] = 0;
-							$row['PERM_R'] = 0;
-							$row['PERM_W'] = 0;
-							$row['PERM_X'] = 0;
-							$row['PERM_C'] = 0;
-							$row['PERM_S'] = 0;
-							$row['PERM_O'] = 0;
-							$row['PERM_V'] = 0;
-							$row['PERM_E'] = 0;
-							foreach ($aclTableRows as $aclInfo) {
-								if (strtolower($aclInfo['CELL_NAME']) == strtolower($row['COLUMN_NAME'])) {
-									$row['proces'][] = $aclInfo['ID_PROCES'];
-									$row['id_zasob'] = $aclInfo['ID_CELL'];
-									$row['PERM_R'] += $aclInfo['PERM_R'];
-									$row['PERM_W'] += $aclInfo['PERM_W'];
-									$row['PERM_X'] += $aclInfo['PERM_X'];
-									$row['PERM_C'] += $aclInfo['PERM_C'];
-									$row['PERM_S'] += $aclInfo['PERM_S'];
-									$row['PERM_O'] += $aclInfo['PERM_O'];
-									$row['PERM_V'] += $aclInfo['PERM_V'];
-									$row['PERM_E'] += $aclInfo['PERM_E'];
-								}
-							}
-							$row['proces'] = (empty($row['proces']))
-								? "<i style=\"color:red\">Brak</i>"
-								: implode(", ", $row['proces']);
-							if (!$row['id_zasob']) $row['id_zasob'] = DB::getPDO()->fetchValue("select ID from CRM_LISTA_ZASOBOW where `DESC` = '{$row['COLUMN_NAME']}' and PARENT_ID = {$idTable} limit 1");
-							return $row;
-						}, DB::getPDO()->fetchAll("
-							select t.TABLE_NAME, t.COLUMN_NAME, t.DATA_TYPE, t.COLUMN_TYPE
-							from `information_schema`.`COLUMNS` t
-							where t.TABLE_SCHEMA = '{$databaseName}'
-								and t.TABLE_NAME like '{$tableName}'
-						")
-					)
-				]);
-
-				if (!empty($csvIdProces)) {
-					$csvIdProces = implode(",", $csvIdProces);
-					UI::tag('p', null, "DBG csvIdProces({$csvIdProces})");
-					$userLogin = User::getLogin();
-					$dbgExecTime->log('before sql');
-					$rows = DB::getPDO()->fetchAll("select ID_PROCES from `CRM_PROCES_idx_USER_to_PROCES_VIEW` where ADM_ACCOUNT = '{$userLogin}' and ID_PROCES in({$csvIdProces}) group by ID_PROCES");
-					$dbgExecTime->log('after sql', ['sql']);
-					UI::table(['caption' => "from CRM_PROCES_idx_USER_to_PROCES_VIEW", 'rows' => $rows]);
-					$userIdProces = array(); foreach ($rows as $row) $userIdProces[] = $row['ID_PROCES'];
-					$userTablePerms = array();
-					foreach ($aclTableRows as $row) {
-						if (!in_array($row['ID_PROCES'], $userIdProces)) continue;
-						if (array_key_exists($row['CELL_NAME'], $userTablePerms)) {
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_R' ] += $row['PERM_R'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_W' ] += $row['PERM_W'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_X' ] += $row['PERM_X'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_C' ] += $row['PERM_C'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_S' ] += $row['PERM_S'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_O' ] += $row['PERM_O'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_V' ] += $row['PERM_V'];
-							$userTablePerms[ $row['CELL_NAME'] ][ 'PERM_E' ] += $row['PERM_E'];
-						} else {
-							$userTablePerms[ $row['CELL_NAME'] ] = $row;
-							unset($userTablePerms[ $row['CELL_NAME'] ][ 'TABLE_DESCRIPTION' ]);
-							unset($userTablePerms[ $row['CELL_NAME'] ][ 'ID_PROCES' ]);
-							unset($userTablePerms[ $row['CELL_NAME'] ][ 'FORM_TREAT' ]);
-						}
-					}
-					UI::table(['caption' => "\$userTablePerms", 'rows' => $userTablePerms]);
-				} else UI::alert('warning', "brak \$csvIdProces");
-				$dbgExecTime->printDebug();
-				UI::endContainer();
-			}
-		} catch (Exception $e) {
-			UI::startContainer();
-			UI::alert('danger', "<strong>Wystąpiły błędy!</strong> " . $e->getMessage());
-			UI::endContainer();
-			DBG::log($e);
-		}
-		UI::dol();
-	}
-
-	public function setInstanceAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'setInstanceAjax'), $args = 'JSON_FROM_REQUEST_BODY');
-	}
-	public function setInstanceAjax($args) {
-		// namespace => default_db/CRM_PROCES/PROCES_INIT
-		// primaryKey => 6
-		// instance => default_db/CRM_PROCES/PROCES_TREE
-		// toConnect => yes
-		if (empty($args['namespace'])) throw new Exception("Missing namespace");
-		if (empty($args['primaryKey'])) throw new Exception("Missing primaryKey");
-		if (empty($args['instance'])) throw new Exception("Missing instance");
-		if (empty($args['toConnect'])) throw new Exception("Missing toConnect");
-		if (!in_array($args['toConnect'], ['yes', 'no'])) throw new Exception("Wrong param toConnect");
-		$idInstance = ACL::getInstanceId($args['instance']);
-		$instanceTable = ACL::getInstanceTable($args['namespace']);
-		switch ($args['toConnect']) {
-			case 'yes': {
-				// TODO: _HIST info - waiting
-				$ret = DB::getPDO()->execSql("
-					insert into `{$instanceTable}` (`pk`, `idInstance`)
-						values ( :pk , :idInstance )
-				", [
-					'pk' => $args['primaryKey'],
-					'idInstance' => $idInstance,
-				]);
-				// TODO: _HIST info - mark as done
-			} break;
-			case 'no': {
-				// TODO: _HIST info - waiting
-				$ret = DB::getPDO()->execSql("
-					delete from `{$instanceTable}`
-					where `pk` = :pk
-						and `idInstance` = :idInstance
-				", [
-					'pk' => $args['primaryKey'],
-					'idInstance' => $idInstance,
-				]);
-				// TODO: _HIST info - mark as done
-			} break;
-		}
-		return [
-			'type' => 'success',
-			'msg' => "Wprowadzono zmiany ({$ret})",
-			// TODO: 'data' => all instances for pk
-		];
-	}
-
-	public function rmUserTableFilterAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'rmUserTableFilterAjax'), $args = 'JSON_FROM_REQUEST_BODY');
-	}
-	public function rmUserTableFilterAjax($args) {
-		$namespace = V::get('namespace', '', $args);
-		$filtrName = V::get('filtrName', '', $args);
-		if (!$namespace) throw new Exception("Missing namespace");
-		if (!$filtrName) throw new Exception("Missing filtrName");
-
-		$userFltrConfKey = "tableColFilters__" . User::getLogin();
-		$currentFilters = DB::getPDO()->fetchValue(" select CONF_VAL from CRM_CONFIG where CONF_KEY = '{$userFltrConfKey}' ");
-		if (!$currentFilters) return [
-			'type' => 'warning',
-			'msg' => "Brak filtrów w bazie",
-		];
-		$currentFilters = json_decode($currentFilters, 'assoc');
-		unset($currentFilters[$namespace][$filtrName]);
-		$affeced = DB::getPDO()->update('CRM_CONFIG', 'CONF_KEY', $userFltrConfKey, [
-			'CONF_VAL' => json_encode($currentFilters)
-		]);
-		return [
-			'type' => 'success',
-			'msg' => 'Zapisano nowy filtr',
-			'data' => $currentFilters[$namespace]
-		];
-	}
-	public function addUserTableFilterAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'addUserTableFilterAjax'), $args = 'JSON_FROM_REQUEST_BODY');
-	}
-	public function addUserTableFilterAjax($args) {
-		$namespace = V::get('namespace', '', $args);
-		$filtrName = V::get('filtrName', '', $args);
-		$visibleCols = V::get('visibleCols', '', $args);
-		if (!$namespace) throw new Exception("Missing namespace");
-		if (!$filtrName) throw new Exception("Missing filtrName");
-		if (!$visibleCols) throw new Exception("Missing visibleCols");
-
-		$userFltrConfKey = "tableColFilters__" . User::getLogin();
-		$currentFilters = DB::getPDO()->fetchValue(" select CONF_VAL from CRM_CONFIG where CONF_KEY = '{$userFltrConfKey}' ");
-		$currentFilters = ($currentFilters) ? json_decode($currentFilters, 'assoc') : [];
-		$currentFilters[$namespace][$filtrName] = $visibleCols;
-		$sqlFltr = json_encode($currentFilters);
-		DB::getPDO()->execSql("
-			insert into CRM_CONFIG (CONF_KEY, CONF_VAL)
-			values ('$userFltrConfKey', '{$sqlFltr}')
-			on duplicate key update CONF_VAL = '{$sqlFltr}'
-		");
-		return [
-			'type' => 'success',
-			'msg' => 'Zapisano nowy filtr',
-			'data' => $currentFilters[$namespace]
-		];
-	}
-	public function getUserTableFilterAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'getUserTableFilterAjax'), $args = 'JSON_FROM_REQUEST_BODY');
-	}
-	public function getUserTableFilterAjax($args) {
-		$namespace = V::get('namespace', '', $args);
-		if (!$namespace) throw new Exception("Missing namespace");
-
-		$userFltrConfKey = "tableColFilters__" . User::getLogin();
-		$currentFilters = DB::getPDO()->fetchValue(" select CONF_VAL from CRM_CONFIG where CONF_KEY = '{$userFltrConfKey}' ");
-		$currentFilters = ($currentFilters) ? json_decode($currentFilters, 'assoc') : [];
-		return [
-			'type' => 'success',
-			'msg' => 'Odczytano filtry użytkownika',
-			'data' => (!empty($currentFilters[$namespace])) ? $currentFilters[$namespace] : []
-		];
-	}
-
-	public function revertFromHistAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'revertFromHistAjax'));
-	}
-	public function revertFromHistAjax() {
-		$typeName = V::get('typeName', '', $_REQUEST, 'word');
-		if (!$typeName) throw new Exception("Wrong param typeName");
-
-		// TODO: use namespace from url
-		// $namespace = V::get('namespace', '', $_GET, 'word');
-		// if (!$namespace) {
-		// 	$typeName = V::get('typeName', '', $_GET, 'word');
-		// 	if (!$typeName) throw new Exception("Wrong param typeName");
-		// 	$namespace = Api_WfsNs::getBaseWfsUri() . '/' . str_replace(':', '/', $typeName);
-		// }
-		// $acl = Core_AclHelper::getAclByNamespace($namespace, $forceTblAclInit = ('1' == V::get('_force', '', $_GET)));
-
-		$id = V::get('ID', '', $_REQUEST, 'word');
-		if (!$id) throw new Exception("Wrong param ID");
-		$idHist = V::get('idHist', '', $_REQUEST, 'word');
-		if (!$idHist) throw new Exception("Wrong param idHist");
-		$fieldName = V::get('fieldName', '', $_REQUEST, 'word');
-		if (!$fieldName) throw new Exception("Wrong param fieldName");
-		$acl = Core_AclHelper::getAclByTypeName($typeName);
-
-		$item = $acl->getItem($id);
-		if (!$item) throw new HttpException("Item not found", 404);
-		if (!$acl->canWriteObjectField($fieldName, $record)) throw new Exception("Missing perm Write for field {$fieldName}");
-		$histItem = $acl->getHistItem($id, $idHist);
-		if (!$histItem) throw new HttpException("Hist Item not found", 404);
-
-		$histValue = V::get($fieldName, 'N/S;', $histItem);
-		if ('N/S;' == $histValue) throw new Exception("Missing field value in hist[{$idHist}] for field({$fieldName}) from item[{$id}]");
-
-		if ($acl->isGeomField($fieldName)) {
-			$wktType = strtoupper($acl->getGeomFieldType($fieldName));
-			if (!$wktType) throw new Exception("Wrong geometry type for field {$fieldName}");
-			if ($wktType != strtoupper(substr($histValue, 0, strlen($wktType)))) throw new Exception("Wrong geometry type for field {$fieldName} in hist value");
-			$coords = trim(substr($histValue, strlen($wktType)), '()');
-			$wktValue = $acl->convertGmlCoordsToWkt($wktType, $coords, ['cs'=>' ', 'ts'=>',']);
-			if (!$wktValue) throw new Exception("BUG in hist record");
-
-			$sqlObj = array();
-			$sqlObj['ID'] = $id;
-			$sqlObj[$fieldName] = "GeomFromText('{$wktValue}')";
-			$affected = DB::getDB()->UPDATE_OBJ($acl->getName(), (object)$sqlObj);
-			if (0 == $affected) throw new AlertInfoException("Nie wprowadzono żadnych zmian");
-			else if ($affected < 0) throw new Exception("Wystąpiły błędy podczas aktualizacji rekordu [{$id}]");
-			$jsonResponse = array();
-			$jsonResponse['type'] = 'success';
-			$jsonResponse['msg'] = "Zaktualizowano dane na podstawie wcześniejszej wartości dla rekordu [{$id}]";
-			$jsonResponse['actions'] = array();
-			$jsonResponse['actions'][] = ['jsFunction'=>'TableAjax__HIST_Route', 'args'=>[$id]];
-			return $jsonResponse;
-		} else {
-			throw new HttpException("Not implemented - update from hist only for the geom field", 501);
-		}
-		throw new Exception("BUG: update field '{$fieldName}' in item[{$id}] from hist[{$idHist}]", 501);
-	}
-
-	public function removeTheGeomAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'removeTheGeomAjax'), $args = 'JSON_FROM_REQUEST_BODY');
-	}
-	public function removeTheGeomAjax($args) {
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = Core_AclHelper::getAclByNamespace($namespace, $forceTblAclInit = ('1' == V::get('_force', '', $_GET)));
-		$primaryKeyField = $acl->getPrimaryKeyField();
-		$primaryKey = V::get($primaryKeyField, 0, $args, 'int');
-		$geomFieldName = 'the_geom';
-		$response = new stdClass();
-
-		if ($primaryKey <= 0) throw new HttpException("Bad Request - Wrong param ID", 400);
-
-		$record = $acl->getItem($primaryKey);
-		if (!$record) throw new HttpException("Nie odnaleziono rekordu nr {$primaryKey}", 404);
-		if (!$acl->canWriteObjectField($geomFieldName, $record)) throw new HttpException("Brak dostępu do zapisu dla pola {$geomFieldName}", 403);
-
-		if (empty($record->{$geomFieldName})) {
-			$response->type = 'info';
-			$response->msg = "Rekord nie jest powiązany z żadnym obiektem na mapie";
-			$response->record = $record;
-			return $response;
-		}
-
-		$itemPatch = array();
-		$itemPatch[$geomFieldName] = "NULL";
-		$itemPatch[$primaryKeyField] = $primaryKey;
-
-		$response = new stdClass();
-		try {
-			$affected = $acl->updateItem($itemPatch);
-
-			if ($affected > 0) {
-				$response->type = 'success';
-				$response->msg = "Usunięto obiekt z mapy dla rekordu {$primaryKey}";// Rekord zapisany pomyślnie
-			} else if ($affected == 0) {
-				$response->type = 'info';
-				$response->msg = "Nie wprowadzono żadnych zmian";
-			}
-			$response->record = $acl->getItem($primaryKey);
-		}
-		catch (Exception $e) {
-			$response->type = 'error';
-			$response->msg = $e->getMessage();
-		}
-
-		return $response;
-	}
-
-	public function moreFunctionsCellAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'moreFunctionsCell'), $args = $_GET);
-	}
-	public function moreFunctionsCell($args) {// ajax task 'MORE_FUNCTIONS_CELL'
-		$id = V::get('ID', 0, $args, 'int');
-		if ($id <= 0) throw new HttpException("404", 404);
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = Core_AclHelper::getAclByNamespace($namespace, $forceTblAclInit = ('1' == V::get('_force', '', $args)));
-
-		$response = new stdClass();
-		$response->type = 'success';
-		$response->msg = 'Funkcje';
-		$response->rowFunctions = Core_AclHelper::getMoreFunctionsCell($acl, array('primary_key' => $id));
-		return $response;
-	}
-
-	public function editFormAction() {// namespace, _hash, _primaryKey
-		$args = $_REQUEST;
-		$id = V::get('_primaryKey', 0, $args, 'int');
-		if ($id <= 0) throw new HttpException("Bad Request - missing primaryKey", 400);
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = Core_AclHelper::getAclByNamespace($namespace);
-		$tbl = $this->getTableAjaxWidget($acl);
-		$tbl->sendAjaxEdit($id, $args);
-	}
-	public function editSaveAjaxAction() {
-		Response::sendTryCatchJson(array($this, 'editSaveAjax'), $args = 'JSON_FROM_REQUEST_BODY');
-	}
-	public function editSaveAjax($args) {
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = Core_AclHelper::getAclByNamespace($namespace);
-
-		$primaryKeyField = $acl->getPrimaryKeyField();
-		$primaryKey = V::get('primaryKey', 0, $args, 'int');
-		if (empty($primaryKey)) throw new HttpException("Bad Request - missing primaryKey!", 400);
-
-		$item = $acl->getItem($primaryKey);
-		if (!$item) throw new HttpException("Item not exists!", 404);
-
-		$itemFromUser = $acl->convertObjectFromUserInput($args['form'], $type = 'array_by_id', $prefix = 'f');
-
-		$response = new stdClass();
-		$response->primaryKey = $primaryKey;
-		try {
-			$itemFromUser[$primaryKeyField] = $primaryKey;
-			$affected = $acl->updateItem($itemFromUser);
-
-			if ($affected > 0) {
-				$response->type = 'success';
-				$response->msg = "Rekord zapisany pomyślnie";//"Record saved successfully";
-			} else if ($affected == 0) {
-				$response->type = 'info';
-				$response->msg = "Nie wprowadzono żadnych zmian";
-			}
-			$response->record = $acl->getItem($primaryKey);
-			$rowFunList = Core_AclHelper::getMoreFunctionsCell($acl, array('primary_key'=>$primaryKey, 'record'=>$response->record));
-			if (!empty($rowFunList)) $response->rowFunctions = $rowFunList;
-		}
-		catch (Exception $e) {
-			$response->type = 'error';
-			$response->msg = "Wystąpiły błędy!";
-			$response->msg .= $e->getMessage();
-		}
-
-		return $response;
-	}
-
-	public function typeSpecialCellAction() {
-		Response::sendTryCatchJson(array($this, 'typeSpecialCell'), $args = $_REQUEST);
-	}
-	public function typeSpecialCell($args) {
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = Core_AclHelper::getAclByNamespace($namespace);
-		$id = V::get('ID', 0, $args, 'int');
-		$fieldName = V::get('col', '', $args);
-		if ($id <= 0 || empty($fieldName)) throw new HttpException("Bad Request - missing id or col", 400);
-
-		$col = $fieldName;// TODO: RM $col
-
-		$jsonData = new stdClass();
-		$idField = $acl->getFieldIdByName($fieldName);
-		if (!$idField) throw new Exception("Wrong field");
-
-		$item = $acl->getItem($id);
-		if (!$acl->canReadObjectField($fieldName, $item)) throw new Exception("Brak dostępu");
-
-		$typeSpecial = Typespecial::getInstance($idField, $fieldName);
-		if ($typeSpecial) {
-			$jsonData->data = $typeSpecial->getReturnData($acl->getID(), $id, $fieldName, '');
-			$jsonData->namespace = 'default_db/' . V::get('tbl_name', '', $jsonData->data);
-		}
-		return $jsonData;
-	}
-
-	/**
-	 * @param $_GET['namespace'] = AclNamespace
-	 * @param $_GET['format'] = 'csv' | 'html'
-	 * @param $_GET['flds'] = csv - coma separated field names
-	 * @param $_GET['sortCol'] = FieldName
-	 * @param $_GET['sortDir'] = SortDir ('desc' | 'asc')
-	 * @param $_GET['f_{$fieldName}'] = filter
-	 * @param $_GET['sf_{$fieldName}'] = force filter
-	 */
-	public function exportAction() {
-		$args = $_GET;
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = Core_AclHelper::getAclByNamespace($namespace);
-
-		$exportLimit = 10000;
-		$params = array();
-		$params['limit'] = $exportLimit;
-		// $params['limitstart'] = 0;
-		$params['order_by'] = V::get('sortCol', '', $args);
-		$params['order_dir'] = V::get('sortDir', '', $args);
-		$params['cols'] = array($acl->getPrimaryKeyField());
-		$toExportFields = explode(',', V::get('flds', '', $_GET));
-		if (empty($toExportFields)) throw new Exception("Nie wybrano żandych pól do exportu.");
-		$allowedExportFieldList = Core_AclHelper::getExportFieldList($acl);
-		foreach ($toExportFields as $fieldName) {
-			if ($fieldName == $acl->getPrimaryKeyField()) continue;
-			if (!in_array($fieldName, $allowedExportFieldList)) throw new Exception("Brak uprawnień do exportu pola '{$fieldName}'");
-			$params['cols'][] = $fieldName;
-		}
-
-		$labels = array();
-		foreach ($toExportFields as $fieldName) {
-			$labels[ $fieldName ] = $acl->getFieldLabel($fieldName);
-		}
-
-		foreach ($args as $k => $v) {
-			if (strlen($k) > 3 && substr($k, 0, 2) == 'f_' && strlen($v) > 0) {// filter prefix
-				$params[$k] = $v;
-			}
-			else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_' && strlen($v) > 0) {// special filter prefix
-				$params[$k] = $v;
-			}
-		}
-		$queryFeatures = $acl->buildQuery($params);
-		$total = $queryFeatures->getTotal();
-		// if ($total > $exportLimit) $params['limit'] = $exportLimit;
-		$items = $queryFeatures->getItems();
-
-		$format = V::get('format', 'html', $_GET);
-		if ('html' == $format) {
-			UI::gora();
-			UI::startTag('table', ['class'=>'table table-bordered table-hover']);
-				UI::startTag('thead');
-					UI::startTag('tr');
-					foreach ($labels as $fldName => $label) {
-						UI::tag('th', [], $label);
-					}
-					UI::endTag('tr');
-				UI::endTag('thead');
-				UI::startTag('tbody');
-				foreach ($items as $item) :
-					UI::startTag('tr');
-					foreach ($labels as $fldName => $label) :
-						UI::tag('td', [], $item->{$fldName});
-					endforeach;
-					UI::endTag('tr');
-				endforeach;
-				UI::endTag('tbody');
-			UI::endTag('table');
-			UI::dol();
-		}
-		else if ('csv' == $format) {
-			$csvFileName = "Tabela-" . $acl->getName() . "-" . date("Y-m-d_H_s");
-			header('Content-Type: text/csv; charset=utf-8');
-			header("Content-Disposition: attachment; filename={$csvFileName}.csv");
-			$csvSeparator = ';';
-
-			$labelsLine = array();
-			foreach ($labels as $fldName => $label) {
-				$labelsLine[] = '"' . addslashes($label) . '"';
-			}
-			echo implode($csvSeparator, $labelsLine) . "\n";
-
-			foreach ($items as $item) {
-				$itemLine = array();
-				foreach ($labels as $fldName => $label) {
-					$itemLine[] = '"' . addslashes($item->{$fldName}) . '"';
-				}
-				echo implode($csvSeparator, $itemLine) . "\n";
-			}
-		}
-		else {
-			die("Nieobsługiwany format danych.");
-		}
-	}
-
-	public function loadDataAjaxAction() {
-		// $tbl = $this->getTableAjaxWidget($acl);
-		Response::sendTryCatchJson(array($this, 'loadDataAjax'), $args = $_GET);
-	}
-	public function loadDataAjax($args) {
-		$namespace = V::get('namespace', '', $args, 'word');
-		if (!$namespace) throw new HttpException("Bad Request - missing namespace", 400);
-		$acl = P5::getAclByNamespace($namespace);
-
-		$uiConf = [
-			'pageSize' => 10
-		];
-		$DBG = ('1' == V::get('DBG', '', $args));
-		$pageSize = V::get('pageSize', $uiConf['pageSize'], $args, 'int');
-		$page = V::get('page', 0, $args, 'int');
-		$currSortCol = V::get('currSortCol', '', $args);
-		$currSortFlip = V::get('currSortFlip', '', $args);
-		if ($page > 0) {
-			$page -= 1;
-		}
-
-		$params = array();
-		$params['limit'] = $pageSize;
-		$params['limitstart'] = $page * $params['limit'];
-		$params['order_by'] = ($currSortCol)? $currSortCol : '';
-		$params['order_dir'] = $currSortFlip;
-
-		$filters = new stdClass();
-		$filters->currSortCol = $currSortCol;
-		$filters->currSortFlip = $currSortFlip;
-		foreach ($args as $k => $v) {
-			if (strlen($k) > 3 && substr($k, 0, 2) == 'f_' && strlen($v) > 0) {// filter prefix
-				$params[$k] = $v;
-				$filters->{$k} = $v;
-			}
-			else if (strlen($k) > 4 && substr($k, 0, 3) == 'sf_' && strlen($v) > 0) {// special filter prefix
-				$params[$k] = $v;
-				$filters->{$k} = $v;
-			}
-		}
-
-		// TODO: $this->setFilters($filters);
-
-		$vCols = $acl->getVirtualFieldListByIdZasob();
-		if (!empty($vCols)) {
-			if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">vCols (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($vCols);echo'</pre>';}
-		}
-
-		$visibleCols = $acl->getVisibleFieldListByIdZasob();
-		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">visibleCols (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($visibleCols);echo'</pre>';}
-
-		$jsonData = new stdClass();
-		$jsonData->page = $page + 1;
-		$jsonData->pageSize = $pageSize;
-		$jsonData->filters = $filters;
-		$jsonData->cols = new stdClass();
-		$jsonData->primaryKey = $acl->getPrimaryKeyField();
-		$ind = 0;
-		foreach ($visibleCols as $fieldID => $col) {
-			$ind++;
-			$columnConfig = (object)array('index'=>$ind);
-			if (in_array($col, array('A_STATUS','A_STATUS_CURRENT','A_SERVICES_STATUS_CURRENT'))) {
-				$columnConfig->format = '<div class="cell-A_STATUS-{0}">{0}</div>';
-			}
-			else if (in_array($col, array('Status'))) {
-				// Ahmes problems Status colors
-				$columnConfig->format = '<div class="cell-Status-{0}">{0}</div>';
-			}
-			else if ($acl->isGeomField($col)) {
-				$columnConfig->type = 'geom';
-			}
-			if ('' !== ($label = $acl->getFieldLabel($col))) {
-				$columnConfig->friendly = $label;
-			}
-			$colType = $acl->getFieldType($col);
-			if ($colType) {// @see MarkTableAjaxFilterColType
-				if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">field('.$col.') $colType (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($colType);echo'</pre>';}
-				if ($colType['type'] == 'date') {
-					//$columnConfig->type = 'date';// TODO: require datetimepicker
-				}
-				if (!empty($colType['simpleType'])) $columnConfig->type = $colType['simpleType'];
-			} else {// typespecial - no type
-				$columnConfig->type = 'special';
-			}
-			$columnConfig->xsdType = $acl->getXsdFieldType($col);
-			if ($columnConfig->xsdType) {
-				$ex = explode(":", $columnConfig->xsdType);
-				switch ($ex[0]) {
-					case 'ref':
-					case 'alias_ref':
-						if (3 != count($ex)) throw new HttpException("Schema Error for field({$col}) xsdType({$columnConfig->xsdType})", 500);
-						$columnConfig->type = 'ref';
-						$columnConfig->xsdRefUri = Api_WfsNs::getNsUri($ex[1]);
-						$columnConfig->xsdRefType = $ex[2];
-						$columnConfig->xsdRefNsPrefix = $ex[1];
-						break;
-					case 'xsd':
-						switch ($ex[1]) {
-							case 'string': $columnConfig->type = 'string'; break;
-							case 'ind': $columnConfig->type = 'number'; break;// TODO: bug 'ind'?
-						}
-						break;
-					case 'p5':
-						switch ($ex[1]) {
-							case 'alias': {
-								$format = $acl->getXsdFieldParam($col, 'format');
-								if ($format) $columnConfig->format = $format;
-							} break;
-							case 'string': {
-								$columnConfig->type = 'p5:string';
-								$columnConfig->formatByValue = $acl->getXsdFieldParam($col, 'formatByValue');
-							} break;
-						}
-						break;
-				}
-			}
-
-			$typeSpecial = Typespecial::getInstance($fieldID, $col);
-			if ($typeSpecial) {
-				if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">typeSpecial (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($typeSpecial);echo'</pre>';}
-				$columnConfig->_tsRetId = $typeSpecial->getReturnId();
-				if ($columnConfig->_tsRetId == 0) {
-					$tsParamOut = V::get('param_out', null, $typeSpecial);
-					if ($tsParamOut) {
-						$tsFormat = V::get('format', null, $tsParamOut);
-						$tsValues = V::get('values', null, $tsParamOut);
-						$tsAliases = V::get('alias', null, $tsParamOut);
-						if (false !== strpos($tsFormat, '<a') && !empty($tsValues) && !empty($tsAliases)) {
-							$tsAliasMap = array();
-							/* [values] => Array([ID] => 1467), [alias] => Array([1467] => ID) */
-							$bugTsColsNotVisible = array();
-							foreach ($tsValues as $kVarName => $vIdZasob) {
-								if (array_key_exists($vIdZasob, $tsAliases)) {
-									$tsAliasMap[$kVarName] = $tsAliases[$vIdZasob];
-								} else {
-									$bugTsColsNotVisible[] = "noAliasFor {$vIdZasob}";
-								}
-								if (!array_key_exists($vIdZasob, $visibleCols)) {
-									$bugTsColsNotVisible[] = $vIdZasob;
-								}
-							}
-							if (empty($bugTsColsNotVisible)) {
-								$tsSimpleLink = new stdClass();
-								$tsSimpleLink->format = $tsFormat;
-								$tsSimpleLink->aliasMap = $tsAliasMap;
-								$columnConfig->_tsSimpleLink = $tsSimpleLink;
-								$columnConfig->type = 'simpleLink';
-							} else {
-								$columnConfig->_tsSimpleLinkBug = $bugTsColsNotVisible;
-							}
-						}
-					}
-				}
-			}
-
-			if ($columnConfig->xsdType) {// fix fields type p5:typeSpecialSimpleLink (previously defined by Typespecial)
-				switch ($columnConfig->xsdType) {
-					case 'p5:typeSpecialSimpleLink': {
-						$columnConfig->type = 'simpleLink';
-						$columnConfig->_tsRetId = 0;
-						$columnConfig->_tsSimpleLink = new stdClass();
-						$columnConfig->_tsSimpleLink->format = $acl->getXsdFieldParam($col, 'format');
-						$columnConfig->_tsSimpleLink->aliasMap = $acl->getXsdFieldParam($col, 'aliasMap');
-					} break;
-				}
-			}
-
-			// @see ajaxHiddenColsSave
-			if (UserProfile::isHiddenColumn($acl->getID(), $fieldID)) {
-				$columnConfig->hidden = true;
-			}
-
-			$columnConfig->description = $acl->getFieldOpis($col);
-
-			$jsonData->cols->{$col} = $columnConfig;
-		}
-		$jsonData->rows = array();
-		$queryFeatures = $acl->buildQuery($params);
-		$jsonData->total = $queryFeatures->getTotal();
-		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">get_total (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($jsonData->total);echo'</pre>';}
-		$listItems = $queryFeatures->getItems();
-		$primaryKeyField = $acl->getPrimaryKeyField();
-		$items = []; foreach ($listItems as $item) $items[ $item[$primaryKeyField] ] = $item;
-
-		foreach ($items as $idx => $item) $items[$idx] = (array)$item;
-		if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">items (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($items);echo'</pre>';}
-		// TODO: add virtual data by Typespecial
-		if (!empty($vCols) && !empty($items)) {
-			foreach ($vCols as $vColID => $vCol) {
-				$colType = $acl->getFieldTypeById($vColID);
-				if ($colType) continue;// pomin Typespecial dla realnych komorek w bazie danych
-
-				$typeSpecial = Typespecial::getInstance($vColID, $vCol);
-				if ($typeSpecial) {
-					$columnConfig = V::get($vCol, null, $jsonData->cols);
-					if ($columnConfig && !empty($columnConfig->_tsSimpleLink)) {
-						// pomin simple link values - mved to js render
-					} else {
-						if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Typespecial('.$vColID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($typeSpecial);echo'</pre>';}
-						$ids = array_keys($items);
-						$specialValues = $typeSpecial->getValuesByIds($this->_zasobID, $ids);
-						if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Typespecial('.$vCol.') specialValues (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($specialValues);echo'</pre>';}
-						if (!empty($specialValues)) foreach ($specialValues as $kItemID => $vValues) {
-							$tsValue = implode('<br>', $vValues);
-							if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Item['.$kItemID.'].'.$vCol.' specialValues (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($items[$kItemID]);echo'</pre>';}
-							if (!empty($items[$kItemID][$vCol]) && !empty($tsValue)) {
-								$items[$kItemID][$vCol] .= ": {$tsValue}";
-							} else {
-								$items[$kItemID][$vCol] = $tsValue;
-							}
-						}
-					}
-				}
-			}
-		}
-		{
-			if(V::get('DBG', '', $_GET)){$jsonData->__DBG__ = [];}
-			$p5Alias = [];
-			foreach ((array)$jsonData->cols as $fieldName => $conf) {
-				if ('p5:alias' == V::get('xsdType', '', $conf)) {
-					if(V::get('DBG', '', $_GET)){$jsonData->__DBG__[$fieldName] = $conf;}
-					$aliasType = $acl->getXsdFieldParam($fieldName, 'type');// 'type' => 'sql_table_alias',
-					if ('sql_table_alias' == $aliasType) {
-						$p5Alias[$fieldName] = (array)$conf;
-						$p5Alias[$fieldName]['type'] = 'sql_table_alias';
-						$p5Alias[$fieldName]['local_join_key'] = $acl->getXsdFieldParam($fieldName, 'local_join_key');// 'local_join_key' => 'ID',
-						$p5Alias[$fieldName]['remote_table_name'] = $acl->getXsdFieldParam($fieldName, 'remote_table_name');// 'remote_table_name' => 'CRM_LISTA_ZASOBOW_ORDERS_summary_view',
-						$p5Alias[$fieldName]['remote_join_key'] = $acl->getXsdFieldParam($fieldName, 'remote_join_key');// 'remote_join_key' => 'ID',
-						$p5Alias[$fieldName]['remote_column_value'] = $acl->getXsdFieldParam($fieldName, 'remote_column_value');// 'remote_column_value' => 'SUM_POS',
-					} else if ('sql_query_alias' == $aliasType) {
-						$p5Alias[$fieldName] = (array)$conf;
-						$p5Alias[$fieldName]['type'] = 'sql_query_alias';
-						$p5Alias[$fieldName]['local_join_key'] = $acl->getXsdFieldParam($fieldName, 'local_join_key');
-						$p5Alias[$fieldName]['join_query_format'] = $acl->getXsdFieldParam($fieldName, 'join_query_format');
-					}
-				}
-			}
-			if(V::get('DBG', '', $_GET)){$jsonData->__DBG__['$p5Alias'] = $p5Alias;}
-			if(V::get('DBG', '', $_GET)){$jsonData->__DBG__['$aliasValuesRaw'] = [];}
-			if ($p5Alias) {
-				$sqlLocalTableName = $acl->getRootTableName();
-				$primaryKeyField = $acl->getPrimaryKeyField();
-				foreach ($p5Alias as $fieldName => $conf) {
-					$aliasValuesRaw = [];
-
-					if ('sql_table_alias' == $conf['type']) {
-						$localKeys = [];
-						$localKeyName = V::get('local_join_key', '', $conf);
-						if ($localKeyName) {
-							if (!array_key_exists($localKeyName, $localKeys)) {
-								$localKeys[$localKeyName] = [];
-								foreach ($items as $item) {
-									$keyLocal = V::get($localKeyName, 0, $item);
-									if ($keyLocal) $localKeys[$localKeyName][] = DB::getPDO()->quote($keyLocal, PDO::PARAM_STR);
-								}
-							}
-							if(V::get('DBG', '', $_GET)){$jsonData->__DBG__['$localKeys'] = $localKeys;}
-							if (!empty($localKeys[$localKeyName])) {
-								$sqlRemoteTable = V::get('remote_table_name', '', $conf);
-								$sqlRemoteValueFieldName = V::get('remote_column_value', '', $conf);
-								$sqlRemoteKeyName = V::get('remote_join_key', '', $conf);
-								$sqlLocalKeyName = $acl->getSqlFieldName($localKeyName);
-								$aliasValuesRaw = DB::getPDO()->fetchAllByKey("
-									select r.{$sqlRemoteKeyName} as {$sqlLocalKeyName}, r.{$sqlRemoteValueFieldName} as remote_value
-									from {$sqlRemoteTable} r
-									where r.{$sqlRemoteKeyName} in(" . implode(",", $localKeys[$localKeyName]) . ")
-								", $sqlLocalKeyName);
-								if(V::get('DBG', '', $_GET)){$jsonData->__DBG__['$aliasValuesRaw'][$fieldName] = $aliasValuesRaw;}
-							}
-						}
-					} else if ('sql_query_alias' == $conf['type']) {
-						$localKeys = [];
-						$localKeyName = V::get('local_join_key', '', $conf);
-						$sqlFormat = V::get('join_query_format', '', $conf);
-						if ($localKeyName && $sqlFormat) {
-							if (!array_key_exists($localKeyName, $localKeys)) {
-								$localKeys[$localKeyName] = [];
-								foreach ($items as $item) {
-									$keyLocal = V::get($localKeyName, 0, $item);
-									if ($keyLocal) $localKeys[$localKeyName][] = DB::getPDO()->quote($keyLocal, PDO::PARAM_STR);
-								}
-							}
-						}
-						if (!empty($localKeys[$localKeyName])) {
-							$sql = str_replace('{sql_in_local_join_key}', implode(",", $localKeys[$localKeyName]), $sqlFormat);
-							$sqlLocalKeyName = $acl->getSqlFieldName($localKeyName);
-							$aliasValuesRaw = DB::getPDO()->fetchAllByKey($sql, $sqlLocalKeyName);
-						}
-					}
-					DBG::log($aliasValuesRaw, 'array', '$aliasValuesRaw');
-					if (!empty($aliasValuesRaw)) {
-						if(V::get('DBG_P5', '', $_GET)){echo '{ "$aliasValuesRaw": '.json_encode($aliasValuesRaw).', "dbg": [' . "\n";}
-						array_walk($items, function (&$item) use ($fieldName, $sqlLocalKeyName, $aliasValuesRaw) {
-							$sqlValue = V::get($sqlLocalKeyName, null, $item);
-							if(V::get('DBG_P5', '', $_GET)){echo '{ "sqlValue": "'.$sqlValue.'", "remote_value": "'.$aliasValuesRaw[$sqlValue]['remote_value'].'", "item": '.json_encode($item) . '},' . "\n";}
-							if ($sqlValue !== null && array_key_exists($sqlValue, $aliasValuesRaw)) {
-								if(V::get('DBG_P5', '', $_GET)){echo '{ "TODO_update_value": "'.$aliasValuesRaw[$sqlValue]['remote_value'].'"},' . "\n";}
-								$item[$fieldName] = $aliasValuesRaw[$sqlValue]['remote_value'];
-								if(V::get('DBG_P5', '', $_GET)){echo '{ "TODO_updated_value": "'.$item[$fieldName].'"},' . "\n";}
-							}
-						});
-						if(V::get('DBG_P5', '', $_GET)){echo "\n".'{}]}';die();}
-					}
-				}
-			}
-		}
-		foreach ($items as $item) {
-			// TODO: hide items without 'R'
-			foreach ($visibleCols as $fieldName) {
-				// TODO: ID default 'R'
-				if (!$acl->canReadObjectField($fieldName, $item)) $item[$fieldName] = '*****';
-
-				// null => empty string
-				if (!isset($item[$fieldName]) || (!$item[$fieldName] && $item[$fieldName] !== '0')) {
-					if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">isEmptyString['.$fieldName.'] (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($item[$fieldName]);echo'</pre>';}
-					$item[$fieldName] = '';
-				}
-			}
-			$jsonData->rows[] = $item;
-		}
-		$jsonData->type = 'success';
-		$jsonData->msg = 'pobrano nowe dane';
-		return $jsonData;
-	}
-
-}

+ 228 - 0
SE/se-lib/Route/ViewTableAjax.php

@@ -99,6 +99,187 @@ class Route_ViewTableAjax extends RouteBase {
 			$tbl = $this->getTableAjaxWidget($acl, $backRefFilter, $childRefFilter);
 			$tbl->setFilterInit($filterInit);
 			if (!empty($forceFilterInit)) $tbl->setForceFilterInit($forceFilterInit);
+			if (V::get('DBG_INST', '', $_GET)) { // TODO: TEST namespace
+				$siblings = ACL::getNamespaceSiblings($namespace);
+				DBG::nicePrint($siblings, '$siblings');
+				$filtrInstance = V::get('f_instance', [], $_POST, 'array');
+				DBG::nicePrint($filtrInstance, '$filtrInstance');
+				$sibling = 'default_db/CRM_PROCES/PROCES_INIT'; DBG::nicePrint(array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'YES'], ('YES' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : []), "merge {$sibling} YES");
+				$sibling = 'default_db/CRM_PROCES/PROCES_INIT'; DBG::nicePrint(array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'NO'], ('NO' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : []), "merge {$sibling} NO");
+
+				$_ = array(UI, 'h');
+				echo $_('form', ['method' => "POST", 'style' => "width:600px; border:1px solid #ddd; border-radius:2px"], [
+					$_('div', ['style' => "background-color:#ddd"], "Test Filtr instancji"),
+					$_('div', ['style' => "padding:8px"], array_map(function ($sibling) use ($filtrInstance, $_) {
+						return $_('div', [], [
+							$_('label', ['style' => "margin:0 8px"], [
+								$_('input', array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'YES'], ('YES' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : [])),
+								" TAK "
+							]),
+							$_('label', ['style' => "margin:0 8px"], [
+								$_('input', array_merge(['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'NO'], ('NO' === V::get($sibling, '', $filtrInstance)) ? ['checked' => "checked"] : [])),
+								" NIE "
+							]),
+							$_('label', ['style' => "margin:0 8px"], [
+								$_('input', ['type'=>"radio", 'name'=>"f_instance[{$sibling}]", 'value'=>'x']),
+								" pomiń "
+							]),
+							// $_('button', ['onClick'=>"this.form.f_instance['{$sibling}'].value = ''; return false"], "odznacz"),
+							$_('button', ['onClick'=>"console.log(this.form.elements['f_instance[{$sibling}]']); this.form.elements['f_instance[{$sibling}]'].value = 'x'; return false"], "odznacz"),
+							" - {$sibling}"
+						]);
+					}, $siblings)),
+					$_('div', [], [
+						$_('input', ['type'=>"hidden", 'name'=>'_route', 'value'=>"ViewObject"]),
+						$_('input', ['type'=>"hidden", 'name'=>'namespace', 'value'=>$namespace]),
+						$_('input', ['type'=>"submit", 'value'=>"Filtruj - TEST"]),
+					]),
+				]);
+				DBG::nicePrint($_POST, '$_POST');
+				{
+					$args = $_POST;
+					$fIsInstance = [];
+					$fIsNotInstance = [];
+					if (!empty($args['f_instance'])) {
+						foreach ($args['f_instance'] as $inst => $selected) {
+							if ('YES' === $selected) {
+								$fIsInstance[] = $inst;
+							} else if ('NO' === $selected) {
+								$fIsNotInstance[] = $inst;
+							}
+						}
+					}
+				}
+				$queryFeatures = $acl->buildQuery([
+					// TODO: 'propertyName' => "*,@instance",
+					'f_is_instance' => $fIsInstance,
+					'f_is_not_instance' => $fIsNotInstance,
+					'@instances' => '1',
+					'limit' => 10
+				]);
+				// $total = $queryFeatures->getTotal();
+				$items = $queryFeatures->getItems();
+
+				$rootNamespace = $acl->getRootNamespace();
+				DBG::nicePrint($rootNamespace, '$rootNamespace');
+				$jsRenderFunName = 'render_dropdown_instances_' . substr(md5(time()), 0, 6);
+				DBG::nicePrint($jsRenderFunName, '$jsRenderFunName');
+				UI::table([
+					'rows' => array_map(function($row) use ($namespace, $siblings, $rootNamespace, $jsRenderFunName) {
+						return [
+							'ID' => $row['ID'],
+							'DESC' => $row['DESC'],
+							'TYPE' => $row['TYPE'],
+							'Typ' => UI::h('div', ['class'=>"p5UI__dropdown-wrap"], [
+								UI::h('button', [
+									// 'onClick' => "p5UI__dropdown(event, this, 'left bottom')",
+									'onClick' => "p5UI__dropdown(event, this, 'left bottom', {$jsRenderFunName}({$row['ID']}))",
+									'class' => "btn btn-xs btn-default p5UI__dropdown-btn"
+								], [
+									UI::h('i', ['class' => "glyphicon glyphicon-tags", 'title' => "Ustaw typ danych (instancje)"]),
+								]),
+								UI::h('div', ['class' => "p5UI__dropdown-content"]
+									, array_merge(
+										[
+											UI::h('input', ['type' => "text", 'placeholder' => "Search..", 'class' => "p5UI__dropdown-input", 'onkeyup' => "p5_ViewObject_instances_filterInput(this)"], null),
+										]
+										, array_map(function ($sibling) use ($row, $namespace, $rootNamespace) {
+											return UI::h('div', ['label'=>$sibling, 'style'=>"padding:4px 0"], [
+												UI::h('button', array_merge(['class' => "btn btn-xs btn-default",
+													'style' => "margin:0 4px 0 0",
+													'title' => "Ustaw instancje '{$sibling}'",
+													'onClick' => "return p5_ViewObject_instance_set(this, '{$row['ID']}', '{$sibling}', 'yes')"],
+													(in_array($sibling, explode(',', $row['@instances']))) ? ['disabled' => "disabled"] : []
+												), "+"),
+												UI::h('button', ['class' => "btn btn-xs btn-default",
+													'style' => "margin:0 4px 0 0",
+													'title' => "Usuń instancje '{$sibling}'",
+													'onClick' => "return p5_ViewObject_instance_set(this, '{$row['ID']}', '{$sibling}', 'no')"], "-"),
+												UI::h('span', [], substr($sibling, strlen($rootNamespace) + 1)),
+											]);
+										}, $siblings)
+									)
+								)
+							]),
+							'instancesList' => implode(', ', ACL::getFeatureNamespaces($namespace, $row['ID'])),
+						];
+					}, $items)
+				]);
+				echo UI::h('style', ['type' => "text/css"], "
+					.p5UI__dropdown-content { min-width:400px; border:1px solid #ccc; background-color: #fff; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2) }
+					.p5UI__dropdown-content .p5UI__dropdown-item { display:block; color:#000; padding:4px; text-decoration:none }
+					.p5UI__dropdown-content .p5UI__dropdown-item:hover { background-color:#ebebeb }
+				");
+				echo UI::h('script', ['src'=>"static/vendor.js", 'type'=>"text/javascript"]);
+				$jsArgs = [
+					'SET_INSTANCE_URL' => $this->getLink('setInstanceAjax'),
+					'NAMESPACE' => $namespace,
+					'DBG' => DBG::isActive() ? 'true' : 'false',
+				];
+
+				UI::inlineJS(__FILE__ . '.instancesDropdown.js', [
+					'JS_GLOBAL_FUNCTION_NAME' => $jsRenderFunName,
+					'NAMESPACE' => $namespace,
+					'SET_INSTANCE_URL' => $this->getLink('setInstanceAjax'),
+					'DBG' => DBG::isActive() ? 1 : 0,
+					'INITIAL_DROPDOWN_DATA' => [
+						// 'allowed_instances' => $siblings,
+						'allowed_instances' => array_map(function ($sibling) use ($rootNamespace) {
+							return [
+								'namespace' => $sibling,
+								'label' => substr($sibling, strlen($rootNamespace) + 1)
+							];
+						}, $siblings),
+						'items' => array_map(function($row) use ($namespace, $siblings, $rootNamespace, $jsRenderFunName) {
+							return [
+								'pk' => $row['ID'], // TODO: $primaryKeyField
+								'instances' => explode(',', $row['@instances']),
+							];
+						}, $items)
+					],
+				]);
+				echo UI::h('script', [], "
+					var SET_INSTANCE_URL = '{$jsArgs['SET_INSTANCE_URL']}'
+					var NAMESPACE = '{$jsArgs['NAMESPACE']}'
+					function p5_ViewObject_instance_set(n, pk, sibling, toConnect) {
+						console.log('p5_ViewObject_instance_set pk('+pk+'), sibling('+sibling+'), toConnect('+toConnect+'), n', n);
+						window.fetch(SET_INSTANCE_URL, {
+							method: 'POST',
+							headers: { 'Content-Type': 'application/json' },
+							credentials: 'same-origin',
+							body: JSON.stringify({
+								namespace: NAMESPACE,
+								primaryKey: pk,
+								instance: sibling,
+								toConnect: toConnect,
+							})
+						}).then(function (response) {
+							return response.json()
+						}).then(function (response) {
+							p5UI__notifyAjaxCallback(response)
+							console.log(response) // TODO: render list
+						})
+					}
+				");
+				echo UI::h('script', [], "
+					function p5_ViewObject_instances_filterInput(n) {
+						var input, filter, ul, li, a, i, div;
+						input = n // .id-myInput
+						filter = input.value.toUpperCase()
+						div = n.parentNode // .id-myDropdown
+						a = div.getElementsByTagName('div')
+						for (i = 0; i < a.length; i++) {
+							if (a[i].getAttribute('label') && a[i].getAttribute('label').toUpperCase().indexOf(filter) > -1) {
+								a[i].style.display = 'block'
+							} else {
+								a[i].style.display = 'none'
+							}
+						}
+					}
+				");
+				echo '<hr style="margin-top:300px">';
+				exit;
+			}
 			echo $tbl->render();
 
 			if (DBG::isActive() && V::get('DBG_ACL', '', $_GET)) {// test load perms
@@ -207,6 +388,53 @@ class Route_ViewTableAjax extends RouteBase {
 		UI::dol();
 	}
 
+	public function setInstanceAjaxAction() {
+		Response::sendTryCatchJson(array($this, 'setInstanceAjax'), $args = 'JSON_FROM_REQUEST_BODY');
+	}
+	public function setInstanceAjax($args) {
+		// namespace => default_db/CRM_PROCES/PROCES_INIT
+		// primaryKey => 6
+		// instance => default_db/CRM_PROCES/PROCES_TREE
+		// toConnect => yes
+		if (empty($args['namespace'])) throw new Exception("Missing namespace");
+		if (empty($args['primaryKey'])) throw new Exception("Missing primaryKey");
+		if (empty($args['instance'])) throw new Exception("Missing instance");
+		if (empty($args['toConnect'])) throw new Exception("Missing toConnect");
+		if (!in_array($args['toConnect'], ['yes', 'no'])) throw new Exception("Wrong param toConnect");
+		$idInstance = ACL::getInstanceId($args['instance']);
+		$instanceTable = ACL::getInstanceTable($args['namespace']);
+		switch ($args['toConnect']) {
+			case 'yes': {
+				// TODO: _HIST info - waiting
+				$ret = DB::getPDO()->execSql("
+					insert into `{$instanceTable}` (`pk`, `idInstance`)
+						values ( :pk , :idInstance )
+				", [
+					'pk' => $args['primaryKey'],
+					'idInstance' => $idInstance,
+				]);
+				// TODO: _HIST info - mark as done
+			} break;
+			case 'no': {
+				// TODO: _HIST info - waiting
+				$ret = DB::getPDO()->execSql("
+					delete from `{$instanceTable}`
+					where `pk` = :pk
+						and `idInstance` = :idInstance
+				", [
+					'pk' => $args['primaryKey'],
+					'idInstance' => $idInstance,
+				]);
+				// TODO: _HIST info - mark as done
+			} break;
+		}
+		return [
+			'type' => 'success',
+			'msg' => "Wprowadzono zmiany ({$ret})",
+			// TODO: 'data' => all instances for pk
+		];
+	}
+
 	public function rmUserTableFilterAjaxAction() {
 		Response::sendTryCatchJson(array($this, 'rmUserTableFilterAjax'), $args = 'JSON_FROM_REQUEST_BODY');
 	}

+ 0 - 0
SE/se-lib/Route/ViewObject.php.instancesDropdown.js → SE/se-lib/Route/ViewTableAjax.php.instancesDropdown.js