From 8603f003f948a21c93f9028f59360eabd1845606 Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Tue, 30 Dec 2025 20:18:53 -0500 Subject: [PATCH 01/20] agents --- .../agents/code-quality.agent.md | 39 +++++++++++ .../agents/mysql-mariadb.agent.md | 65 +++++++++++++++++++ .../agents/php-devloper.agent.md | 41 ++++++++++++ .gitignore | 1 - 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/agents/code-quality.agent.md create mode 100644 .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md create mode 100644 .github/ISSUE_TEMPLATE/agents/php-devloper.agent.md diff --git a/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md b/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md new file mode 100644 index 0000000..0c93293 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md @@ -0,0 +1,39 @@ +--- +description: "This Custom agent acts as a quality assurance specialist, focusing on code quality, best practices, and maintainability." +name: "Code Quality Specialist" +tools: ["search/codebase", "edit/editFiles", "web/githubRepo", "vscode/extensions", "execute/getTerminalOutput", "web"] +model: "Claude Sonnet 4.5" +--- + +# Code Quality Specialist +You are a Code Quality Specialist agent. Your role is to ensure that the codebase adheres to high standards of quality, best practices, and maintainability. You have access to various tools to help you perform your tasks effectively . + +The technology stack you will work with is a lamp stack (Linux, Apache, MySQL, PHP) along with JavaScript for frontend development. + + +## Capabilities +- **Code Review:** Analyze code for adherence to coding standards, best practices, and design patterns. +- **Refactoring:** Suggest and implement code refactoring to improve readability, maintainability, and performance. +- **Testing:** Ensure that code is well-tested, with appropriate unit tests, integration tests, and end-to-end tests. +- **Documentation:** Verify that code is well-documented, with clear comments and comprehensive documentation. +- **Performance Optimization:** Identify and address performance bottlenecks in the codebase. +- **Security Best Practices:** Ensure that code follows security best practices to prevent vulnerabilities. +- **Continuous Integration/Continuous Deployment (CI/CD):** Review and improve CI/CD pipelines to ensure smooth and reliable deployments. +- **Code Metrics:** Utilize code metrics to assess code quality and identify areas for improvement. + +## Tools +You have access to the following tools to assist you in your tasks: +- **search/codebase:** Search through the codebase for relevant information or code snippets. +- **edit/editFiles:** Edit code files to implement improvements or fixes. +- **githubRepo:** Interact with the GitHub repository to manage issues, pull requests, and code reviews. +- **extensions:** Utilize extensions that can enhance your capabilities in code quality assurance. +- **web:** Access the web for additional resources, documentation, or best practices. + + +## Instructions +When assisting with tasks, follow these guidelines: +1. **Understand the Request:** Clearly understand the user's request or issue before proceeding. +2. **Gather Information:** Use the available tools to gather necessary information about the codebase, coding standards, and existing issues. +3. **Provide Solutions:** Offer clear and actionable solutions or recommendations based on best practices and your expertise. +4. **Communicate Clearly:** Ensure that your explanations are clear and easy to understand, especially for users who may not be code quality experts. +5. **Follow Up:** If necessary, follow up on previous tasks to ensure that code quality issues have been resolved or improvements have been successfully implemented. diff --git a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md new file mode 100644 index 0000000..4ab939b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md @@ -0,0 +1,65 @@ +--- +description: "This custom agent assits with enhancements, troubleshooting, and management of MySQL and MariaDB databases." +name: "MySQL/ MariaDB Database Administrator" +tools: ["search/codebase", "edit/editFiles", "web/githubRepo", "vscode/extensions", "execute/getTerminalOutput", "web"] +model: "Claude Sonnet 4.5" +--- + +# MySQL/ MariaDB Database Administrator + +You are a MySQL and MariaDB Database Administrator agent. Your role is to assist with enhancements, troubleshooting, and management of MySQL and MariaDB databases. You have access to various tools to help you perform your tasks effectively. + +## Capabilities +- **Database Management:** Assist with database creation, configuration, optimization, and maintenance tasks. +- **Query Optimization:** Analyze and optimize SQL queries for better performance. +- **Troubleshooting:** Diagnose and resolve database-related issues, including connection problems, performance bottlenecks, and data integrity concerns. +- **Backup and Recovery:** Provide guidance on backup strategies and recovery procedures. +- **Security:** Advise on best practices for securing MySQL and MariaDB databases. +- **Version Upgrades:** Assist with planning and executing database version upgrades. +- **Monitoring:** Recommend tools and techniques for monitoring database performance and health. +- **Scripting:** Help with writing and optimizing scripts for database automation tasks. + +## Tools +You have access to the following tools to assist you in your tasks: +- **search/codebase:** Search through the codebase for relevant information or code snippets. +- **edit/editFiles:** Edit configuration files, scripts, or code as needed. +- **githubRepo:** Interact with the GitHub repository to manage issues, pull requests, and code reviews. +- **extensions:** Utilize extensions that can enhance your capabilities in managing databases. +- **web:** Access the web for additional resources, documentation, or troubleshooting guides. + +## Instructions +When assisting with tasks, follow these guidelines: +1. **Understand the Request:** Clearly understand the user's request or issue before proceeding. +2. **Gather Information:** Use the available tools to gather necessary information about the database environment, configurations, and any existing issues. +3. **Provide Solutions:** Offer clear and actionable solutions or recommendations based on best practices and your expertise. +4. **Communicate Clearly:** Ensure that your explanations are clear and easy to understand, especially for users who may not be database experts. +5. **Follow Up:** If necessary, follow up on previous tasks to ensure that issues have been resolved or enhancements have been successfully implemented. + + +## Sample design patternsHere are some common design patterns and best practices for MySQL and MariaDB database management: +- **Normalization:** Ensure that database schemas are normalized to reduce redundancy and improve data integrity. +- **Indexing:** Use appropriate indexing strategies to enhance query performance. +- **Connection Pooling:** Implement connection pooling to manage database connections efficiently and improve application performance + + + +## Built in Cacti DB functions are included from the cacti project. Here are some of the commonly used functions: +## you can find the included file in the cacti project here: +- [Cacti DB Functions](https://github.com/Cacti/cacti/blob/1.2.x/lib/database.php) +- `db_fetch_row($result)`: Fetches a single row from the result set as an associative array. +- `db_fetch_assoc($result)`: Fetches a single row from the result set as an associative array. +- `db_query($query)`: Executes a SQL query and returns the result set. +- `db_insert($table, $data)`: Inserts a new record into the specified table. +- `db_update($table, $data, $where)`: Updates records in the specified table based on the given conditions. +- `db_delete($table, $where)`: Deletes records from the specified table based on the given conditions. +- `db_escape_string($string)`: Escapes special characters in a string for use in a SQL query. +- `db_num_rows($result)`: Returns the number of rows in the result set. +- `db_last_insert_id()`: Retrieves the ID of the last inserted record. + + +##web documentation +For additional information and best practices, refer to the official MySQL and MariaDB documentation: +- [MySQL Documentation](https://dev.mysql.com/doc/) +- [MariaDB Documentation](https://mariadb.com/kb/en/documentation/) + +Use your capabilities and tools effectively to assist users with their MySQL and MariaDB database needs. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md b/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md new file mode 100644 index 0000000..1992350 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md @@ -0,0 +1,41 @@ +--- +description: "This custom agent acts as a PHP developer, assisting with PHP code development, debugging, and optimization." +name: "PHP Developer" +tools: ["search/codebase", "edit/editFiles", "web/githubRepo", "vscode/extensions", "execute/getTerminalOutput", "web"] +model: "Claude Sonnet 4.5" +--- + +# PHP Developer +You are a PHP Developer agent. Your role is to assist with PHP code development, debugging, and optimization. You have access to various tools to help you perform your tasks effectively. +You are to focus on PHP PSR-12 coding standards and best practices supporting modern PHP versions (PHP 8.1 and above). +Your other roles include: +- **Code Review:** Analyze PHP code for adherence to coding standards, best practices, and design patterns. +- **Debugging:** Identify and resolve bugs or issues in PHP code. +- **Performance Optimization:** Suggest and implement optimizations to improve the performance of PHP applications. +- **Testing:** Ensure that PHP code is well-tested, with appropriate unit tests and integration tests. +- **Documentation:** Verify that PHP code is well-documented, with clear comments and comprehensive documentation. +- **Security Best Practices:** Ensure that PHP code follows security best practices to prevent vulnerabilities. + +## Tools +You have access to the following tools to assist you in your tasks: +- **search/codebase:** Search through the codebase for relevant information or code snippets. +- **edit/editFiles:** Edit PHP code files to implement improvements or fixes. +- **githubRepo:** Interact with the GitHub repository to manage issues, pull requests, and code reviews. +- **extensions:** Utilize extensions that can enhance your capabilities in PHP development. +- **web:** Access the web for additional resources, documentation, or best practices. + + + +## The project in this repo calls on functions from the cacti project. You can find the cacti documentation and main github repo here: +- [Cacti GitHub Repository](https://github.com/Cacti/cacti/tree/1.2.x) +- [Cacti Documentation](https://www.github.com/Cacti/documentation) + + + +## Instructions +When assisting with tasks, follow these guidelines: +1. **Understand the Request:** Clearly understand the user's request or issue before proceeding. +2. **Gather Information:** Use the available tools to gather necessary information about the PHP codebase, coding standards, and existing issues. +3. **Provide Solutions:** Offer clear and actionable solutions or recommendations based on best practices and your expertise. +4. **Communicate Clearly:** Ensure that your explanations are clear and easy to understand, especially for users who may not be PHP experts. +5. **Follow Up:** If necessary, follow up on previous tasks to ensure that PHP code issues have been resolved or improvements have been successfully implemented. diff --git a/.gitignore b/.gitignore index ec5e85f..efca3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,6 @@ # | http://www.cacti.net/ | # +-------------------------------------------------------------------------+ -.git* locales/po/*.mo config.php From 75c5cd951afa40b60998a0965b4ea8246eeab2f0 Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Tue, 30 Dec 2025 20:39:56 -0500 Subject: [PATCH 02/20] Update copilot-instructions.md --- .github/ISSUE_TEMPLATE/copilot-instructions.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/copilot-instructions.md b/.github/ISSUE_TEMPLATE/copilot-instructions.md index ced1322..d89f764 100644 --- a/.github/ISSUE_TEMPLATE/copilot-instructions.md +++ b/.github/ISSUE_TEMPLATE/copilot-instructions.md @@ -11,6 +11,7 @@ This is the **Syslog Plugin** for Cacti, a PHP-based network monitoring and grap - **Critical:** ALWAYS use the `syslog_db_*` wrapper functions (defined in `database.php`) for all database operations. NEVER use standard Cacti `db_*` functions directly for syslog tables, as they will fail if a dedicated database is configured. - **Integration:** The plugin integrates with Cacti via hooks defined in `setup.php`. - **Poller Integration:** Background processes (`syslog_process.php`, `syslog_removal.php`) are triggered by Cacti's poller or run independently. +- **Syslog Reception:** Syslog messages are directly inserted into `syslog_incoming` table syslog_process.php then processes them. ## Critical Developer Workflows @@ -55,3 +56,8 @@ This is the **Syslog Plugin** for Cacti, a PHP-based network monitoring and grap - `config.php.dist`: Template for database configuration. - `functions.php`: Core logic and utility functions. - `syslog.php`: Main UI entry point. + + +**Documentation & Resources** +- [Cacti main repo](https://github.com/Cacti/cacti/tree/1.2.x) +- [cacti documentation](https://www.github.com/Cacti/documentation) \ No newline at end of file From 5d8ac7e3a03e3fb3951d126fce2b68bf6b69d0c4 Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Wed, 31 Dec 2025 00:29:02 -0500 Subject: [PATCH 03/20] add missing return --- functions.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/functions.php b/functions.php index 5cb78ca..c9e0a36 100644 --- a/functions.php +++ b/functions.php @@ -684,9 +684,11 @@ function syslog_row_color($priority, $message) { break; } - print ""; + print ""; + return $class; } + function sql_hosts_where($tab) { global $hostfilter, $hostfilter_log, $syslog_incoming_config; global $syslogdb_default; From 0652b7e2c1a1d8d7f79f0fecd204483ad7df50ee Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Wed, 31 Dec 2025 00:29:21 -0500 Subject: [PATCH 04/20] Update syslog.css --- syslog.css | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/syslog.css b/syslog.css index e8a1867..12adcbe 100644 --- a/syslog.css +++ b/syslog.css @@ -93,3 +93,28 @@ p { text-align:left; font-size:12px; } + +/* Syslog message grouping styles */ +.syslog-group-toggle { + transition: transform 0.2s ease; + color: #337ab7; + display: inline-block; +} + +.syslog-group-toggle:hover { + color: #23527c; +} + +.syslog-group-toggle.fa-chevron-up { + transform: rotate(0deg); +} + +.syslog-group-toggle.fa-chevron-down { + transform: rotate(0deg); +} + + +.syslog-detail-row:hover { + /* Slightly highlight on hover but keep parent coloring visible */ + background: rgba(0,0,0,0.02) !important; +} From d730c1d0958e453df3b2f881f37127157681906c Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Wed, 31 Dec 2025 00:32:46 -0500 Subject: [PATCH 05/20] Allow grouping of similar messeges in the UI This feature allows users to group messeges based on similar text and host This is useful for when a host has been sending repeted alarms of the same type --- syslog.php | 318 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 274 insertions(+), 44 deletions(-) diff --git a/syslog.php b/syslog.php index 1fec1c9..70103a7 100644 --- a/syslog.php +++ b/syslog.php @@ -199,7 +199,7 @@ function syslog_view_alarm() { global $syslogdb_default; print ""; - print ""; + print ""; print " + + + +
" . __('Syslog Alert View', 'syslog') . "
" . __('Syslog Alert View', 'syslog') . "
\n"; $html = syslog_db_fetch_cell('SELECT html FROM `' . $syslogdb_default . '`.`syslog_logs` WHERE seq=' . get_request_var('id')); @@ -662,6 +662,7 @@ function applyFilter() { strURL += '×pan=' + $('#timespan').val(); strURL += '&rfilter=' + base64_encode($('#rfilter').val()); strURL += '&rows=' + $('#rows').val(); + strURL += '&grouping=' + ($('#grouping').length ? $('#grouping').val() : '0'); loadPageNoHeader(strURL); } @@ -758,11 +759,17 @@ function syslog_request_validation($current_tab, $force = false) { 'pageset' => true, 'default' => read_user_setting('syslog_eprogram', '-1', $force), ), + 'grouping' => array( + 'filter' => FILTER_VALIDATE_INT, + 'pageset' => true, + 'default' => read_user_setting('syslog_grouping', '0', $force), + ), 'rfilter' => array( 'filter' => FILTER_VALIDATE_IS_REGEX, 'pageset' => true, 'default' => '' ), + 'date1' => array( 'filter' => FILTER_CALLBACK, 'pageset' => true, @@ -996,35 +1003,128 @@ function get_syslog_messages(&$sql_where, $rows, $tab) { } if ($tab == 'syslog') { - if (get_request_var('removal') == '-1') { - $query_sql = "SELECT syslog.*, syslog_programs.program, 'main' AS mtype - FROM `" . $syslogdb_default . "`.`syslog` - LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` - ON syslog.program_id=syslog_programs.program_id " . - $sql_where . " - $sql_order - $sql_limit"; - } elseif (get_request_var('removal') == '1') { - $query_sql = "(SELECT syslog.*, syslog_programs.program, 'main' AS mtype - FROM `" . $syslogdb_default . "`.`syslog` AS syslog - LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` - ON syslog.program_id=syslog_programs.program_id " . - $sql_where . " - ) UNION (SELECT syslog.*, syslog_programs.program, 'remove' AS mtype - FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog - LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` - ON syslog.program_id=syslog_programs.program_id " . - $sql_where . ") + // Check if grouping is enabled + $grouping_enabled = isset_request_var('grouping') && get_request_var('grouping') == '1'; + + if ($grouping_enabled) { + // When grouping, we need to get grouped results with counts + if (get_request_var('removal') == '-1') { + $query_sql = "SELECT + syslog.host_id, + syslog.message, + syslog.program_id, + syslog.facility_id, + syslog.priority_id, + syslog_programs.program, + 'main' AS mtype, + COUNT(*) AS occurrence_count, + MIN(syslog.logtime) AS first_logtime, + MAX(syslog.logtime) AS logtime, + MIN(syslog.seq) AS seq, + GROUP_CONCAT(syslog.seq ORDER BY syslog.logtime DESC SEPARATOR ',') AS seq_list + FROM `" . $syslogdb_default . "`.`syslog` + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + GROUP BY syslog.host_id, syslog.message, syslog.program_id, syslog.facility_id, syslog.priority_id + $sql_order + $sql_limit"; + } elseif (get_request_var('removal') == '1') { + $query_sql = "SELECT * FROM ( + (SELECT + syslog.host_id, + syslog.message, + syslog.program_id, + syslog.facility_id, + syslog.priority_id, + syslog_programs.program, + 'main' AS mtype, + COUNT(*) AS occurrence_count, + MIN(syslog.logtime) AS first_logtime, + MAX(syslog.logtime) AS logtime, + MIN(syslog.seq) AS seq, + GROUP_CONCAT(syslog.seq ORDER BY syslog.logtime DESC SEPARATOR ',') AS seq_list + FROM `" . $syslogdb_default . "`.`syslog` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + GROUP BY syslog.host_id, syslog.message, syslog.program_id, syslog.facility_id, syslog.priority_id + ) UNION (SELECT + syslog.host_id, + syslog.message, + syslog.program_id, + syslog.facility_id, + syslog.priority_id, + syslog_programs.program, + 'remove' AS mtype, + COUNT(*) AS occurrence_count, + MIN(syslog.logtime) AS first_logtime, + MAX(syslog.logtime) AS logtime, + MIN(syslog.seq) AS seq, + GROUP_CONCAT(syslog.seq ORDER BY syslog.logtime DESC SEPARATOR ',') AS seq_list + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + GROUP BY syslog.host_id, syslog.message, syslog.program_id, syslog.facility_id, syslog.priority_id + ) + ) AS grouped_results $sql_order $sql_limit"; + } else { + $query_sql = "SELECT + syslog.host_id, + syslog.message, + syslog.program_id, + syslog.facility_id, + syslog.priority_id, + syslog_programs.program, + 'remove' AS mtype, + COUNT(*) AS occurrence_count, + MIN(syslog.logtime) AS first_logtime, + MAX(syslog.logtime) AS logtime, + MIN(syslog.seq) AS seq, + GROUP_CONCAT(syslog.seq ORDER BY syslog.logtime DESC SEPARATOR ',') AS seq_list + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` AS syslog_programs + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + GROUP BY syslog.host_id, syslog.message, syslog.program_id, syslog.facility_id, syslog.priority_id + $sql_order + $sql_limit"; + } } else { - $query_sql = "SELECT syslog.*, syslog_programs.program, 'remove' AS mtype - FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog - LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` AS syslog_programs - ON syslog.program_id=syslog_programs.program_id " . - $sql_where . " - $sql_order - $sql_limit"; + // Original non-grouped queries + if (get_request_var('removal') == '-1') { + $query_sql = "SELECT syslog.*, syslog_programs.program, 'main' AS mtype + FROM `" . $syslogdb_default . "`.`syslog` + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + $sql_order + $sql_limit"; + } elseif (get_request_var('removal') == '1') { + $query_sql = "(SELECT syslog.*, syslog_programs.program, 'main' AS mtype + FROM `" . $syslogdb_default . "`.`syslog` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + ) UNION (SELECT syslog.*, syslog_programs.program, 'remove' AS mtype + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . ") + $sql_order + $sql_limit"; + } else { + $query_sql = "SELECT syslog.*, syslog_programs.program, 'remove' AS mtype + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` AS syslog_programs + ON syslog.program_id=syslog_programs.program_id " . + $sql_where . " + $sql_order + $sql_limit"; + } } } else { $query_sql = "SELECT syslog.*, sf.facility, sp.priority, spr.program, sa.name, sa.severity @@ -1251,6 +1351,7 @@ function applyFilter() { strURL += '&trimval='+$('#trimval').val(); strURL += '&removal='+$('#removal').val(); strURL += '&refresh='+$('#refresh').val(); + strURL += '&grouping=' + ($('#grouping').length ? $('#grouping').val() : '0'); loadPageNoHeader(strURL); } @@ -1638,6 +1739,19 @@ function timeshiftFilterRight() { '> + + + + + +
@@ -1746,25 +1860,53 @@ function syslog_messages($tab = 'syslog') { syslog_filter($sql_where, $tab); if ($tab == 'syslog') { - if (get_request_var('removal') == 1) { - $total_rows = syslog_db_fetch_cell("SELECT SUM(totals) - FROM ( - SELECT count(*) AS totals + // Check if grouping is enabled for row count + $grouping_enabled = isset_request_var('grouping') && get_request_var('grouping') == '1'; + + if ($grouping_enabled) { + // When grouping, count distinct groups instead of individual rows + if (get_request_var('removal') == 1) { + $total_rows = syslog_db_fetch_cell("SELECT SUM(totals) + FROM ( + SELECT COUNT(DISTINCT CONCAT(host_id, '|', message, '|', program_id, '|', facility_id, '|', priority_id)) AS totals + FROM `" . $syslogdb_default . "`.`syslog` AS syslog + $sql_where + UNION + SELECT COUNT(DISTINCT CONCAT(host_id, '|', message, '|', program_id, '|', facility_id, '|', priority_id)) AS totals + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + $sql_where + ) AS rowcount"); + } elseif (get_request_var('removal') == -1) { + $total_rows = syslog_db_fetch_cell("SELECT COUNT(DISTINCT CONCAT(host_id, '|', message, '|', program_id, '|', facility_id, '|', priority_id)) FROM `" . $syslogdb_default . "`.`syslog` AS syslog - $sql_where - UNION - SELECT count(*) AS totals + $sql_where"); + } else { + $total_rows = syslog_db_fetch_cell("SELECT COUNT(DISTINCT CONCAT(host_id, '|', message, '|', program_id, '|', facility_id, '|', priority_id)) FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog - $sql_where - ) AS rowcount"); - } elseif (get_request_var('removal') == -1) { - $total_rows = syslog_db_fetch_cell("SELECT count(*) - FROM `" . $syslogdb_default . "`.`syslog` AS syslog - $sql_where"); + $sql_where"); + } } else { - $total_rows = syslog_db_fetch_cell("SELECT count(*) - FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog - $sql_where"); + // Original non-grouped row counting + if (get_request_var('removal') == 1) { + $total_rows = syslog_db_fetch_cell("SELECT SUM(totals) + FROM ( + SELECT count(*) AS totals + FROM `" . $syslogdb_default . "`.`syslog` AS syslog + $sql_where + UNION + SELECT count(*) AS totals + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + $sql_where + ) AS rowcount"); + } elseif (get_request_var('removal') == -1) { + $total_rows = syslog_db_fetch_cell("SELECT count(*) + FROM `" . $syslogdb_default . "`.`syslog` AS syslog + $sql_where"); + } else { + $total_rows = syslog_db_fetch_cell("SELECT count(*) + FROM `" . $syslogdb_default . "`.`syslog_removed` AS syslog + $sql_where"); + } } } else { $total_rows = syslog_db_fetch_cell("SELECT count(*) @@ -1781,6 +1923,9 @@ function syslog_messages($tab = 'syslog') { } if ($tab == 'syslog') { + // Check if grouping is enabled for display + $grouping_enabled = isset_request_var('grouping') && get_request_var('grouping') == '1'; + if (api_plugin_user_realm_auth('syslog_alerts.php')) { $display_text = array( 'nosortt' => array(__('Actions', 'syslog'), 'ASC'), @@ -1790,6 +1935,11 @@ function syslog_messages($tab = 'syslog') { 'message' => array(__('Message', 'syslog'), 'ASC'), 'facility_id' => array(__('Facility', 'syslog'), 'ASC'), 'priority_id' => array(__('Priority', 'syslog'), 'ASC')); + + // Add count column if grouping is enabled + if ($grouping_enabled) { + $display_text['occurrence_count'] = array(__('Count', 'syslog'), 'DESC'); + } } else { $display_text = array( 'logtime' => array(__('Date', 'syslog'), 'ASC'), @@ -1798,6 +1948,11 @@ function syslog_messages($tab = 'syslog') { 'message' => array(__('Message', 'syslog'), 'ASC'), 'facility_id' => array(__('Facility', 'syslog'), 'ASC'), 'priority_id' => array(__('Priority', 'syslog'), 'ASC')); + + // Add count column if grouping is enabled + if ($grouping_enabled) { + $display_text['occurrence_count'] = array(__('Count', 'syslog'), 'DESC'); + } } $nav = html_nav_bar("syslog.php?tab=$tab", MAX_DISPLAY_PAGES, get_request_var_request('page'), $rows, $total_rows, cacti_sizeof($display_text), __('Messages', 'syslog'), 'page', 'main'); @@ -1847,14 +2002,68 @@ function syslog_messages($tab = 'syslog') { form_selectable_cell($url, $sm['seq'], '', 'left'); } - form_selectable_cell($sm['logtime'], $sm['seq'], '', 'left'); + // Display grouped or individual messages + if ($grouping_enabled && isset($sm['occurrence_count']) && $sm['occurrence_count'] > 1) { + // Grouped message display with expand/collapse + $expand_icon = ""; + form_selectable_cell($expand_icon . $sm['logtime'], $sm['seq'], '', 'left'); + } else { + form_selectable_cell($sm['logtime'], $sm['seq'], '', 'left'); + } + form_selectable_cell(isset($hosts[$sm['host_id']]) ? $hosts[$sm['host_id']]:__('Unknown', 'syslog'), $sm['seq'], '', 'left'); form_selectable_cell($sm['program'], $sm['seq'], '', 'left'); form_selectable_cell(filter_value(title_trim($sm[$syslog_incoming_config['textField']], get_request_var_request('trimval')), get_request_var('rfilter')), $sm['seq'], '', 'left syslogMessage'); form_selectable_cell(isset($facilities[$sm['facility_id']]) ? $facilities[$sm['facility_id']]:__('Unknown', 'syslog'), $sm['seq'], '', 'left'); form_selectable_cell(isset($priorities[$sm['priority_id']]) ? $priorities[$sm['priority_id']]:__('Unknown', 'syslog'), $sm['seq'], '', 'left'); + // Add occurrence count if grouping is enabled + if ($grouping_enabled) { + form_selectable_cell(isset($sm['occurrence_count']) ? $sm['occurrence_count'] : 1, $sm['seq'], '', 'right'); + } + form_end_row(); + + // If grouping is enabled and there are multiple occurrences, add hidden detail rows + if ($grouping_enabled && isset($sm['occurrence_count']) && $sm['occurrence_count'] > 1 && isset($sm['seq_list'])) { + $seq_array = explode(',', $sm['seq_list']); + + // Get individual messages for this group + $detail_messages = syslog_db_fetch_assoc("SELECT syslog.*, syslog_programs.program + FROM `" . $syslogdb_default . "`.`" . (($sm['mtype'] == 'main') ? 'syslog' : 'syslog_removed') . "` AS syslog + LEFT JOIN `" . $syslogdb_default . "`.`syslog_programs` + ON syslog.program_id=syslog_programs.program_id + WHERE syslog.seq IN (" . implode(',', array_map('intval', $seq_array)) . ") + ORDER BY syslog.logtime DESC"); + + if (cacti_sizeof($detail_messages)) { + foreach ($detail_messages as $dm) { + $severity_class = syslog_row_color($dm['priority_id'], $dm['message']); + print ""; + if (api_plugin_user_realm_auth('syslog_alerts.php')) { + $url = ''; + if ($sm['mtype'] == 'main') { + $url .= ""; + $url .= ""; + } + print "" . $url . ""; + } + + print "" . $dm['logtime'] . ""; + print "" . (isset($hosts[$dm['host_id']]) ? $hosts[$dm['host_id']] : __('Unknown', 'syslog')) . ""; + print "" . $dm['program'] . ""; + print "" . filter_value(title_trim($dm[$syslog_incoming_config['textField']], get_request_var_request('trimval')), get_request_var('rfilter')) . ""; + print "" . (isset($facilities[$dm['facility_id']]) ? $facilities[$dm['facility_id']] : __('Unknown', 'syslog')) . ""; + print "" . (isset($priorities[$dm['priority_id']]) ? $priorities[$dm['priority_id']] : __('Unknown', 'syslog')) . ""; + + if ($grouping_enabled) { + print ""; + } + + print ""; + } + } + } } } else { print "" . __('No Syslog Messages', 'syslog') . ""; @@ -1888,6 +2097,26 @@ function syslog_messages($tab = 'syslog') { }).on('click', function() { $(this).tooltip('close'); }); + + // Handle syslog group expand/collapse + $('.syslog-group-toggle').off('click').on('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + + var seq = $(this).data('seq'); + var detailRows = $('.syslog-detail-' + seq); + var icon = $(this); + + if (detailRows.is(':visible')) { + // Collapse + detailRows.hide(); + icon.removeClass('fa-chevron-up').addClass('fa-chevron-down'); + } else { + // Expand + detailRows.show(); + icon.removeClass('fa-chevron-down').addClass('fa-chevron-up'); + } + }); }); Date: Wed, 31 Dec 2025 00:55:01 -0500 Subject: [PATCH 06/20] Clean up JS code Move JS functions to functions.js file - Easier and cleaner --- functions.php | 7 + js/functions.js | 510 +++++++++++++++++++++++++++++++++++++++++++++ syslog.php | 300 +------------------------- syslog_alerts.php | 39 +--- syslog_removal.php | 62 +----- syslog_reports.php | 39 +--- 6 files changed, 539 insertions(+), 418 deletions(-) create mode 100644 js/functions.js diff --git a/functions.php b/functions.php index c9e0a36..846f330 100644 --- a/functions.php +++ b/functions.php @@ -22,6 +22,13 @@ +-------------------------------------------------------------------------+ */ +function syslog_include_js() { + global $config; + ?> + + 0) { + data.predefined_timespan = $('#predefined_timespan').val(); + } + + data.predefined_timeshift = $('#predefined_timeshift').val(); + + $.post(strURL, data).done(function() { + $('#text').show().text('Filter Settings Saved').fadeOut(2000); + }); +} + +/** + * Shift time filter left (backward) + */ +function timeshiftFilterLeft() { + var strURL = 'syslog.php?tab='+(window.pageTab || '')+'&header=false'; + strURL += '&shift_left=true'; + strURL += '&date1='+$('#date1').val(); + strURL += '&date2='+$('#date2').val(); + strURL += '&predefined_timeshift='+$('#predefined_timeshift').val(); + loadPageNoHeader(strURL); +} + +/** + * Shift time filter right (forward) + */ +function timeshiftFilterRight() { + var strURL = 'syslog.php?tab='+(window.pageTab || '')+'&header=false'; + strURL += '&shift_right=true'; + strURL += '&date1='+$('#date1').val(); + strURL += '&date2='+$('#date2').val(); + strURL += '&predefined_timeshift='+$('#predefined_timeshift').val(); + loadPageNoHeader(strURL); +} + +/** + * Initialize main syslog view + * @param {object} config - Configuration object containing: pageTab, placeHolder, noneSelectedText, devicesSelectedText, allDevicesText + */ +function initSyslogMain(config) { + var date1Open = false; + var date2Open = false; + var pageTab = config.pageTab || ''; + var hostTerm = ''; + var placeHolder = config.placeHolder || ''; + + // Make pageTab global for other functions + window.pageTab = pageTab; + + $(function() { + $('#syslog_form').submit(function(event) { + event.preventDefault(); + applyFilter(); + }); + + $('#host').multiselect({ + menuHeight: $(window).height()*.7, + menuWidth: '220', + linkInfo: faIcons, + noneSelectedText: config.noneSelectedText || '', + selectedText: function(numChecked, numTotal, checkedItems) { + myReturn = numChecked + ' ' + config.devicesSelectedText; + $.each(checkedItems, function(index, value) { + if (value.value == '0') { + myReturn = config.allDevicesText; + return false; + } + }); + return myReturn; + }, + uncheckAll: function() { + $(this).multiselect('widget').find(':checkbox:first').each(function() { + $(this).prop('checked', true); + }); + $('#test').trigger('keyup'); + }, + checkAll: function() { + $(this).multiselect('widget').find(':checkbox').not(':first').each(function() { + $(this).prop('checked', true); + }); + $(this).multiselect('widget').find(':checkbox:first').each(function() { + $(this).prop('checked', false); + }); + }, + open: function(event, ui) { + if ($('#term').length == 0) { + var width = parseInt($(this).multiselect('widget').find('.ui-multiselect-header').width() - 5); + $(this).multiselect('widget').find('.ui-multiselect-header').after(''); + $('#term').on('keyup', function() { + $.getJSON('syslog.php?action=ajax_hosts&term='+$('#term').val(), function(data) { + $('#host').find('option').not(':selected').each(function() { + if ($(this).attr('id') != 'host_all') { + $(this).remove(); + } + }); + + $.each(data, function(index, hostData) { + if ($('#host option[value="'+index+'"]').length == 0) { + $('#host').append(''); + } + }); + + $('#host').multiselect('refresh'); + }); + }); + } + + $('#term').focus(); + }, + click: function(event, ui) { + checked=$(this).multiselect('widget').find('input:checked').length; + + if (ui.value == '0') { + if (ui.checked == true) { + $('#host').multiselect('uncheckAll'); + $(this).multiselect('widget').find(':checkbox:first').each(function() { + $(this).prop('checked', true); + }); + } + } else if (checked == 0) { + $(this).multiselect('widget').find(':checkbox:first').each(function() { + $(this).click(); + }); + } else if ($(this).multiselect('widget').find('input:checked:first').val() == '0') { + if (checked > 0) { + $(this).multiselect('widget').find(':checkbox:first').each(function() { + $(this).click(); + $(this).prop('disable', true); + }); + } + } + } + }); + + $('#save').click(function() { + saveSettings(); + }); + + $('#go').click(function() { + applyFilter(); + }); + + $('#clear').click(function() { + clearFilter(); + }); + + $('#export').click(function() { + exportRecords(); + }); + + $('#balerts').click(function() { + loadTopTab(urlPath+'plugins/syslog/syslog_alerts.php?header=false'); + $('.maintabs').find('a').removeClass('selected'); + $('#tab-console').addClass('selected'); + }); + + $('#bremoval').click(function() { + loadTopTab(urlPath+'plugins/syslog/syslog_removal.php?header=false'); + $('.maintabs').find('a').removeClass('selected'); + $('#tab-console').addClass('selected'); + }); + + $('#breports').click(function() { + loadTopTab(urlPath+'plugins/syslog/syslog_reports.php?header=false'); + $('.maintabs').find('a').removeClass('selected'); + $('#tab-console').addClass('selected'); + }); + + $('#startDate').click(function() { + if (date1Open) { + date1Open = false; + $('#date1').datetimepicker('hide'); + } else { + date1Open = true; + $('#date1').datetimepicker('show'); + } + }); + + $('#endDate').click(function() { + if (date2Open) { + date2Open = false; + $('#date2').datetimepicker('hide'); + } else { + date2Open = true; + $('#date2').datetimepicker('show'); + } + }); + + $('#date1').datetimepicker({ + minuteGrid: 10, + stepMinute: 1, + showAnim: 'slideDown', + numberOfMonths: 1, + timeFormat: 'HH:mm', + dateFormat: 'yy-mm-dd', + showButtonPanel: false + }); + + $('#date2').datetimepicker({ + minuteGrid: 10, + stepMinute: 1, + showAnim: 'slideDown', + numberOfMonths: 1, + timeFormat: 'HH:mm', + dateFormat: 'yy-mm-dd', + showButtonPanel: false + }); + }); +} + +/* ======================================================================== + * Removal Rules Functions (syslog_removal.php) + * ======================================================================== */ + +/** + * Apply filter for removal rules view + */ +function applyFilterRemoval() { + strURL = 'syslog_removal.php?filter='+$('#filter').val()+'&enabled='+$('#enabled').val()+'&rows='+$('#rows').val()+'&page='+$('#page').val()+'&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Clear filter for removal rules view + */ +function clearFilterRemoval() { + strURL = 'syslog_removal.php?clear=1&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Import removal rule + */ +function importRemoval() { + strURL = 'syslog_removal.php?action=import&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Change message textarea rows based on type + */ +function changeTypes() { + if ($('#type').val == 'sql') { + $('#message').prop('rows', 5); + } else { + $('#message').prop('rows', 2); + } +} + +/** + * Initialize removal rules view + * @param {boolean} allowEdits - Whether edits are allowed + */ +function initSyslogRemoval(allowEdits) { + $(function() { + if (!allowEdits) { + $('#syslog_edit').find('select, input, textarea, submit').not(':button').prop('disabled', true); + $('#syslog_edit').find('select').each(function() { + if ($(this).selectmenu('instance')) { + $(this).selectmenu('refresh'); + } + }); + } + + $('#refresh').click(function() { + applyFilterRemoval(); + }); + + $('#clear').click(function() { + clearFilterRemoval(); + }); + + $('#import').click(function() { + importRemoval(); + }); + + $('#removal').submit(function(event) { + event.preventDefault(); + applyFilterRemoval(); + }); + }); +} + +/* ======================================================================== + * Alert Rules Functions (syslog_alerts.php) + * ======================================================================== */ + +/** + * Apply filter for alert rules view + */ +function applyFilterAlerts() { + strURL = 'syslog_alerts.php?filter='+$('#filter').val()+'&enabled='+$('#enabled').val()+'&rows='+$('#rows').val()+'&page='+$('#page').val()+'&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Clear filter for alert rules view + */ +function clearFilterAlerts() { + strURL = 'syslog_alerts.php?clear=1&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Import alert rule + */ +function importAlert() { + strURL = 'syslog_alerts.php?action=import&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Initialize alert rules view + */ +function initSyslogAlerts() { + $(function() { + $('#refresh').click(function() { + applyFilterAlerts(); + }); + + $('#clear').click(function() { + clearFilterAlerts(); + }); + + $('#import').click(function() { + importAlert(); + }); + + $('#alert').submit(function(event) { + event.preventDefault(); + applyFilterAlerts(); + }); + }); +} + +/* ======================================================================== + * Report Rules Functions (syslog_reports.php) + * ======================================================================== */ + +/** + * Apply filter for report rules view + */ +function applyFilterReports() { + strURL = 'syslog_reports.php?filter='+$('#filter').val()+'&enabled='+$('#enabled').val()+'&rows='+$('#rows').val()+'&page='+$('#page').val()+'&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Clear filter for report rules view + */ +function clearFilterReports() { + strURL = 'syslog_reports.php?clear=1&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Import report rule + */ +function importReport() { + strURL = 'syslog_reports.php?action=import&header=false'; + loadPageNoHeader(strURL); +} + +/** + * Initialize report rules view + */ +function initSyslogReports() { + $(function() { + $('#refresh').click(function() { + applyFilterReports(); + }); + + $('#clear').click(function() { + clearFilterReports(); + }); + + $('#import').click(function() { + importReport(); + }); + + $('#reports').submit(function(event) { + event.preventDefault(); + applyFilterReports(); + }); + }); +} diff --git a/syslog.php b/syslog.php index 70103a7..3cf5a69 100644 --- a/syslog.php +++ b/syslog.php @@ -92,6 +92,8 @@ } else { general_header(); + syslog_include_js(); + syslog_display_tabs($current_tab); if ($current_tab == 'current') { @@ -628,44 +630,7 @@ function syslog_stats_filter() { '> diff --git a/syslog_removal.php b/syslog_removal.php index 421e87b..c961a81 100644 --- a/syslog_removal.php +++ b/syslog_removal.php @@ -61,6 +61,7 @@ break; case 'import': top_header(); + syslog_include_js(); import(); bottom_footer(); @@ -72,6 +73,7 @@ case 'edit': case 'newedit': top_header(); + syslog_include_js(); syslog_action_edit(); @@ -79,6 +81,7 @@ break; default: top_header(); + syslog_include_js(); syslog_removal(); @@ -498,28 +501,7 @@ function syslog_action_edit() { ?> '> diff --git a/syslog_reports.php b/syslog_reports.php index 8354843..abf5bc8 100644 --- a/syslog_reports.php +++ b/syslog_reports.php @@ -51,6 +51,7 @@ break; case 'import': top_header(); + syslog_include_js(); import(); bottom_footer(); @@ -61,6 +62,7 @@ break; case 'edit': top_header(); + syslog_include_js(); syslog_action_edit(); @@ -68,6 +70,7 @@ break; default: top_header(); + syslog_include_js(); syslog_report(); @@ -614,41 +617,7 @@ function syslog_filter() { '> Date: Wed, 31 Dec 2025 11:23:06 -0500 Subject: [PATCH 07/20] Update .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md index 4ab939b..095fdd9 100644 --- a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md +++ b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md @@ -39,7 +39,7 @@ When assisting with tasks, follow these guidelines: ## Sample design patternsHere are some common design patterns and best practices for MySQL and MariaDB database management: - **Normalization:** Ensure that database schemas are normalized to reduce redundancy and improve data integrity. - **Indexing:** Use appropriate indexing strategies to enhance query performance. -- **Connection Pooling:** Implement connection pooling to manage database connections efficiently and improve application performance +- **Connection Pooling:** Implement connection pooling to manage database connections efficiently and improve application performance. From 8b7fcc47f4fc1eacae63872d52e4e5de0253706d Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:23:16 -0500 Subject: [PATCH 08/20] Update .github/ISSUE_TEMPLATE/agents/code-quality.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agents/code-quality.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md b/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md index 0c93293..3d9c760 100644 --- a/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md +++ b/.github/ISSUE_TEMPLATE/agents/code-quality.agent.md @@ -6,7 +6,7 @@ model: "Claude Sonnet 4.5" --- # Code Quality Specialist -You are a Code Quality Specialist agent. Your role is to ensure that the codebase adheres to high standards of quality, best practices, and maintainability. You have access to various tools to help you perform your tasks effectively . +You are a Code Quality Specialist agent. Your role is to ensure that the codebase adheres to high standards of quality, best practices, and maintainability. You have access to various tools to help you perform your tasks effectively. The technology stack you will work with is a lamp stack (Linux, Apache, MySQL, PHP) along with JavaScript for frontend development. From ca77dfd3e10208f1cd6c8ded8ee23a4c4d9c4590 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:23:27 -0500 Subject: [PATCH 09/20] Update .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md index 095fdd9..cdfb3ff 100644 --- a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md +++ b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md @@ -1,5 +1,5 @@ --- -description: "This custom agent assits with enhancements, troubleshooting, and management of MySQL and MariaDB databases." +description: "This custom agent assists with enhancements, troubleshooting, and management of MySQL and MariaDB databases." name: "MySQL/ MariaDB Database Administrator" tools: ["search/codebase", "edit/editFiles", "web/githubRepo", "vscode/extensions", "execute/getTerminalOutput", "web"] model: "Claude Sonnet 4.5" From e1f7846fd3c010b39732560dacd721a51c29bf80 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:23:40 -0500 Subject: [PATCH 10/20] Update .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md index cdfb3ff..8e3a4cd 100644 --- a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md +++ b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md @@ -36,7 +36,9 @@ When assisting with tasks, follow these guidelines: 5. **Follow Up:** If necessary, follow up on previous tasks to ensure that issues have been resolved or enhancements have been successfully implemented. -## Sample design patternsHere are some common design patterns and best practices for MySQL and MariaDB database management: +## Sample design patterns + +Here are some common design patterns and best practices for MySQL and MariaDB database management: - **Normalization:** Ensure that database schemas are normalized to reduce redundancy and improve data integrity. - **Indexing:** Use appropriate indexing strategies to enhance query performance. - **Connection Pooling:** Implement connection pooling to manage database connections efficiently and improve application performance. From f7f660a0e66ad0317a3b13b79771142608b14027 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:24:07 -0500 Subject: [PATCH 11/20] Update .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md index 8e3a4cd..c5d71c6 100644 --- a/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md +++ b/.github/ISSUE_TEMPLATE/agents/mysql-mariadb.agent.md @@ -59,7 +59,7 @@ Here are some common design patterns and best practices for MySQL and MariaDB da - `db_last_insert_id()`: Retrieves the ID of the last inserted record. -##web documentation +## web documentation For additional information and best practices, refer to the official MySQL and MariaDB documentation: - [MySQL Documentation](https://dev.mysql.com/doc/) - [MariaDB Documentation](https://mariadb.com/kb/en/documentation/) From 8deaf6d808b069839808c6295781de3fd92be751 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:27:37 -0500 Subject: [PATCH 12/20] Update js/functions.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- js/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/functions.js b/js/functions.js index 9eaaa05..4903aad 100644 --- a/js/functions.js +++ b/js/functions.js @@ -183,7 +183,7 @@ function initSyslogMain(config) { linkInfo: faIcons, noneSelectedText: config.noneSelectedText || '', selectedText: function(numChecked, numTotal, checkedItems) { - myReturn = numChecked + ' ' + config.devicesSelectedText; + var myReturn = numChecked + ' ' + config.devicesSelectedText; $.each(checkedItems, function(index, value) { if (value.value == '0') { myReturn = config.allDevicesText; From 49884523e927f804c9ad8809b6c611edec5685a9 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:28:44 -0500 Subject: [PATCH 13/20] Update js/functions.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- js/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/functions.js b/js/functions.js index 4903aad..ab72e0f 100644 --- a/js/functions.js +++ b/js/functions.js @@ -364,7 +364,7 @@ function importRemoval() { * Change message textarea rows based on type */ function changeTypes() { - if ($('#type').val == 'sql') { + if ($('#type').val() == 'sql') { $('#message').prop('rows', 5); } else { $('#message').prop('rows', 2); From c738058b2a96ed34a8d0af42159e2a23e95297e7 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:30:13 -0500 Subject: [PATCH 14/20] Fix formatting in syslog.php --- syslog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syslog.php b/syslog.php index 3cf5a69..01e12a1 100644 --- a/syslog.php +++ b/syslog.php @@ -201,7 +201,7 @@ function syslog_view_alarm() { global $syslogdb_default; print ""; - print ""; + print ""; print ""; + print ""; if (api_plugin_user_realm_auth('syslog_alerts.php')) { $url = ''; if ($sm['mtype'] == 'main') { From 39b9dc99caa8c296dc4c4b982fbfca792fbfbc10 Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Thu, 1 Jan 2026 19:01:25 -0500 Subject: [PATCH 17/20] Update .github/ISSUE_TEMPLATE/agents/php-devloper.agent.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/agents/php-devloper.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md b/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md index 1992350..71ef59e 100644 --- a/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md +++ b/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md @@ -28,7 +28,7 @@ You have access to the following tools to assist you in your tasks: ## The project in this repo calls on functions from the cacti project. You can find the cacti documentation and main github repo here: - [Cacti GitHub Repository](https://github.com/Cacti/cacti/tree/1.2.x) -- [Cacti Documentation](https://www.github.com/Cacti/documentation) +- [Cacti Documentation](https://github.com/Cacti/documentation) From bb3836ef99d29765386431b2a4ce6a8031d8f4a8 Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Thu, 1 Jan 2026 19:05:19 -0500 Subject: [PATCH 18/20] Correct filename spelling --- .../agents/{php-devloper.agent.md => php-developer.agent.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/agents/{php-devloper.agent.md => php-developer.agent.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/agents/php-devloper.agent.md b/.github/ISSUE_TEMPLATE/agents/php-developer.agent.md similarity index 100% rename from .github/ISSUE_TEMPLATE/agents/php-devloper.agent.md rename to .github/ISSUE_TEMPLATE/agents/php-developer.agent.md From 107e1066a98e96d9d9dbadafeba489ed56f22375 Mon Sep 17 00:00:00 2001 From: Sean Mancini Date: Thu, 1 Jan 2026 20:04:47 -0500 Subject: [PATCH 19/20] Migrate autocomplete js function --- js/functions.js | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ syslog.php | 73 ++-------------------------------------- 2 files changed, 90 insertions(+), 71 deletions(-) diff --git a/js/functions.js b/js/functions.js index ab72e0f..63eaec1 100644 --- a/js/functions.js +++ b/js/functions.js @@ -508,3 +508,91 @@ function initSyslogReports() { }); }); } + +/* ======================================================================== + * Autocomplete Form Callback Functions + * ======================================================================== */ + +/** + * Initialize autocomplete for form dropdown fields + * @param {string} formName - The name of the form field + * @param {string} callback - The AJAX callback action + * @param {string} onChange - The onChange callback to execute when selection changes + */ +function initSyslogAutocomplete(formName, callback, onChange) { + var formNameTimer; + var formNameClickTimer; + var formNameOpen = false; + + $(function() { + $('#' + formName + '_input').autocomplete({ + source: window.location.pathname + '?action=' + callback, + autoFocus: true, + minLength: 0, + select: function(event, ui) { + $('#' + formName + '_input').val(ui.item.label); + if (ui.item.id) { + $('#' + formName).val(ui.item.id); + } else { + $('#' + formName).val(ui.item.value); + } + if (onChange) { + eval(onChange); + } + } + }).css('border', 'none').css('background-color', 'transparent'); + + $('#' + formName + '_wrap').on('dblclick', function() { + formNameOpen = false; + clearTimeout(formNameTimer); + clearTimeout(formNameClickTimer); + $('#' + formName + '_input').autocomplete('close'); + }).on('click', function() { + if (formNameOpen) { + $('#' + formName + '_input').autocomplete('close'); + clearTimeout(formNameTimer); + formNameOpen = false; + } else { + formNameClickTimer = setTimeout(function() { + $('#' + formName + '_input').autocomplete('search', ''); + clearTimeout(formNameTimer); + formNameOpen = true; + }, 200); + } + }).on('mouseleave', function() { + formNameTimer = setTimeout(function() { + $('#' + formName + '_input').autocomplete('close'); + }, 800); + }); + + var width = $('#' + formName + '_input').textBoxWidth(); + if (width < 100) { + width = 100; + } + + $('#' + formName + '_wrap').css('width', width + 20); + $('#' + formName + '_input').css('width', width); + + $('ul[id^="ui-id"]').on('mouseenter', function() { + clearTimeout(formNameTimer); + }).on('mouseleave', function() { + formNameTimer = setTimeout(function() { + $('#' + formName + '_input').autocomplete('close'); + }, 800); + }); + + $('ul[id^="ui-id"] > li').each().on('mouseenter', function() { + $(this).addClass('ui-state-hover'); + }).on('mouseleave', function() { + $(this).removeClass('ui-state-hover'); + }); + + $('#' + formName + '_wrap').on('mouseenter', function() { + $(this).addClass('ui-state-hover'); + $('input#' + formName + '_input').addClass('ui-state-hover'); + }).on('mouseleave', function() { + $(this).removeClass('ui-state-hover'); + $('input#' + formName + '_input').removeClass('ui-state-hover'); + }); + }); +} diff --git a/syslog.php b/syslog.php index deb37ed..696c4e4 100644 --- a/syslog.php +++ b/syslog.php @@ -970,9 +970,8 @@ function get_syslog_messages(&$sql_where, $rows, $tab) { if ($tab == 'syslog') { // Check if grouping is enabled $grouping_enabled = isset_request_var('grouping') && get_request_var('grouping') == '1'; - + if ($grouping_enabled) { - // When grouping, we need to get grouped results with counts if (get_request_var('removal') == '-1') { $query_sql = "SELECT syslog.host_id, @@ -2071,75 +2070,7 @@ function syslog_form_callback($form_name, $classic_sql, $column_display, $column } Date: Thu, 1 Jan 2026 20:15:14 -0500 Subject: [PATCH 20/20] Migrate syslog messege display JS to cleaner function --- js/functions.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ syslog.php | 40 +--------------------------------------- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/js/functions.js b/js/functions.js index 63eaec1..104f5cc 100644 --- a/js/functions.js +++ b/js/functions.js @@ -332,6 +332,54 @@ function initSyslogMain(config) { }); } +/** + * Initialize syslog message tooltips and group expand/collapse functionality + * Call this after the syslog message table is rendered or updated + */ +function initSyslogMessagesDisplay() { + $(function() { + // Initialize tooltips for syslog rows + $('.syslogRow').tooltip({ + track: true, + show: { + effect: 'fade', + duration: 250, + delay: 125 + }, + position: { my: 'left+15 center', at: 'right center' } + }); + + // Initialize tooltips for buttons + $('button').tooltip({ + closed: true + }).on('focus', function() { + $('#filter').tooltip('close'); + }).on('click', function() { + $(this).tooltip('close'); + }); + + // Handle syslog group expand/collapse + $('.syslog-group-toggle').off('click').on('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + + var seq = $(this).data('seq'); + var detailRows = $('.syslog-detail-' + seq); + var icon = $(this); + + if (detailRows.is(':visible')) { + // Collapse + detailRows.hide(); + icon.removeClass('fa-chevron-up').addClass('fa-chevron-down'); + } else { + // Expand + detailRows.show(); + icon.removeClass('fa-chevron-down').addClass('fa-chevron-up'); + } + }); + }); +} + /* ======================================================================== * Removal Rules Functions (syslog_removal.php) * ======================================================================== */ diff --git a/syslog.php b/syslog.php index 696c4e4..d4d31a5 100644 --- a/syslog.php +++ b/syslog.php @@ -1796,45 +1796,7 @@ function syslog_messages($tab = 'syslog') { ?>
" . __('Syslog Alert View', 'syslog') . "
" . __('Syslog Alert View', 'syslog') . "
\n"; $html = syslog_db_fetch_cell('SELECT html FROM `' . $syslogdb_default . '`.`syslog_logs` WHERE seq=' . get_request_var('id')); From 9ae6b93455ae40a45a42d1b7a56ad37f13259c96 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:33:10 -0500 Subject: [PATCH 15/20] Update syslog.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- syslog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syslog.php b/syslog.php index 01e12a1..5fbe580 100644 --- a/syslog.php +++ b/syslog.php @@ -1723,7 +1723,7 @@ function syslog_messages($tab = 'syslog') { // Display grouped or individual messages if ($grouping_enabled && isset($sm['occurrence_count']) && $sm['occurrence_count'] > 1) { // Grouped message display with expand/collapse - $expand_icon = ""; + $expand_icon = ""; form_selectable_cell($expand_icon . $sm['logtime'], $sm['seq'], '', 'left'); } else { form_selectable_cell($sm['logtime'], $sm['seq'], '', 'left'); From ebe5de6c40dd534baffcc159c8e52b80b9964958 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 31 Dec 2025 11:33:48 -0500 Subject: [PATCH 16/20] Update syslog.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- syslog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syslog.php b/syslog.php index 5fbe580..deb37ed 100644 --- a/syslog.php +++ b/syslog.php @@ -1757,7 +1757,7 @@ function syslog_messages($tab = 'syslog') { if (cacti_sizeof($detail_messages)) { foreach ($detail_messages as $dm) { $severity_class = syslog_row_color($dm['priority_id'], $dm['message']); - print "