Weekly update 2022-05-29
This commit is contained in:
parent
797f5a4d8e
commit
68db950971
|
@ -6,8 +6,7 @@ use Exception;
|
|||
/**
|
||||
*
|
||||
* Class fox\baseClass
|
||||
*
|
||||
* @desc baseClass mk 2 class
|
||||
* @desc FOX Base Class
|
||||
* @copyright MX STAR LLC 2021
|
||||
* @version 4.0.0
|
||||
* @author Pavel Dmitriev
|
||||
|
@ -17,6 +16,7 @@ use Exception;
|
|||
*
|
||||
**/
|
||||
|
||||
|
||||
class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportable
|
||||
{
|
||||
|
||||
|
@ -33,7 +33,7 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
|||
// id for xConstruct;
|
||||
|
||||
# if null - generated automatically
|
||||
public static $sqlSelectTemplate = null;
|
||||
public static $baseSqlSelectTemplate = null;
|
||||
|
||||
# primary index field. Default is id
|
||||
public static $sqlIdx = "id";
|
||||
|
@ -146,10 +146,10 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
|||
# How to call from child template:
|
||||
# parent::__construct($id, $sql, $prefix, $settings);
|
||||
$this->__settings = $settings;
|
||||
if (empty($this::$sqlSelectTemplate) && ! empty($this::$sqlTable)) {
|
||||
if (empty($this::$baseSqlSelectTemplate) && ! empty($this::$sqlTable)) {
|
||||
$this->__sqlSelectTemplate = "select * from `" . $this::$sqlTable . "` as `i`";
|
||||
} else {
|
||||
$this->__sqlSelectTemplate = $this::$sqlSelectTemplate;
|
||||
$this->__sqlSelectTemplate = $this::$baseSqlSelectTemplate;
|
||||
}
|
||||
|
||||
if (isset($sql)) {
|
||||
|
@ -208,6 +208,8 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
|||
protected function fillFromRow($row)
|
||||
{
|
||||
foreach ($row as $key => $val) {
|
||||
|
||||
|
||||
if (! empty($this->fillPrefix)) {
|
||||
if (! preg_match("/^" . $this->fillPrefix . "/", $key)) {
|
||||
continue;
|
||||
|
@ -447,6 +449,16 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
|||
}
|
||||
}
|
||||
|
||||
public static function qGetSql() : sql
|
||||
{
|
||||
return (new static())->getSql();
|
||||
}
|
||||
|
||||
public static function qGetSqlSelectTemplate() : string
|
||||
{
|
||||
return (new static())->__sqlSelectTemplate;
|
||||
}
|
||||
|
||||
public function getSql() : sql
|
||||
{
|
||||
$this->checkSql();
|
||||
|
@ -553,7 +565,7 @@ class baseClass extends dbStoredBase implements \JsonSerializable, jsonImportabl
|
|||
$where.=(empty($where)?"":" OR ")."`$key` like '%".common::clearInput($pattern)."'";
|
||||
break;
|
||||
|
||||
case "invCode":
|
||||
case "invcode":
|
||||
$where.=(empty($where)?"":" OR ")."`$key`='".UID::clear($pattern)."'";
|
||||
break;
|
||||
|
||||
|
|
|
@ -38,10 +38,8 @@ class common
|
|||
} else {
|
||||
$val = "";
|
||||
}
|
||||
if ($val == "") {
|
||||
if (isset($_GET[$name])) {
|
||||
$val = preg_replace('![^' . $regex . ']+!', '', $_GET[$name]);
|
||||
}
|
||||
if ($val == "" && isset($_GET[$name])) {
|
||||
$val = preg_replace('![^' . $regex . ']+!', '', $_GET[$name]);
|
||||
}
|
||||
} else {
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace fox;
|
|||
* @license GPLv3
|
||||
*
|
||||
*/
|
||||
class company extends baseClass
|
||||
class company extends baseClass implements externalCallable
|
||||
{
|
||||
|
||||
protected $id;
|
||||
|
@ -28,6 +28,13 @@ class company extends baseClass
|
|||
|
||||
public bool $deleted = false;
|
||||
|
||||
public const types=[
|
||||
"company",
|
||||
"client",
|
||||
"supplier",
|
||||
"partner"
|
||||
];
|
||||
|
||||
public static $sqlTable = "tblCompany";
|
||||
|
||||
public static $deletedFieldName = "deleted";
|
||||
|
@ -35,18 +42,26 @@ class company extends baseClass
|
|||
public static $sqlColumns = [
|
||||
"name" => [
|
||||
"type" => "VARCHAR(255)",
|
||||
"nullable" => false
|
||||
"nullable" => false,
|
||||
"search"=>"like"
|
||||
],
|
||||
"qName" => [
|
||||
"type" => "VARCHAR(255)",
|
||||
"nullable" => false
|
||||
"nullable" => false,
|
||||
"search"=>"like"
|
||||
],
|
||||
"description" => [
|
||||
"type" => "VARCHAR(255)"
|
||||
"type" => "VARCHAR(255)",
|
||||
"search"=>"like"
|
||||
],
|
||||
"type" => [
|
||||
"type" => "VARCHAR(255)",
|
||||
"nullable" => false
|
||||
],
|
||||
"invCode"=> [
|
||||
"type"=>"CHAR(10)",
|
||||
"nullable"=>false,
|
||||
"search"=>"invCode"
|
||||
]
|
||||
];
|
||||
|
||||
|
@ -57,10 +72,98 @@ class company extends baseClass
|
|||
|
||||
protected function validateSave()
|
||||
{
|
||||
if (empty($this->name)) { foxException::throw(foxException::STATUS_ERR, "Empty name not allowed", 406, "ENNA"); }
|
||||
if (empty($this->qName)) { foxException::throw(foxException::STATUS_ERR, "Empty qName not allowed", 406, "EQNA"); }
|
||||
if (array_search($this->type, $this::types)===false) { foxException::throw(foxException::STATUS_ERR, "Invalid type", 406, "ITNA"); }
|
||||
if ($this->invCode->isNull()) {
|
||||
$this->invCode->issue("core", get_class($this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
### REST API
|
||||
public static function API_GET(request $request) {
|
||||
if (!empty($request->parameters)) {
|
||||
throw new foxException("Invalid request",400);
|
||||
}
|
||||
$request->blockIfNoAccess("viewCompanies");
|
||||
return new static(common::clearInput($request->function));
|
||||
}
|
||||
|
||||
public static function API_DELETE(request $request) {
|
||||
if (!empty($request->parameters)) {
|
||||
throw new foxException("Invalid request",400);
|
||||
}
|
||||
$request->blockIfNoAccess("adminCompanies");
|
||||
$c = new static(common::clearInput($request->function));
|
||||
$c->delete();
|
||||
foxRequestResult::throw("201", "Deleted");
|
||||
}
|
||||
|
||||
public static function API_GET_list(request $request) {
|
||||
if (!empty($request->parameters)) {
|
||||
throw new foxException("Invalid request",400);
|
||||
}
|
||||
$request->blockIfNoAccess("viewCompanies");
|
||||
return static::search();
|
||||
}
|
||||
|
||||
public static function API_GET_types(request $request) {
|
||||
if (!empty($request->parameters)) {
|
||||
throw new foxException("Invalid request",400);
|
||||
}
|
||||
$request->blockIfNoAccess("viewCompanies");
|
||||
return static::types;
|
||||
}
|
||||
|
||||
public static function API_PUT(request $request) {
|
||||
if (!empty($request->parameters)) {
|
||||
throw new foxException("Invalid request",400);
|
||||
}
|
||||
$request->blockIfNoAccess("adminCompanies");
|
||||
$c=new static();
|
||||
$c->name=$request->requestBody->name;
|
||||
$c->qName=$request->requestBody->qName;
|
||||
$c->description=$request->requestBody->description;
|
||||
$c->type=$request->requestBody->type;
|
||||
$c->save();
|
||||
return $c;
|
||||
}
|
||||
|
||||
public static function API_PATCH(request $request) {
|
||||
if (!empty($request->parameters)) {
|
||||
throw new foxException("Invalid request",400);
|
||||
}
|
||||
$request->blockIfNoAccess("adminCompanies");
|
||||
$c=new static(common::clearInput($request->function,"0-9"));
|
||||
$c->name=$request->requestBody->name;
|
||||
$c->qName=$request->requestBody->qName;
|
||||
$c->description=$request->requestBody->description;
|
||||
$c->type=$request->requestBody->type;
|
||||
$c->save();
|
||||
return $c;
|
||||
}
|
||||
|
||||
public static function API_POST_search(request $request) {
|
||||
$request->blockIfNoAccess("viewCompanies");
|
||||
$opts=[];
|
||||
$pattern=null;
|
||||
if (property_exists($request->requestBody, "pattern")) {
|
||||
$pattern=$request->requestBody->pattern;
|
||||
}
|
||||
|
||||
$pagesize=null;
|
||||
if (property_exists($request->requestBody, "pageSize")) {
|
||||
$pagesize=common::clearInput($request->requestBody->pageSize,"0-9");
|
||||
}
|
||||
|
||||
$page=1;
|
||||
if (property_exists($request->requestBody, "page")) {
|
||||
$page=common::clearInput($request->requestBody->page,"0-9");
|
||||
}
|
||||
|
||||
return static::search($pattern, $pagesize, $page, $opts);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -19,13 +19,73 @@ class foxException extends \Exception
|
|||
protected $status = "ERR";
|
||||
|
||||
public const STATUS_ERR = "ERR";
|
||||
|
||||
public const STATUS_WARN = "WARN";
|
||||
|
||||
public const STATUS_ALERT = "ALERT";
|
||||
|
||||
public const STATUS_INFO = "INFO";
|
||||
|
||||
public const HTTPCodeNames = [
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
102 => 'Processing',
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
207 => 'Multi-status',
|
||||
208 => 'Already Reported',
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
306 => 'Switch Proxy',
|
||||
307 => 'Temporary Redirect',
|
||||
308 => 'Permanent Redirect',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Time-out',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Large',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested range not satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
418 => 'I\'m a teapot',
|
||||
422 => 'Unprocessable Entity',
|
||||
423 => 'Locked',
|
||||
424 => 'Failed Dependency',
|
||||
425 => 'Unordered Collection',
|
||||
426 => 'Upgrade Required',
|
||||
428 => 'Precondition Required',
|
||||
429 => 'Too Many Requests',
|
||||
431 => 'Request Header Fields Too Large',
|
||||
451 => 'Unavailable For Legal Reasons',
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Time-out',
|
||||
505 => 'HTTP Version not supported',
|
||||
506 => 'Variant Also Negotiates',
|
||||
507 => 'Insufficient Storage',
|
||||
508 => 'Loop Detected',
|
||||
510 => 'Not Extended',
|
||||
511 => 'Network Authentication Required',
|
||||
];
|
||||
|
||||
public static function throw($status, $message, $code, $xCode=null, $prev = null)
|
||||
{
|
||||
$e = new self($message, $code, $prev);
|
||||
|
|
|
@ -13,7 +13,7 @@ class langPack {
|
|||
|
||||
public static function get($key, $lang=null) {
|
||||
$ref=explode(".",$key);
|
||||
if (empty($lang)) { $lang = config::get("DEFAULT_LANGUAGE"); };
|
||||
if (empty($lang)) { $lang = config::get("DEFAULT_LANGUAGE"); }
|
||||
if (empty($lang)) { $lang = "ru"; }
|
||||
|
||||
$mod=moduleInfo::getByInstance($ref[0]);
|
||||
|
|
|
@ -177,8 +177,7 @@ class mailAccount extends baseClass implements externalCallable {
|
|||
if (! $request->user->checkAccess("adminMailAccounts", "core")) {
|
||||
throw new foxException("Forbidden", 403);
|
||||
}
|
||||
$m=new static(common::clearInput($request->function,"0-9"));
|
||||
return $m;
|
||||
return new static(common::clearInput($request->function,"0-9"));
|
||||
}
|
||||
|
||||
public static function APIX_GET_setDefault(request $request) {
|
||||
|
|
|
@ -41,6 +41,8 @@ class modules implements externalCallable
|
|||
"adminUserGroups"=>"Manage userGroups",
|
||||
"adminMailAccounts"=>"Manage system mail accounts",
|
||||
"adminAuthMethods"=>"Manage auth methods",
|
||||
"viewCompanies"=>"View companies",
|
||||
"adminCompanies"=>"Manage companies",
|
||||
],
|
||||
"configKeys"=> [
|
||||
"converterURL"=>"FoxConverter URL prefix",
|
||||
|
@ -80,6 +82,14 @@ class modules implements externalCallable
|
|||
"function" => "groups",
|
||||
"pageKey" => "adminGrous"
|
||||
],
|
||||
[
|
||||
"title" => [
|
||||
"ru" => "Компании",
|
||||
"en" => "Companies"
|
||||
],
|
||||
"function" => "comps",
|
||||
"pageKey" => "adminComps"
|
||||
],
|
||||
[
|
||||
"title" => [
|
||||
"ru" => "Учетные записи почты",
|
||||
|
|
|
@ -173,5 +173,13 @@ class request extends baseClass implements noSqlMigration
|
|||
}
|
||||
return $__foxRequest;
|
||||
}
|
||||
|
||||
public function blockIfNoAccess(string $rule, string $modInstance=null) {
|
||||
if ($modInstance==null) { $modInstance=$this->instance; }
|
||||
if (! $this->user->checkAccess($rule, $modInstance)) {
|
||||
throw new foxException("Forbidden", 403);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -16,44 +16,23 @@ class user extends baseClass implements externalCallable
|
|||
{
|
||||
|
||||
protected $id;
|
||||
|
||||
public $login;
|
||||
|
||||
protected UID $invCode;
|
||||
|
||||
protected $__secret;
|
||||
|
||||
public $authType;
|
||||
|
||||
public $authRefId;
|
||||
|
||||
public int $offlineAuthCtr = 0;
|
||||
|
||||
public $fullName;
|
||||
|
||||
protected bool $active = true;
|
||||
|
||||
protected bool $deleted = false;
|
||||
|
||||
public string $uiTheme = "default";
|
||||
|
||||
public $companyId;
|
||||
|
||||
public $eMail;
|
||||
|
||||
public bool $eMailConfirmed = false;
|
||||
|
||||
protected array $settings = [
|
||||
"pagesize" => 30
|
||||
];
|
||||
|
||||
protected array $config = [];
|
||||
protected ?company $__company = null;
|
||||
|
||||
|
||||
protected static $excludeProps = ["settings","authRefId"];
|
||||
|
||||
protected static $excludeProps = ["authRefId"];
|
||||
public static $sqlTable = "tblUsers";
|
||||
|
||||
public static $deletedFieldName = "deleted";
|
||||
|
||||
public static $sqlColumns = [
|
||||
|
@ -300,6 +279,13 @@ class user extends baseClass implements externalCallable
|
|||
return true;
|
||||
}
|
||||
|
||||
public function export() {
|
||||
$rv=parent::export();
|
||||
$rv["config"]=(object)$this->config;
|
||||
return $rv;
|
||||
}
|
||||
|
||||
### REST API
|
||||
public static function API_GET_list(request $request)
|
||||
{
|
||||
if (! $request->user->checkAccess("adminUsers", "core")) {
|
||||
|
@ -313,7 +299,7 @@ class user extends baseClass implements externalCallable
|
|||
throw new foxException("Forbidden", 403);
|
||||
}
|
||||
$pageSize=common::clearInput($request->requestBody->pageSize,"0-9");
|
||||
if (empty($pageSize)) { $pageSize=$request->user->settings["pageSize"];}
|
||||
if (empty($pageSize)) { $pageSize=$request->user->config["pageSize"];}
|
||||
|
||||
return static::search(common::clearInput($request->requestBody->pattern), $pageSize)->result;
|
||||
|
||||
|
|
|
@ -136,6 +136,15 @@ class userGroup extends baseClass implements externalCallable
|
|||
return true;
|
||||
}
|
||||
|
||||
public function isMember(user $user) {
|
||||
foreach (userGroupMembership::getUsersInGroup($this, $this->sql) as $ugm) {
|
||||
if ($ugm->user->id == $user->id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addAccessRule(string $rule, string $modInstance = "<all>")
|
||||
{
|
||||
if (array_key_exists($modInstance, $this->accessRules) && (array_search($rule, $this->accessRules[$modInstance]) !== false)) {
|
||||
|
|
|
@ -135,7 +135,7 @@ class userGroupMembership extends baseClass implements externalCallable
|
|||
if (empty($page) || !(is_numeric($page))) {$page=0;}
|
||||
|
||||
@$pageSize=common::clearInput($request->requestBody->pageSize);
|
||||
if (empty($pageSize) || !(is_numeric($pageSize))) {$pageSize=$request->user->settings["pageSize"];}
|
||||
if (empty($pageSize) || !(is_numeric($pageSize))) {$pageSize=$request->user->config["pageSize"];}
|
||||
|
||||
if (!empty($request->requestBody->userId)) {
|
||||
$user = new user($userId=common::clearInput($request->requestBody->userId,"0-9"));
|
||||
|
|
|
@ -12,5 +12,7 @@
|
|||
<script src="/static/js/core/fox-common.js"></script>
|
||||
<script type="module" src="/static/js/core/main.js"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
<body>
|
||||
<div style="margin-left: auto; margin-right: auto; margin-top: 20px; padding: 20px; width: 500px; border-radius: 10px; border: 1px solid #FF350040; color: #FF350040; font-size: 30px; font-family: monospace, monospace; mono" id="jsNotStartedStub">JavaScript is not supported in your browser or has not been loaded yet. Wait a few minutes and if it doesn't help, try another browser.</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -40,7 +40,7 @@ export function exec(requestType, method , data, onSuccess,noblank,onError,versi
|
|||
data: JSON.stringify(data),
|
||||
type: requestType,
|
||||
headers: headers,
|
||||
|
||||
async: ref.async==undefined?true:ref.async,
|
||||
complete: function(data,textStatus,request) {
|
||||
if (data.getResponseHeader('X-Fox-Token-Renew') !=null) {
|
||||
session.updateToken(data.getResponseHeader('X-Fox-Token-Renew'));
|
||||
|
@ -164,6 +164,19 @@ export class auth {
|
|||
}
|
||||
|
||||
export class session {
|
||||
static getConfigItem(item) {
|
||||
let user=this.get("user");
|
||||
if (user && user.config && user.config[item]) {
|
||||
return user.config[item];
|
||||
} else {
|
||||
return settings.get(item);
|
||||
}
|
||||
}
|
||||
|
||||
static getLang() {
|
||||
return this.getConfigItem("language");
|
||||
}
|
||||
|
||||
static close() {
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("tokenExpire");
|
||||
|
@ -203,6 +216,14 @@ export class session {
|
|||
return session.get("menu");
|
||||
}
|
||||
}
|
||||
static checkAccess(rule, module) {
|
||||
let acls=this.get("acls");
|
||||
if (module==undefined) { module="core"; }
|
||||
if (acls[module]!=undefined && Object.values(acls[module]).includes(rule)) { return true; }
|
||||
else if (acls["<all>"]!=undefined && acls["<all>"].includes(rule)) { return true; }
|
||||
else if (acls["<all>"]!=undefined && acls["<all>"].includes("isRoot")) { return true; }
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
static getModInstances() {
|
||||
if (session.get("modInstances") == undefined) {
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
export async function load() {
|
||||
|
||||
UI.breadcrumbsUpdate($("<span>",{text: langPack.core.breadcrumbs.modTitle+" / "+langPack.core.iface.companies}));
|
||||
UI.createTabsPanel([
|
||||
{id: "comps", title: langPack.core.iface.companies , preLoad: reloadCompanies, buttons: UI.addButton({id: "btnCompAdd", icon: "fas fa-plus", title: langPack.core.iface.add, onClick: btnCmpAdd_Click})}
|
||||
]);
|
||||
}
|
||||
|
||||
async function reloadCompanies() {
|
||||
await API.exec("GET", "core/company/list", {}, function(json,_textStatus) {
|
||||
$("#comps").empty();
|
||||
|
||||
let dt=$("<table>",{class: "datatable sel"}).appendTo("#comps");
|
||||
let trh=$("<tr>").appendTo(dt);
|
||||
|
||||
$("<th>",{class: "idx", text: "#"}).appendTo(trh);
|
||||
$("<th>",{class: "code", text: langPack.core.iface.uid}).appendTo(trh);
|
||||
$("<th>",{text: langPack.core.iface.type}).appendTo(trh);
|
||||
$("<th>",{text: langPack.core.iface.title}).appendTo(trh);
|
||||
$("<th>",{text: langPack.core.iface.comps.qName}).appendTo(trh);
|
||||
$("<th>",{text: langPack.core.iface.desc}).appendTo(trh);
|
||||
$("<th>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})}).appendTo(trh);
|
||||
|
||||
$.each(json.data.result,function(key,val) {
|
||||
let trd=$("<tr>").appendTo(dt).bind('contextmenu', usmContextMenuOpen).addClass("contextMenu").attr("compId",val.id).attr("compUid",val.invCode);
|
||||
|
||||
$("<td>",{class: "idx", text: key}).appendTo(trd);
|
||||
$("<td>",{class: "code", text: UI.formatInvCode(val.invCode)}).appendTo(trd);
|
||||
$("<td>",{text: langPack.core.iface.comps[val.type]}).appendTo(trd);
|
||||
$("<td>",{text: val.name}).appendTo(trd);
|
||||
$("<td>",{text: val.qName}).appendTo(trd);
|
||||
$("<td>",{text: val.description}).appendTo(trd);
|
||||
|
||||
$("<td>",{class: "button", style: "text-align: center", append: $("<i>",{class: "fas fa-ellipsis-h"})})
|
||||
.click(usmContextMenuOpen)
|
||||
.appendTo(trd);
|
||||
|
||||
});
|
||||
},false);
|
||||
}
|
||||
|
||||
function usmContextMenuOpen(el) {
|
||||
|
||||
let uid=$(el.target).closest("tr").attr("compUid");
|
||||
UI.contextMenuOpen(el,[
|
||||
{title: langPack.core.iface.edit, onClick: function() {
|
||||
compEdit_Click(el);
|
||||
}},
|
||||
{title: langPack.core.iface.delete, onClick: function() {
|
||||
compDel_Click(el);
|
||||
}},
|
||||
|
||||
],"#"+UI.formatInvCode(uid));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function compDel_Click(ref) {
|
||||
var id=($(ref.target).closest("tr").attr("compId"));
|
||||
var uid=($(ref.target).closest("tr").attr("compUid"));
|
||||
var buttons={};
|
||||
buttons[langPack.core.iface.dialodDelButton]=function() {
|
||||
$("#dialogInfo").dialog("close");
|
||||
API.exec({
|
||||
requestType: "DELETE",
|
||||
method: "core/company/"+id,
|
||||
onSuccess: function(json) {
|
||||
reloadCompanies();
|
||||
},
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() { $("#dialogInfo").dialog("close"); }
|
||||
|
||||
UI.showInfoDialog(langPack.core.iface.groups.delButtonTitle+" #"+uid+" "+$(ref.target).closest("tr").attr("xname"),langPack.core.iface.groups.delButtonTitle,buttons);
|
||||
}
|
||||
|
||||
async function compEdit_Click(el) {
|
||||
let id=$(el.currentTarget).closest("tr").attr("compId");
|
||||
var buttons={};
|
||||
buttons[langPack.core.iface.dialodAddButton]=function() {
|
||||
|
||||
let data=UI.collectForm("ItemAdd", true,false, false,true);
|
||||
|
||||
if (data.validateErrCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let vals=data.getVals();
|
||||
API.exec("PATCH",UI.parceURL().module+"/company/"+id,vals, function onAjaxSuccess(json,_textStatus) {
|
||||
UI.closeDialog('ItemAdd');
|
||||
reloadCompanies();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() { UI.closeDialog('ItemAdd'); }
|
||||
|
||||
UI.createDialog(
|
||||
UI.addFieldGroup([
|
||||
UI.addField({title: langPack.core.iface.title, item: "cao_name", type: "input",reqx: true}),
|
||||
UI.addField({title: langPack.core.iface.comps.qName, item: "cao_qName", type: "input",reqx: true}),
|
||||
UI.addField({title: langPack.core.iface.desc, item: "cao_description", type: "input"}),
|
||||
UI.addField({title: langPack.core.iface.type, item: "cao_type", type: "select", reqx: true, args: [
|
||||
{val:"",title: ""},
|
||||
{val:"company",title: langPack.core.iface.comps.company},
|
||||
{val:"client",title: langPack.core.iface.comps.client},
|
||||
{val:"supplier",title: langPack.core.iface.comps.supplier},
|
||||
{val:"parner",title: langPack.core.iface.comps.partner},
|
||||
]}),
|
||||
]),
|
||||
langPack.core.iface.edit,
|
||||
buttons,
|
||||
350,1,'ItemAdd'
|
||||
);
|
||||
|
||||
await API.exec("GET",UI.parceURL().module+"/company/"+id,{}, function onAjaxSuccess(json,_textStatus) {
|
||||
$("#cao_name").val(json.data.name);
|
||||
$("#cao_qName").val(json.data.qName);
|
||||
$("#cao_description").val(json.data.description);
|
||||
$("#cao_type").val(json.data.type);
|
||||
|
||||
});
|
||||
|
||||
UI.openDialog('ItemAdd');
|
||||
}
|
||||
|
||||
function btnCmpAdd_Click(ref) {
|
||||
var buttons={};
|
||||
buttons[langPack.core.iface.dialodAddButton]=function() {
|
||||
|
||||
let data=UI.collectForm("ItemAdd", true,false, false,true);
|
||||
if (data.validateErrCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let vals=data.getVals();
|
||||
API.exec("PUT",UI.parceURL().module+"/company",vals, function onAjaxSuccess(json,_textStatus) {
|
||||
UI.closeDialog('ItemAdd');
|
||||
reloadCompanies();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
buttons[langPack.core.iface.dialodCloseButton]=function() { UI.closeDialog('ItemAdd'); }
|
||||
|
||||
UI.createDialog(
|
||||
UI.addFieldGroup([
|
||||
UI.addField({title: langPack.core.iface.title, item: "cao_name", type: "input",reqx: true}),
|
||||
UI.addField({title: langPack.core.iface.comps.qName, item: "cao_qName", type: "input",reqx: true}),
|
||||
UI.addField({title: langPack.core.iface.desc, item: "cao_description", type: "input"}),
|
||||
UI.addField({title: langPack.core.iface.type, item: "cao_type", type: "select", reqx: true, args: [
|
||||
{val:"",title: ""},
|
||||
{val:"company",title: langPack.core.iface.comps.company},
|
||||
{val:"client",title: langPack.core.iface.comps.client},
|
||||
{val:"supplier",title: langPack.core.iface.comps.supplier},
|
||||
{val:"parner",title: langPack.core.iface.comps.partner},
|
||||
]}),
|
||||
]),
|
||||
langPack.core.iface.add,
|
||||
buttons,
|
||||
350,1,'ItemAdd'
|
||||
);
|
||||
|
||||
UI.openDialog('ItemAdd');
|
||||
}
|
|
@ -12,6 +12,7 @@ export var menuSelector={
|
|||
"group":"adminGrous",
|
||||
mailAccounts:"mailAccounts",
|
||||
oauth: "oauth",
|
||||
comps: "adminComps"
|
||||
};
|
||||
|
||||
export function load() {
|
||||
|
@ -72,6 +73,12 @@ export function load() {
|
|||
})
|
||||
break;
|
||||
|
||||
case "comps":
|
||||
import("./coreComps.js").then(function(mod) {
|
||||
mod.load();
|
||||
})
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new Error(404);
|
||||
|
|
|
@ -18,6 +18,8 @@ export var langItem={
|
|||
notImplementedYet: "Функция не реализована",
|
||||
generalError: "Ошибка",
|
||||
active: "Активен",
|
||||
user: "Пользователь",
|
||||
group: "Группа",
|
||||
version: "Версия",
|
||||
title: "Наименование",
|
||||
url: "URL",
|
||||
|
@ -26,7 +28,10 @@ export var langItem={
|
|||
install: "Установить",
|
||||
set: "Установить",
|
||||
edit: "Изменить",
|
||||
copy: "Копировать",
|
||||
paste: "Вставить",
|
||||
updated: "Обновлен",
|
||||
reload: "Обновить",
|
||||
invCode: "invCode",
|
||||
dialodCloseButton: "Закрыть",
|
||||
dialodDelButton: "Удалить",
|
||||
|
@ -43,6 +48,8 @@ export var langItem={
|
|||
dialogReсoveryTitle: "Восстановление доступа",
|
||||
genDescTitle: "Информация",
|
||||
contextMenuCopySelected: "Копировать выделение",
|
||||
contextMenu: "Открыть действия",
|
||||
actions: "Действия",
|
||||
language:"Язык",
|
||||
yes: "Да",
|
||||
no: "Нет",
|
||||
|
@ -61,6 +68,18 @@ export var langItem={
|
|||
confCodeFmtErr: "Неверный формат кода подтверждения",
|
||||
recoverFormEmtyX: "Должно быть заполнено одно из полей",
|
||||
oauthLoginFailedUNR: "Пользователь не зарегистрирован в системе. Для продолжения работы нужно зарегистрироваться на начальной странице.",
|
||||
type: "Тип",
|
||||
types: "Типы",
|
||||
company: "Компания",
|
||||
companies: "Компании",
|
||||
uid: "UID",
|
||||
comps: {
|
||||
qName: "Алиас",
|
||||
company: "Компания",
|
||||
client: "Клиент",
|
||||
supplier: "Поставщик",
|
||||
partner: "Партнёр",
|
||||
},
|
||||
modules: {
|
||||
installedTabTitle: "Установленные",
|
||||
availTabTitle: "Все доступные",
|
||||
|
|
|
@ -20,7 +20,7 @@ export async function lpInit () {
|
|||
API = mod;
|
||||
});
|
||||
|
||||
var lang=API.settings.get("language");
|
||||
var lang=API.session.getLang();
|
||||
console.log("load "+lang+" language...");
|
||||
|
||||
let modules=[];
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import * as API from './api.js';
|
||||
import * as UI from './ui.js';
|
||||
$("#jsNotStartedStub").remove();
|
||||
|
||||
import { lpInit } from './langpack.js';
|
||||
import { foxMenu } from './ui.menu.js';
|
||||
|
||||
|
||||
var popState_Installed=false;
|
||||
|
||||
$(document).ready(function() {
|
||||
$(document).ready(async function() {
|
||||
let i=0;
|
||||
while (UI ==undefined || API ==undefined) {
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
}
|
||||
|
||||
load();
|
||||
});
|
||||
|
||||
|
@ -20,7 +26,7 @@ export function boot(xlite) {
|
|||
if (xlite==undefined) { xlite=false; }
|
||||
if (!xlite) {
|
||||
UI.setTitle(API.settings.get("title"));
|
||||
UI.loadCSS("/static/theme/"+API.settings.get("theme")+"/main.css");
|
||||
UI.loadCSS("/static/theme/"+API.session.getConfigItem("theme")+"/main.css");
|
||||
}
|
||||
UI.contextMenuClose();
|
||||
|
||||
|
|
|
@ -118,18 +118,22 @@ export function empty() {
|
|||
*/
|
||||
|
||||
export function createLeftPanel(panels) {
|
||||
$("<div>", { class: "widget_panel_left" }).appendTo(".t_main #mainframe");
|
||||
let ref=($(".t_main #mainframe div.widget_panel_left"));
|
||||
if (ref.length==0) {
|
||||
ref=$("<div>", { class: "widget_panel_left" }).appendTo(".t_main #mainframe");
|
||||
} else {
|
||||
ref.empty();
|
||||
}
|
||||
|
||||
var divAccord=$("<div>",{
|
||||
id: "accordion",
|
||||
class: "accordion"
|
||||
}).appendTo(".widget_panel_left");
|
||||
}).appendTo(ref);
|
||||
|
||||
|
||||
$.each(panels,function (index,panel) {
|
||||
|
||||
let px = $("<h3>",{text: panel.title, append: panel.buttons })
|
||||
.add($("<div>", { class: "widget lock c_contacts", id: "gendesc", text: langPack.core.iface.dataLoading}));
|
||||
let px = $("<h3>",{text: panel.title, id: panel.id+"_title", append: panel.buttons, style: panel.disabled?"display: none":"" })
|
||||
.add($("<div>", { class: "widget lock c_contacts", id: panel.id, text: langPack.core.iface.dataLoading, style: panel.disabled?"display: none":""}));
|
||||
|
||||
px.appendTo(divAccord);
|
||||
});
|
||||
|
@ -159,13 +163,18 @@ function panelActivate(panel, callback) {
|
|||
}
|
||||
|
||||
export function createRightPanel(panels) {
|
||||
let ref=$("<div>", { class: "widget_panel_right" }).appendTo(".t_main #mainframe");
|
||||
let ref=($(".t_main #mainframe div.widget_panel_right"));
|
||||
if (ref.length==0) {
|
||||
ref=$("<div>", { class: "widget_panel_right" }).appendTo(".t_main #mainframe");
|
||||
}
|
||||
createTabsPanel(panels,ref);
|
||||
}
|
||||
|
||||
export function createTabsPanel(panels,ref) {
|
||||
if (ref===undefined) {
|
||||
ref=$(".t_main #mainframe");
|
||||
} else {
|
||||
ref.empty();
|
||||
}
|
||||
|
||||
var callback={};
|
||||
|
@ -226,6 +235,12 @@ export function createTabsPanel(panels,ref) {
|
|||
panelBeforeActivate(ui.newPanel,callback);
|
||||
}
|
||||
});
|
||||
|
||||
$.each(panels,function (_index,panel) {
|
||||
if (panel.disabled) {
|
||||
$( "#item_tabs").tabs("disable","#tab-"+panel.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -243,10 +258,10 @@ export function addFieldGroup(items)
|
|||
* }
|
||||
*/
|
||||
|
||||
export function addField(ref)//title, item, blockstyle, fieldstyle, type, args, onChange)
|
||||
export function addField(ref)//title, item, blockstyle, fieldstyle, type, args, onChange, onClick, onContextMenu)
|
||||
{
|
||||
var item=undefined;
|
||||
if (ref.type === undefined || ref.item===undefined) {
|
||||
if (ref.type === undefined || (ref.item===undefined && ref.type != "href")) {
|
||||
var type = 'label';
|
||||
} else {
|
||||
var type=ref.type;
|
||||
|
@ -338,7 +353,11 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
break;
|
||||
|
||||
case "label":
|
||||
item = $("<span>", {class: "i", html: ref.val});
|
||||
item = $("<span>", {id: ref.item, class: "i", html: ref.val});
|
||||
break;
|
||||
|
||||
case "href":
|
||||
item = $("<a>", {href: ref.href, id: ref.item, class: "i", html: ref.val, click: smartClick});
|
||||
break;
|
||||
|
||||
case "multiline":
|
||||
|
@ -396,7 +415,10 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
if (ref.disabled) { item.attr("disabled","true")}
|
||||
}
|
||||
|
||||
item.change(function() {$(this).addClass('changed');});
|
||||
item.change(function() {$(this).addClass('changed');})
|
||||
if (ref.attrs && ref.attrs.disabled) {
|
||||
item.attr("disabled",ref.attrs.disabled)
|
||||
}
|
||||
if (typeof(ref.onChange)=='function') {
|
||||
item.change(ref.onChange);
|
||||
}
|
||||
|
@ -423,6 +445,18 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
}))
|
||||
});
|
||||
|
||||
if (type=="label") {
|
||||
if (typeof(ref.onClick)=="function") {
|
||||
rv.click(ref.onClick);
|
||||
rv.addClass("clickable");
|
||||
|
||||
}
|
||||
if (typeof(ref.onContextMenu)=="function") {
|
||||
rv.bind('contextmenu click', ref.onContextMenu);
|
||||
rv.addClass("withContextMenu");
|
||||
}
|
||||
}
|
||||
|
||||
$.each(ref.attrs, function(key, val) {
|
||||
rv.attr(key,val);
|
||||
});
|
||||
|
@ -443,7 +477,13 @@ export function addField(ref)//title, item, blockstyle, fieldstyle, type, args,
|
|||
}
|
||||
|
||||
export function breadcrumbsUpdate(text) {
|
||||
$("#breadcrumbs_label").text(text);
|
||||
if (typeof(text)=="string") {
|
||||
$("#breadcrumbs_label").text(text);
|
||||
} else {
|
||||
$("#breadcrumbs_label").empty();
|
||||
$("#breadcrumbs_label").append(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function breadcrumbsUpdateSuffix(text) {
|
||||
|
@ -885,7 +925,7 @@ export function contextMenuOpen(event, itemsList, title) {
|
|||
$("body").unbind('contextmenu click', contextMenuClose);
|
||||
let selText = getSelectionText();
|
||||
$("div#contextMenu").empty();
|
||||
$("<p>",{class: "title cmTitle", text: title}).appendTo("div#contextMenu");
|
||||
if (isset(title)) { $("<p>",{class: "title cmTitle", text: title}).appendTo("div#contextMenu"); }
|
||||
let items=$("<div>",{class: "items"}).appendTo("div#contextMenu");
|
||||
|
||||
if (isset(selText)) {
|
||||
|
@ -1110,9 +1150,15 @@ Number.prototype.pad = function(size) {
|
|||
href={href: href};
|
||||
}
|
||||
if (href.external==true) {
|
||||
this.click(function() { document.location.href=href.href; return false;});
|
||||
this.click(function() {
|
||||
if (getSelectionText()) { return; }
|
||||
document.location.href=href.href; return false;
|
||||
});
|
||||
} else {
|
||||
this.prop("href",href.href).click(xClick);
|
||||
this.prop("href",href.href).click(function(ref) {
|
||||
if (getSelectionText()) { return; }
|
||||
xClick(ref);
|
||||
});
|
||||
}
|
||||
this.addClass("clickable");
|
||||
$.each(this.find("td"),function(key,val) {
|
||||
|
@ -1122,5 +1168,15 @@ Number.prototype.pad = function(size) {
|
|||
}
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
onEnter: function(callback) {
|
||||
if (typeof(callback)=="function") {
|
||||
this.on('keyup', function (e) {
|
||||
if (e.key === 'Enter' || e.keyCode === 13) {
|
||||
callback(this);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})})(jQuery)
|
|
@ -16,10 +16,11 @@ export class foxMenu {
|
|||
href: "logout"
|
||||
};
|
||||
foxMenu.drawMenuNode(items,$("#menu_base_1"));
|
||||
foxMenu.menuClose();
|
||||
}
|
||||
|
||||
static drawMenuNode(items,ref,deep,lang, xmodkey) {
|
||||
if (lang==undefined) { lang=API.settings.get("language");}
|
||||
if (lang==undefined) { lang=API.session.getLang();}
|
||||
if (deep==undefined) { deep=0; }
|
||||
let xref=$("<ul>")
|
||||
.appendTo(ref);
|
||||
|
@ -28,6 +29,9 @@ export class foxMenu {
|
|||
|
||||
if (val.xmodkey!=undefined) { xmodkey=val.xmodkey; }
|
||||
|
||||
let aclMatch=(val.accessRule==undefined) || API.session.checkAccess(val.accessRule, xmodkey);
|
||||
if (!aclMatch) { return; }
|
||||
|
||||
let title=val.title[lang];
|
||||
if (title==undefined) { title=Object.values(val.title).shift();};
|
||||
let xlabel;
|
||||
|
@ -52,7 +56,6 @@ export class foxMenu {
|
|||
.append($("<i>",{ class: "fas fa-minus minus"}))
|
||||
.append(xlabel)
|
||||
)
|
||||
|
||||
.appendTo(xref)
|
||||
|
||||
if (deep==0) {
|
||||
|
@ -70,13 +73,7 @@ export class foxMenu {
|
|||
|
||||
}
|
||||
|
||||
static menuItemClick(ref,noExec) {
|
||||
|
||||
let xref=$(ref.target).closest("li");
|
||||
let xchilds=xref.children("ul").children("li");
|
||||
let xparents=xref.parents("li");
|
||||
let xroot=xref.parents("li.xmenu_root");
|
||||
|
||||
static menuClose() {
|
||||
$(".xmenu_dx").hide();
|
||||
|
||||
$(".xmenu").removeClass("xmenu_open")
|
||||
|
@ -84,6 +81,14 @@ export class foxMenu {
|
|||
.removeClass("xmenu_axtree")
|
||||
.addClass("xmenu_closed");
|
||||
|
||||
}
|
||||
static menuItemClick(ref,noExec) {
|
||||
|
||||
let xref=$(ref.target).closest("li");
|
||||
let xchilds=xref.children("ul").children("li");
|
||||
let xparents=xref.parents("li");
|
||||
let xroot=xref.parents("li.xmenu_root");
|
||||
foxMenu.menuClose();
|
||||
xref.addClass("xmenu_open")
|
||||
.addClass("xmenu_active")
|
||||
.removeClass("xmenu_closed")
|
||||
|
|
|
@ -148,7 +148,7 @@ table.datatable td.icon,
|
|||
table.datatable th.icon
|
||||
{
|
||||
width: 20px;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
@ -919,7 +919,8 @@ table.datatable td
|
|||
|
||||
table.datatable.sel tr.clickable,
|
||||
table.datatable.selm tbody.clickable,
|
||||
table.datatable.selm tr.ss.clickable {
|
||||
table.datatable.selm tr.ss.clickable,
|
||||
div.crm_entity_field_block.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -928,7 +929,8 @@ table.datatable.selm tbody.contextMenu,
|
|||
table.datatable.selm tr.ss.contextMenu,
|
||||
table.datatable.sel tr.contextMenu a,
|
||||
table.datatable.selm tbody.contextMenu a,
|
||||
table.datatable.selm tr.ss.contextMenu a {
|
||||
table.datatable.selm tr.ss.contextMenu a,
|
||||
div.crm_entity_field_block.withContextMenu {
|
||||
cursor: context-menu;
|
||||
}
|
||||
|
||||
|
@ -1675,9 +1677,11 @@ table.datatable td.code
|
|||
color: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
table.datatable th.code
|
||||
table.datatable th.code,
|
||||
table.datatable td.code
|
||||
{
|
||||
min-width: 110px;
|
||||
width: 105px;
|
||||
}
|
||||
table.datatable td.comment
|
||||
{
|
||||
|
@ -2182,11 +2186,6 @@ td.hideable, th.hideable
|
|||
display: none;
|
||||
}
|
||||
|
||||
table.datatable th.code
|
||||
{
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
td.hideablealt, th.hideablealt
|
||||
{
|
||||
display: table-cell;
|
||||
|
|
Loading…
Reference in New Issue