Compare commits
4
Commits
8d24759a15
...
c0c8a2531c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0c8a2531c | ||
|
|
c5e17ca57a | ||
|
|
37c5f0c500 | ||
|
|
a36e501596 |
No files matched your search
Generated
+216
-250
@@ -25,6 +25,21 @@
|
||||
"pkg": "^5.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz",
|
||||
"integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.18.2",
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
|
||||
@@ -45,6 +60,34 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.18.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz",
|
||||
"integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz",
|
||||
"integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.18.10",
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||
@@ -123,9 +166,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.0.tgz",
|
||||
"integrity": "sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==",
|
||||
"version": "26.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.3.0.tgz",
|
||||
"integrity": "sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
@@ -274,9 +317,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/better-sqlite3": {
|
||||
"version": "11.3.0",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.3.0.tgz",
|
||||
"integrity": "sha512-iHt9j8NPYF3oKCNOO5ZI4JwThjt3Z6J6XrcwG85VNMVzv1ByqrHWv5VILEbCMFWDsoHhXvQ7oC8vgRXFAKgl9w==",
|
||||
"version": "11.10.0",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz",
|
||||
"integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -304,6 +347,20 @@
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bl/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.6",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz",
|
||||
@@ -585,15 +642,6 @@
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
@@ -904,45 +952,28 @@
|
||||
"readable-stream": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/from2/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/from2/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/from2/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -1224,6 +1255,23 @@
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/into-stream": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz",
|
||||
"integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"from2": "^2.3.0",
|
||||
"p-is-promise": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
@@ -1234,16 +1282,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.2",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
|
||||
"integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
|
||||
"integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -1305,6 +1350,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
|
||||
@@ -1399,19 +1457,6 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch/node_modules/picomatch": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
@@ -1503,20 +1548,34 @@
|
||||
"readable-stream": "^3.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multistream/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.22.5",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.22.5.tgz",
|
||||
"integrity": "sha512-95uZ2TrPWAZdwpB3vvvDbmEMcNG8yIeNCyu6GUcr/QnWEE/wXm7+mhOCsdQfWQDTV7qYT/PDUZ4U4UPP4AsXqQ==",
|
||||
"version": "3.24.2",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.24.2.tgz",
|
||||
"integrity": "sha512-l9kXeKGwd6VCbSjmpO/bLWb+YCYpbvE4whte8ec6InXebvCNyEEydyRCnRU+TSHNqRLJ8B+Tk1uWb+vMCJgJzA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"aws-ssl-profiles": "^1.1.2",
|
||||
"denque": "^2.1.0",
|
||||
"generate-function": "^2.3.1",
|
||||
"iconv-lite": "^0.7.2",
|
||||
"iconv-lite": "^0.7.3",
|
||||
"long": "^5.3.2",
|
||||
"lru.min": "^1.1.4",
|
||||
"named-placeholders": "^1.1.6",
|
||||
"sql-escaper": "^1.3.3"
|
||||
"sql-escaper": "^1.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
@@ -1569,9 +1628,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.94.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.94.0.tgz",
|
||||
"integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==",
|
||||
"version": "3.95.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.95.0.tgz",
|
||||
"integrity": "sha512-T9iGctuocf0qIWFFOTxPzjT5q0SILqaBYXt272tlBHvTKC5+3JnkMirLxNJNkXHtFyBjU2Jx+NL4Zipr0B/c6Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
@@ -1602,9 +1661,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.3.tgz",
|
||||
"integrity": "sha512-n+YP+NKwR5zRWa60k3GiQ6Q3B4KXCoAw40dAKeCtYn020iNN74aWK2liXIC3ZEATeGql7we3tE3t8QwhY0eskw==",
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.5.tgz",
|
||||
"integrity": "sha512-wvjiKvjczmsN7U/8006JOdXubgBk2XFAbioDMbT+sM7cPs0QrhJTa6KBRX7P5REGGkDcLUz/EarWidb8G8C1jQ==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@@ -1695,14 +1754,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz",
|
||||
"integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.23.0.tgz",
|
||||
"integrity": "sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.14.0",
|
||||
"pg-pool": "^3.14.0",
|
||||
"pg-protocol": "^1.15.0",
|
||||
"pg-protocol": "^1.16.0",
|
||||
"pg-types": "2.2.0",
|
||||
"pgpass": "1.0.5"
|
||||
},
|
||||
@@ -1753,9 +1812,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz",
|
||||
"integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==",
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.16.0.tgz",
|
||||
"integrity": "sha512-sILXutLVjCLjcDuOmvhX5e2Z4cS5qG/6Bu3VkpFwdf/633ElGLpEh9bgmuI5I4sqKqkifQiGyiCcx1HdtrK7tg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
@@ -1783,6 +1842,19 @@
|
||||
"split2": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg": {
|
||||
"version": "5.8.1",
|
||||
"resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.1.tgz",
|
||||
@@ -1837,124 +1909,6 @@
|
||||
"pkg-fetch": "lib-es5/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-fetch/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/@babel/generator": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz",
|
||||
"integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.18.2",
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/@babel/parser": {
|
||||
"version": "7.18.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz",
|
||||
"integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/@babel/types": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz",
|
||||
"integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.18.10",
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/into-stream": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz",
|
||||
"integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"from2": "^2.3.0",
|
||||
"p-is-promise": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/is-core-module": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
|
||||
"integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jsesc": "bin/jsesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg/node_modules/napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
|
||||
@@ -2173,19 +2127,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
@@ -2218,6 +2181,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve/node_modules/is-core-module": {
|
||||
"version": "2.16.2",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
|
||||
"integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
|
||||
@@ -2479,9 +2458,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sql-escaper": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.3.3.tgz",
|
||||
"integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==",
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.5.1.tgz",
|
||||
"integrity": "sha512-4toX5E1fQbBrpfXidaHnF0669nkAdETeIPTs2SUjxxD7RRIs9ICG4gtpmfc68JCEKehsdwLFqBu9VlQqZ1P1gg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
@@ -2524,47 +2503,20 @@
|
||||
"readable-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-meter/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-meter/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stream-meter/node_modules/string_decoder": {
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
"node_modules/string_decoder/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
@@ -2657,6 +2609,20 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
||||
+2
-7
@@ -197,13 +197,8 @@
|
||||
<input type="text" class="search-input" id="global-search"
|
||||
placeholder="Cerca ticket (numero, titolo o corpo)..." style="padding-right: 32px;" />
|
||||
<button id="global-search-clear"
|
||||
style="position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; padding: 4px; cursor: pointer; color: var(--text-muted); display: none; align-items: center; justify-content: center;"
|
||||
title="Cancella ricerca">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
style="width:14px;height:14px;display:block;">
|
||||
<path d="M18 6L6 18M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
style="position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; padding: 0; cursor: pointer; color: var(--text-muted); display: none; align-items: center; justify-content: center; font-size: 13px; line-height: 1;"
|
||||
title="Cancella ricerca">✕</button>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm" id="topbar-new-ticket" onclick="window.location.hash='#/tickets/new'">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:16px;height:16px;">
|
||||
|
||||
+34
-12
@@ -163,12 +163,20 @@ const App = {
|
||||
searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const hash = window.location.hash;
|
||||
if (!hash.startsWith('#/tickets') || hash.includes('/new') || hash.match(/#\/tickets\/\d+/)) {
|
||||
window.location.hash = '#/tickets';
|
||||
const query = searchInput.value.trim();
|
||||
searchInput.value = '';
|
||||
toggleClearBtn();
|
||||
if (query) {
|
||||
const newHash = `#/ricerca-spudorata?q=${encodeURIComponent(query)}`;
|
||||
if (window.location.hash === newHash && typeof RicercaSpudorataView !== 'undefined') {
|
||||
const input = document.getElementById('spudorata-search-input');
|
||||
if (input) input.value = query;
|
||||
RicercaSpudorataView.executeSearch(query);
|
||||
} else {
|
||||
TicketListView.currentPage = 1;
|
||||
TicketListView.render();
|
||||
window.location.hash = newHash;
|
||||
}
|
||||
} else {
|
||||
window.location.hash = '#/ricerca-spudorata';
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -178,12 +186,9 @@ const App = {
|
||||
searchInput.value = '';
|
||||
searchClearBtn.style.display = 'none';
|
||||
searchInput.focus();
|
||||
const hash = window.location.hash;
|
||||
if (hash.startsWith('#/tickets') && !hash.includes('/new') && !hash.match(/#\/tickets\/\d+/)) {
|
||||
TicketListView.currentPage = 1;
|
||||
TicketListView.render();
|
||||
} else {
|
||||
window.location.hash = '#/tickets';
|
||||
if (window.location.hash.startsWith('#/ricerca-spudorata') && typeof RicercaSpudorataView !== 'undefined') {
|
||||
RicercaSpudorataView.invalidateCache();
|
||||
RicercaSpudorataView.render();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -241,10 +246,16 @@ const App = {
|
||||
} else {
|
||||
this.route();
|
||||
}
|
||||
|
||||
// Set periodic refresh for daily time accounting counter (every 60 seconds)
|
||||
if (!this.dailyTimerInterval) {
|
||||
this.dailyTimerInterval = setInterval(() => this.updateDailyTimer(), 60000);
|
||||
}
|
||||
},
|
||||
|
||||
/** Route based on current hash */
|
||||
route() {
|
||||
this.updateDailyTimer();
|
||||
const fullHash = window.location.hash || '#/dashboard';
|
||||
const hash = fullHash.split('?')[0];
|
||||
const titleEl = document.getElementById('page-title');
|
||||
@@ -364,7 +375,18 @@ const App = {
|
||||
throw new Error(errData.error || errData.message || `HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
const data = await response.json();
|
||||
|
||||
// Automatically update daily timer on any system mutation (POST, PUT, PATCH, DELETE)
|
||||
const method = (options.method || 'GET').toUpperCase();
|
||||
if (method !== 'GET' && !url.includes('/api/users/time-today')) {
|
||||
setTimeout(() => {
|
||||
this.updateDailyTimer();
|
||||
this.updateSidebarBadges();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/** Ensure lookup data is loaded (cached) */
|
||||
|
||||
@@ -14,6 +14,7 @@ const Filters = {
|
||||
customer_user_id: '',
|
||||
date_from: '',
|
||||
date_to: '',
|
||||
sub_search: '',
|
||||
},
|
||||
my: {
|
||||
queue_id: '',
|
||||
@@ -23,6 +24,7 @@ const Filters = {
|
||||
customer_user_id: '',
|
||||
date_from: '',
|
||||
date_to: '',
|
||||
sub_search: '',
|
||||
},
|
||||
spudorata: {
|
||||
queue_id: '',
|
||||
@@ -32,6 +34,7 @@ const Filters = {
|
||||
customer_user_id: '',
|
||||
date_from: '',
|
||||
date_to: '',
|
||||
sub_search: '',
|
||||
}
|
||||
},
|
||||
|
||||
@@ -93,7 +96,7 @@ const Filters = {
|
||||
|
||||
/** Reset all filters */
|
||||
reset() {
|
||||
this.state = { queue_id: '', state_id: '', priority_id: '', user_id: '', customer_user_id: '', date_from: '', date_to: '' };
|
||||
this.state = { queue_id: '', state_id: '', priority_id: '', user_id: '', customer_user_id: '', date_from: '', date_to: '', sub_search: '' };
|
||||
if (this.currentMode === 'my') {
|
||||
const activeAgentId = localStorage.getItem('activeAgentId') || '1';
|
||||
this.state.user_id = activeAgentId;
|
||||
@@ -341,6 +344,13 @@ const Filters = {
|
||||
<span class="filter-label">A Data/Ora</span>
|
||||
<input type="datetime-local" class="filter-select" data-filter="date_to" id="filter-date-to" value="${this.state.date_to || ''}" style="width: 170px; padding: 4px 8px; font-family: inherit; font-size: 0.85rem;" />
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<span class="filter-label">Cerca in Cache</span>
|
||||
<div style="position:relative; display:inline-flex; align-items:center;">
|
||||
<input type="text" class="filter-select form-input" data-filter="sub_search" id="filter-sub-search" value="${App.escapeHtml(this.state.sub_search || '')}" placeholder="Filtra testo (Invio)..." title="Digita e premi Invio per filtrare i risultati in cache" style="width: 140px; padding: 4px 22px 4px 8px; font-family: inherit; font-size: 0.85rem;" autocomplete="off" />
|
||||
<button type="button" id="filter-sub-search-clear" style="position:absolute; right:6px; top:50%; transform:translateY(-50%); background:none; border:none; color:var(--text-muted); cursor:pointer; display:${this.state.sub_search ? 'flex' : 'none'}; align-items:center; justify-content:center; padding:0; font-size:12px; line-height:1;" title="Cancella testo in cache">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filters-actions" style="display:flex; gap:6px; align-items:center;">
|
||||
<button class="btn btn-primary btn-xs" id="filter-refresh" title="Aggiorna lista ticket" style="display:inline-flex; align-items:center; gap:4px; height:26px; padding:0 10px; font-size:0.78rem;">
|
||||
🔄 Aggiorna
|
||||
@@ -363,6 +373,42 @@ const Filters = {
|
||||
this.save();
|
||||
if (onFilterChange) onFilterChange();
|
||||
});
|
||||
|
||||
if (sel.tagName === 'INPUT' && sel.type === 'text') {
|
||||
if (sel.dataset.filter === 'sub_search') {
|
||||
const clearBtn = document.getElementById('filter-sub-search-clear');
|
||||
sel.addEventListener('input', () => {
|
||||
if (clearBtn) clearBtn.style.display = sel.value.trim() ? 'flex' : 'none';
|
||||
});
|
||||
sel.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
this.selectedPresetId = null;
|
||||
this.state[e.target.dataset.filter] = e.target.value;
|
||||
this.save();
|
||||
if (onFilterChange) onFilterChange();
|
||||
}
|
||||
});
|
||||
if (clearBtn) {
|
||||
clearBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
sel.value = '';
|
||||
clearBtn.style.display = 'none';
|
||||
this.selectedPresetId = null;
|
||||
this.state.sub_search = '';
|
||||
this.save();
|
||||
if (onFilterChange) onFilterChange();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
sel.addEventListener('input', (e) => {
|
||||
this.selectedPresetId = null;
|
||||
this.state[e.target.dataset.filter] = e.target.value;
|
||||
this.save();
|
||||
if (onFilterChange) onFilterChange();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Helper to bind standard multiselect popover events
|
||||
|
||||
@@ -24,36 +24,32 @@ const RicercaSpudorataView = {
|
||||
Filters.load();
|
||||
|
||||
const container = document.getElementById('view-container');
|
||||
container.innerHTML = `
|
||||
<div class="loading-screen">
|
||||
<div class="spinner"></div>
|
||||
<p>Inizializzazione Ricerca Spudorata...</p>
|
||||
</div>
|
||||
`;
|
||||
if (!container) return;
|
||||
|
||||
await App.ensureLookups();
|
||||
const urlParams = new URLSearchParams((window.location.hash.split('?')[1]) || '');
|
||||
const qParam = urlParams.get('q');
|
||||
|
||||
try {
|
||||
const settings = await App.api('/api/dashboard/settings');
|
||||
if (settings && settings.tickets_per_page) {
|
||||
this.perPage = settings.tickets_per_page;
|
||||
if (qParam && qParam !== this.searchTerm) {
|
||||
this.renderContainer(container);
|
||||
this.bindEvents();
|
||||
const input = document.getElementById('spudorata-search-input');
|
||||
if (input) input.value = qParam;
|
||||
this.executeSearch(qParam);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to load agent settings:', err);
|
||||
|
||||
// Instant render from memory cache if already searched
|
||||
if (this.hasSearched && this.cachedTickets) {
|
||||
this.renderContainer(container);
|
||||
this.bindEvents();
|
||||
this.renderLocalResults();
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderContainer(container);
|
||||
this.bindEvents();
|
||||
|
||||
const urlParams = new URLSearchParams((window.location.hash.split('?')[1]) || '');
|
||||
const qParam = urlParams.get('q');
|
||||
if (qParam && !this.hasSearched) {
|
||||
const input = document.getElementById('spudorata-search-input');
|
||||
if (input) input.value = qParam;
|
||||
this.executeSearch(qParam);
|
||||
} else if (this.hasSearched && this.cachedTickets) {
|
||||
this.renderLocalResults();
|
||||
}
|
||||
App.ensureLookups();
|
||||
},
|
||||
|
||||
renderContainer(container) {
|
||||
@@ -324,6 +320,30 @@ const RicercaSpudorataView = {
|
||||
let list = [...this.cachedTickets];
|
||||
const s = Filters.state;
|
||||
|
||||
if (s.sub_search) {
|
||||
const q = String(s.sub_search).toLowerCase().trim();
|
||||
if (q) {
|
||||
list = list.filter(t => {
|
||||
const fields = [
|
||||
t.tn,
|
||||
t.title,
|
||||
t.queue_name,
|
||||
t.state_name,
|
||||
t.priority_name,
|
||||
t.owner_first,
|
||||
t.owner_last,
|
||||
`${t.owner_first || ''} ${t.owner_last || ''}`,
|
||||
t.customer_first,
|
||||
t.customer_last,
|
||||
`${t.customer_first || ''} ${t.customer_last || ''}`,
|
||||
t.customer_id,
|
||||
t.customer_user_id
|
||||
];
|
||||
return fields.some(f => f && String(f).toLowerCase().includes(q));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (s.state_id) {
|
||||
const selectedStates = String(s.state_id).split(',').filter(Boolean);
|
||||
list = list.filter(t => selectedStates.includes(String(t.ticket_state_id)));
|
||||
|
||||
+190
-41
@@ -9,18 +9,27 @@ const TicketListView = {
|
||||
sortDir: 'DESC',
|
||||
selectedIds: new Set(),
|
||||
selectedOrder: [],
|
||||
lastQueryParams: null,
|
||||
cachedData: null,
|
||||
rawTicketsByMode: {
|
||||
general: null,
|
||||
my: null
|
||||
},
|
||||
lastSearchTermByMode: {
|
||||
general: '',
|
||||
my: ''
|
||||
},
|
||||
otrsBaseUrl: null,
|
||||
needsRefresh: false,
|
||||
|
||||
invalidateCache() {
|
||||
this.lastQueryParams = null;
|
||||
this.cachedData = null;
|
||||
this.rawTicketsByMode.general = null;
|
||||
this.rawTicketsByMode.my = null;
|
||||
this.needsRefresh = true;
|
||||
},
|
||||
|
||||
async render(force = false) {
|
||||
const isMyTickets = window.location.hash.startsWith('#/tickets/my');
|
||||
Filters.currentMode = isMyTickets ? 'my' : 'general';
|
||||
const newMode = isMyTickets ? 'my' : 'general';
|
||||
Filters.currentMode = newMode;
|
||||
Filters.load(); // Load state for current mode
|
||||
|
||||
if (isMyTickets) {
|
||||
@@ -29,40 +38,27 @@ const TicketListView = {
|
||||
Filters.save();
|
||||
}
|
||||
|
||||
const params = Filters.toQueryParams();
|
||||
params.set('page', this.currentPage);
|
||||
params.set('per_page', this.perPage);
|
||||
params.set('sort_by', this.sortBy);
|
||||
params.set('sort_dir', this.sortDir);
|
||||
|
||||
const searchInput = document.getElementById('global-search');
|
||||
if (searchInput && searchInput.value.trim()) {
|
||||
params.set('search', searchInput.value.trim());
|
||||
}
|
||||
|
||||
const currentQueryString = `${Filters.currentMode}:${params.toString()}`;
|
||||
const globalSearchVal = searchInput ? searchInput.value.trim() : '';
|
||||
const container = document.getElementById('view-container');
|
||||
if (!container) return;
|
||||
|
||||
// Return cached results instantly if query params haven't changed and no force refresh requested
|
||||
if (!force && !this.needsRefresh && this.lastQueryParams === currentQueryString && this.cachedData) {
|
||||
const currentHash = (window.location.hash || '#/dashboard').split('?')[0];
|
||||
if (currentHash !== '#/tickets' && currentHash !== '#/tickets/my') {
|
||||
return;
|
||||
}
|
||||
this.renderContent(container, this.cachedData);
|
||||
this.bindEvents(this.cachedData);
|
||||
return;
|
||||
}
|
||||
const cachedTickets = this.rawTicketsByMode[newMode];
|
||||
const cachedSearchTerm = this.lastSearchTermByMode[newMode];
|
||||
|
||||
const shouldFetch = force ||
|
||||
this.needsRefresh ||
|
||||
!cachedTickets ||
|
||||
cachedSearchTerm !== globalSearchVal;
|
||||
|
||||
if (shouldFetch) {
|
||||
if (!container.querySelector('.ticket-table-wrapper') && !container.querySelector('.ticket-table')) {
|
||||
container.innerHTML = '<div class="loading-screen"><div class="spinner"></div><p>Caricamento ticket...</p></div>';
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch lookups for filter dropdowns
|
||||
await App.ensureLookups();
|
||||
|
||||
// Fetch agent settings for tickets_per_page
|
||||
try {
|
||||
const settings = await App.api('/api/dashboard/settings');
|
||||
if (settings && settings.tickets_per_page) {
|
||||
@@ -72,22 +68,27 @@ const TicketListView = {
|
||||
console.warn('Failed to load agent settings:', err);
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set('per_page', '2000');
|
||||
if (isMyTickets) {
|
||||
const activeAgentId = localStorage.getItem('activeAgentId') || '1';
|
||||
params.set('user_id', activeAgentId);
|
||||
}
|
||||
if (globalSearchVal) {
|
||||
params.set('search', globalSearchVal);
|
||||
}
|
||||
|
||||
const data = await App.api(`/api/tickets?${params.toString()}`);
|
||||
|
||||
// Route guard: if the user navigated away while the async search was in flight, do not overwrite the view
|
||||
const currentHash = (window.location.hash || '#/dashboard').split('?')[0];
|
||||
if (currentHash !== '#/tickets' && currentHash !== '#/tickets/my') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save to cache
|
||||
this.lastQueryParams = currentQueryString;
|
||||
this.cachedData = data;
|
||||
this.rawTicketsByMode[newMode] = data.tickets || [];
|
||||
this.lastSearchTermByMode[newMode] = globalSearchVal;
|
||||
this.otrsBaseUrl = data.otrsBaseUrl || '';
|
||||
this.needsRefresh = false;
|
||||
|
||||
this.renderContent(container, data);
|
||||
this.bindEvents(data);
|
||||
|
||||
} catch (err) {
|
||||
const currentHash = (window.location.hash || '#/dashboard').split('?')[0];
|
||||
if (currentHash !== '#/tickets' && currentHash !== '#/tickets/my') {
|
||||
@@ -101,7 +102,146 @@ const TicketListView = {
|
||||
<div class="empty-state-sub">${App.escapeHtml(err.message)}</div>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.renderLocalResults();
|
||||
},
|
||||
|
||||
renderLocalResults() {
|
||||
const container = document.getElementById('view-container');
|
||||
if (!container) return;
|
||||
|
||||
const filtered = this.getFilteredTickets();
|
||||
const total = filtered.length;
|
||||
const totalPages = Math.ceil(total / this.perPage) || 1;
|
||||
|
||||
if (this.currentPage > totalPages) {
|
||||
this.currentPage = 1;
|
||||
}
|
||||
|
||||
const sorted = this.sortTickets(filtered);
|
||||
const startIndex = (this.currentPage - 1) * this.perPage;
|
||||
const paginatedTickets = sorted.slice(startIndex, startIndex + this.perPage);
|
||||
|
||||
const dataObj = {
|
||||
tickets: paginatedTickets,
|
||||
total: total,
|
||||
page: this.currentPage,
|
||||
per_page: this.perPage,
|
||||
total_pages: totalPages,
|
||||
otrsBaseUrl: this.otrsBaseUrl
|
||||
};
|
||||
|
||||
this.renderContent(container, dataObj);
|
||||
this.bindEvents(dataObj);
|
||||
},
|
||||
|
||||
getFilteredTickets() {
|
||||
const rawTickets = this.rawTicketsByMode[Filters.currentMode] || [];
|
||||
if (!rawTickets || rawTickets.length === 0) return [];
|
||||
let list = [...rawTickets];
|
||||
const s = Filters.state;
|
||||
|
||||
// Sub-search text filter
|
||||
if (s.sub_search) {
|
||||
const q = String(s.sub_search).toLowerCase().trim();
|
||||
if (q) {
|
||||
list = list.filter(t => {
|
||||
const fields = [
|
||||
t.tn,
|
||||
t.title,
|
||||
t.queue_name,
|
||||
t.state_name,
|
||||
t.priority_name,
|
||||
t.owner_first,
|
||||
t.owner_last,
|
||||
`${t.owner_first || ''} ${t.owner_last || ''}`,
|
||||
t.customer_first,
|
||||
t.customer_last,
|
||||
`${t.customer_first || ''} ${t.customer_last || ''}`,
|
||||
t.customer_id,
|
||||
t.customer_user_id
|
||||
];
|
||||
return fields.some(f => f && String(f).toLowerCase().includes(q));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// State filter
|
||||
if (s.state_id) {
|
||||
const selectedStates = String(s.state_id).split(',').filter(Boolean);
|
||||
list = list.filter(t => selectedStates.includes(String(t.ticket_state_id)));
|
||||
}
|
||||
|
||||
// Queue filter
|
||||
if (s.queue_id) {
|
||||
const selectedQueues = String(s.queue_id).split(',').filter(Boolean);
|
||||
list = list.filter(t => selectedQueues.includes(String(t.queue_id)));
|
||||
}
|
||||
|
||||
// Priority filter
|
||||
if (s.priority_id) {
|
||||
const selectedPriorities = String(s.priority_id).split(',').filter(Boolean);
|
||||
list = list.filter(t => selectedPriorities.includes(String(t.ticket_priority_id)));
|
||||
}
|
||||
|
||||
// Owner filter (general mode)
|
||||
if (s.user_id && Filters.currentMode !== 'my') {
|
||||
const selectedUsers = String(s.user_id).split(',').filter(Boolean);
|
||||
list = list.filter(t => selectedUsers.includes(String(t.user_id)));
|
||||
}
|
||||
|
||||
// Customer user filter
|
||||
if (s.customer_user_id) {
|
||||
const selectedCustomers = String(s.customer_user_id).split(',').filter(Boolean).map(c => c.toLowerCase());
|
||||
list = list.filter(t => t.customer_user_id && selectedCustomers.includes(String(t.customer_user_id).toLowerCase()));
|
||||
}
|
||||
|
||||
// Date from
|
||||
if (s.date_from) {
|
||||
const fromDate = new Date(s.date_from);
|
||||
list = list.filter(t => new Date(t.create_time) >= fromDate);
|
||||
}
|
||||
|
||||
// Date to
|
||||
if (s.date_to) {
|
||||
const toDate = new Date(s.date_to + 'T23:59:59');
|
||||
list = list.filter(t => new Date(t.create_time) <= toDate);
|
||||
}
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
sortTickets(tickets) {
|
||||
const list = [...tickets];
|
||||
const key = this.sortBy;
|
||||
const isAsc = this.sortDir === 'ASC';
|
||||
|
||||
list.sort((a, b) => {
|
||||
let valA, valB;
|
||||
if (key === 'queue') {
|
||||
valA = a.queue_name || '';
|
||||
valB = b.queue_name || '';
|
||||
} else if (key === 'state') {
|
||||
valA = a.state_name || '';
|
||||
valB = b.state_name || '';
|
||||
} else if (key === 'priority') {
|
||||
valA = a.ticket_priority_id || 0;
|
||||
valB = b.ticket_priority_id || 0;
|
||||
} else {
|
||||
valA = a[key] || '';
|
||||
valB = b[key] || '';
|
||||
}
|
||||
|
||||
if (typeof valA === 'string') {
|
||||
return isAsc ? valA.localeCompare(valB, 'it', { sensitivity: 'base' }) : valB.localeCompare(valA, 'it', { sensitivity: 'base' });
|
||||
}
|
||||
return isAsc ? valA - valB : valB - valA;
|
||||
});
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
renderContent(container, data) {
|
||||
@@ -237,6 +377,7 @@ const TicketListView = {
|
||||
<option value="50" ${per_page === 50 ? 'selected' : ''}>50</option>
|
||||
<option value="100" ${per_page === 100 ? 'selected' : ''}>100</option>
|
||||
<option value="200" ${per_page === 200 ? 'selected' : ''}>200</option>
|
||||
<option value="500" ${per_page === 500 ? 'selected' : ''}>500</option>
|
||||
</select>
|
||||
</div>
|
||||
`;
|
||||
@@ -286,9 +427,17 @@ const TicketListView = {
|
||||
this.currentPage = 1;
|
||||
this.selectedIds.clear();
|
||||
this.selectedOrder = [];
|
||||
this.render();
|
||||
this.renderLocalResults();
|
||||
});
|
||||
|
||||
// Refresh button
|
||||
const refreshFilterBtn = document.getElementById('filter-refresh');
|
||||
if (refreshFilterBtn) {
|
||||
refreshFilterBtn.addEventListener('click', () => {
|
||||
this.render(true);
|
||||
});
|
||||
}
|
||||
|
||||
// Sort events
|
||||
document.querySelectorAll('.ticket-table th.sortable').forEach(th => {
|
||||
th.addEventListener('click', () => {
|
||||
@@ -300,7 +449,7 @@ const TicketListView = {
|
||||
this.sortDir = 'DESC';
|
||||
}
|
||||
this.currentPage = 1;
|
||||
this.render();
|
||||
this.renderLocalResults();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -606,10 +755,10 @@ const TicketListView = {
|
||||
// Pagination
|
||||
document.querySelectorAll('.pagination-btn[data-page]').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
this.currentPage = parseInt(btn.dataset.page);
|
||||
this.currentPage = parseInt(btn.dataset.page, 10);
|
||||
this.selectedIds.clear();
|
||||
this.selectedOrder = [];
|
||||
this.render();
|
||||
this.renderLocalResults();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -625,7 +774,7 @@ const TicketListView = {
|
||||
Toast.success(`Righe per pagina aggiornate a ${newLimit}!`);
|
||||
this.perPage = newLimit;
|
||||
this.currentPage = 1;
|
||||
this.render();
|
||||
this.renderLocalResults();
|
||||
} catch (err) {
|
||||
Toast.error('Errore durante il salvataggio dell\'impostazione: ' + err.message);
|
||||
}
|
||||
|
||||
@@ -236,6 +236,37 @@ router.get('/settings', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/dashboard/settings — Save settings for the agent
|
||||
router.post('/settings', (req, res) => {
|
||||
const activeAgentId = parseInt(req.headers['x-agent-id'], 10) || 1;
|
||||
const { preview_limit, tickets_per_page } = req.body || {};
|
||||
|
||||
try {
|
||||
const existing = db.prepare("SELECT agent_id, preview_limit, tickets_per_page FROM agent_settings WHERE agent_id = ?").get(activeAgentId);
|
||||
|
||||
const newPreviewLimit = preview_limit !== undefined ? parseInt(preview_limit, 10) : (existing ? existing.preview_limit : 10);
|
||||
const newTicketsPerPage = tickets_per_page !== undefined ? parseInt(tickets_per_page, 10) : (existing ? existing.tickets_per_page : 50);
|
||||
|
||||
if (existing) {
|
||||
db.prepare(`
|
||||
UPDATE agent_settings
|
||||
SET preview_limit = ?, tickets_per_page = ?
|
||||
WHERE agent_id = ?
|
||||
`).run(newPreviewLimit, newTicketsPerPage, activeAgentId);
|
||||
} else {
|
||||
db.prepare(`
|
||||
INSERT INTO agent_settings (agent_id, preview_limit, tickets_per_page)
|
||||
VALUES (?, ?, ?)
|
||||
`).run(activeAgentId, newPreviewLimit, newTicketsPerPage);
|
||||
}
|
||||
|
||||
res.json({ success: true, preview_limit: newPreviewLimit, tickets_per_page: newTicketsPerPage });
|
||||
} catch (err) {
|
||||
console.error('Error saving agent settings:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/dashboard/chart-lines
|
||||
router.get('/chart-lines', (req, res) => {
|
||||
try {
|
||||
|
||||
+4
-3
@@ -103,7 +103,7 @@ router.get('/', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
queue_id, state_id, priority_id, user_id, type_id, customer_user_id,
|
||||
search, sort_by = 'create_time', sort_dir = 'DESC',
|
||||
search, sub_search, sort_by = 'create_time', sort_dir = 'DESC',
|
||||
page = 1, per_page = 50,
|
||||
date_from, date_to
|
||||
} = req.query;
|
||||
@@ -209,7 +209,8 @@ router.get('/', async (req, res) => {
|
||||
conditions.push(`t.create_time <= $${paramIdx++}`);
|
||||
params.push(new Date(date_to));
|
||||
}
|
||||
if (search) {
|
||||
const searchTerm = search || sub_search;
|
||||
if (searchTerm) {
|
||||
conditions.push(`(
|
||||
t.title ILIKE $${paramIdx} OR
|
||||
t.tn ILIKE $${paramIdx} OR
|
||||
@@ -222,7 +223,7 @@ router.get('/', async (req, res) => {
|
||||
)
|
||||
)
|
||||
)`);
|
||||
params.push(`%${search}%`);
|
||||
params.push(`%${searchTerm}%`);
|
||||
paramIdx++;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user