Jump to content

[deprecated] RockGrid - powerful, performant and beautiful data listing tool


bernhard

Recommended Posts

Important security update!

Hi RockGrid users,

I'm very sorry for that, but I have to announce a security update. If you are using RockGrid on a public site please upgrade to v0.0.22 (Fieldtype) immediately. It is a simple but important update: https://github.com/BernhardBaumrock/FieldtypeRockGrid/commit/0be2086139c84f775937246ed2985ac4c4a3e9c3; The proplem exists on all RockGrid fields with AJAX turned ON. In this case it was theoretically possible to expose the field data to a user that should not be allowed to see this data (in the worst case even a guest user) if the user knew how to do it and he also knew the name of the rockgrid field.

The update now restricts access for AJAX field data to superusers only. You can easily adjust that via simple hooks:

// rockgrid access control
$wire->addHookAfter("InputfieldRockGrid::access", function(HookEvent $event) {
  // all grid data is accessible for all logged in users
  $event->return = $this->user->isLoggedin();
});

Or more granular via the fieldname:

// rockgrid access control
$wire->addHookAfter("InputfieldRockGrid::access", function(HookEvent $event) {
  $field = $event->arguments(0);
  $user = $this->user;
  $access = $event->return;

  switch($field) {
    case 'field1':
    case 'field2':
    case 'field3':
      $access = $user->isLoggedin();
      break;

    case 'field4':
      $access = ($user->name == 'foo');
      break;
  }

  $event->return = $access;
});

Field 1-3 is allowed for logged in users, field4 only for user foo and all other fields only for superusers (default rule).

I'm not totally happy any more with several aspects of RockFinder and RockGrid, but it is the best option I have so far (until I can build something totally new, maybe with tabulator if tests work well).

Special thx to @Zeka for bringing this issue to my attention by coincidence in the other topic!

  • Like 6
  • Thanks 1
Link to comment
Share on other sites

I am trying to figure out how to join pages from two templates into a grid. I will attach a picture of an incorrect result just as a talking point:

rockfinder_join.thumb.png.c85d712768f896aeba2c03a56c3c8427.png

The goal would be to plonk the data from unive into the grid, with rows filled only when code and number match the ones in the main (A-T) grid. The incorrectly repeating result in the screenshot was reached with this:

$finder1 = new RockFinder('template=A-T', ['code', 'nb', 'variation', 'name']);
$finder2 = new RockFinder('template=unive3', ['code', 'nb', 'proverbtype']);
// join finder
$finder1->join($finder2, 'unive', ['code' => 'code']);
$this->setData($finder1);

So how can I match by two fields to get what I want?

Link to comment
Share on other sites

Hi Beluga,

is this a tabulator grid? Is it a custom module or the rockgrid extension you've linked some time ago?

Regarding your join: I think in that case it would be the easiest to join them via plain sql; Something like

$foo = $finder1->getSQL();
$bar = $finder2->getSQL();
$sql = "SELECT * FROM ($foo) AS foo LEFT JOIN ($bar) as bar ON (foo.col1 = bar.col1 AND foo.col2 = bar.col2)";
$this->setData($sql);

PS: Be careful when joining / listing tables that have same name columns! This can lead to different results in the grid than in the resulting sql table. Compare the results to a regular SQL client by copying the resulting sql and executing it in Adminer and similar...

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Woooaw - with your query and renaming the fields of the other template, I got a perfect result!! (You were right that the column names have to be different) Thanks a lot.

This is using my old hacky Tabulator grid 🙂

  • Like 2
Link to comment
Share on other sites

Glad it worked 🙂

Yeah, it's good old SQL and RockFinder taking away the complexity of getting all fields related to a page/template and taking into account PW statuses. Though one has to be careful about access control related to fields, related pages, referenced page statuses etc...

Link to comment
Share on other sites

  • 2 weeks later...

Should the page refresh when using the view, edit, delete if i would delete the page through RockGrid?

 

col = RockGrid.colDefs.rowActions(col);
col.pinned = 'left';
col.width = 120;

image.png.7962f6743de24484cf2b02eb685a8cca.png

For now it just spins and if i refresh the page it shows that the deletion worked.

 

My console:

[{action: "trash", payload: ["1949"], response: "Trashed 1 pages"}]

Link to comment
Share on other sites

36 minutes ago, gottberg said:

Any ideas?

Sorry, no - otherwise I would of course have posted them above. Please debug it, check the console for errors, try different browsers etc.; It is working here on all my installations.

Link to comment
Share on other sites

Sorry, didnt think that through 😄

I get the same errors i Firefox:

JqueryCore.js?v=1545420649:2 POST http://localhost/celsa/pw/celsacalc/?RockGrid=1&field=Transportzoner net::ERR_CONTENT_DECODING_FAILED 200 (OK)

Could i have some issues with the Module?

image.png.a242f17b66d4f524dae8d01bf03742b3.png

Also shows undefiend: 25

 

Edit: Trashcan also shows as undefined.

Link to comment
Share on other sites

On 6/30/2018 at 5:38 PM, bernhard said:

Support: Please note that this module might not be as easy and plug&play as many other modules. It needs a good understanding of agGrid (and JavaScript in general) and it likely needs some looks into the code to get all the options. Please understand that I can not provide free support for every request here in the forum. I try to answer all questions that might also help others or that might improve the module but for individual requests I offer paid support for 60€ per hour (excl vat).

I'm sorry but I can't help you further than I did with this one. If you want me to have a look at your setup you can contact me via email/PM.

Link to comment
Share on other sites

8 hours ago, gottberg said:

Could i have some issues with the Module?

Looking at the error you got, you could fix it by enabling zlib.output_compression in your php.ini.

ps: to be clear, you have a server issue.

 

 

Edited by flydev
ps
Link to comment
Share on other sites

  • 2 weeks later...
On 6/4/2019 at 11:48 AM, bernhard said:

I'm sorry but I can't help you further than I did with this one. If you want me to have a look at your setup you can contact me via email/PM.

Thank you so much for the help you gave! Bernhard helped me through Skype and TeamViewer and solved the issue. I have and had some issues with MAMP.

He also gave me some pointers of how to use RockGrid and best practises etc. Worth every €!!!

I recommend to use RockGrid if you need to list and edit data. I also recommend to contact Bernhard and buy some support if you want to quickly learn how to use RockGrid! 🙂 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

On 6/4/2019 at 8:13 PM, flydev said:

Looking at the error you got, you could fix it by enabling zlib.output_compression in your php.ini.

ps: to be clear, you have a server issue.

 

 

Thanks for the tip! Tried that but i doesn't help.. 😞 

Link to comment
Share on other sites

I am wondering how to optimise a query. It is taking 23 seconds on a server with 4GB of memory. It is live here: https://mattikuusiproverbtypology.fi/references/

I have considered moving to static JS data as the data in the db does not change very often.
The query is:

$finder1 = new RockFinder('template=A-T', ['code', 'nb', 'variation', 'name', 'page1', 'page2', 'page3', 'runningnb', 'additnb', 'abbrevat']);
$finder2 = new RockFinder('template=M6books', ['abbrev', 'author_editor', 'booktitle']);
$at = $finder1->getSQL();
$m6books = $finder2->getSQL();
$sql = "SELECT * FROM ($at) AS at LEFT JOIN ($m6books) as m6books ON (at.abbrevat = m6books.abbrev)";
$this->setData($sql);

I temporarily enabled slow_query_log like so in my.cnf:

long_query_time=1
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow-query.log

(with /var/log/mysql owned by mysql user)

Below is the slow query log - for some reason it contains two identical queries, each taking over 9 seconds. I wonder why that is? Due to ajax? Does this happen to others?
 

Spoiler



/usr/bin/mysqld, Version: 10.3.15-MariaDB-log (Source distribution). started with:
Tcp port: 0  Unix socket: /run/mysqld/mysqld.sock
Time            Id Command    Argument
# Time: 190616  9:07:29
# User@Host: root[root] @ localhost []
# Thread_id: 9  Schema: x  QC_hit: No
# Query_time: 9.433453  Lock_time: 0.009225  Rows_sent: 36276  Rows_examined: 515142
# Rows_affected: 0  Bytes_sent: 5495003
use x;
SET timestamp=1560665249;
SELECT * FROM (SELECT
    `rockfinder`.*
FROM
    /* original pw query */
    (SELECT pages.id
    FROM `pages`
    LEFT JOIN pages_access ON (pages_access.pages_id=pages.id AND pages_access.templates_id IN(2,3))
    WHERE (pages.templates_id=43)
    AND (pages.status<1024)
    AND pages.templates_id NOT IN(2,3)
    AND pages_access.pages_id IS NULL
    GROUP BY pages.id ) as `pwfinder`

/* rockfinder */
LEFT JOIN (    SELECT
      `pages`.`id` AS `id`,
      `code`.`code` AS `code`,
      `nb`.`nb` AS `nb`,
      `variation`.`variation` AS `variation`,
      `name`.`name` AS `name`,
      `page1`.`page1` AS `page1`,
      `page2`.`page2` AS `page2`,
      `page3`.`page3` AS `page3`,
      `runningnb`.`runningnb` AS `runningnb`,
      `additnb`.`additnb` AS `additnb`,
      `abbrevat`.`abbrevat` AS `abbrevat`
    FROM
      `pages`
    
    /* --- join code --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `code`.`data` AS `code`
    FROM `field_code` AS `code`) AS `code` ON `code`.`pageid` = `pages`.`id`
    /* --- end code --- */
    
    
    /* --- join nb --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `nb`.`data` AS `nb`
    FROM `field_nb` AS `nb`) AS `nb` ON `nb`.`pageid` = `pages`.`id`
    /* --- end nb --- */
    
    
    /* --- join variation --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `variation`.`data` AS `variation`
    FROM `field_variation` AS `variation`) AS `variation` ON `variation`.`pageid` = `pages`.`id`
    /* --- end variation --- */
    
    
    /* --- join name --- */
    LEFT JOIN (SELECT `id` AS `pageid`, `name` FROM `pages` AS `name`) AS `name` ON `name`.`pageid` = `pages`.`id`
    /* --- end name --- */
    
    
    /* --- join page1 --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `page1`.`data` AS `page1`
    FROM `field_page1` AS `page1`) AS `page1` ON `page1`.`pageid` = `pages`.`id`
    /* --- end page1 --- */
    
    
    /* --- join page2 --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `page2`.`data` AS `page2`
    FROM `field_page2` AS `page2`) AS `page2` ON `page2`.`pageid` = `pages`.`id`
    /* --- end page2 --- */
    
    
    /* --- join page3 --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `page3`.`data` AS `page3`
    FROM `field_page3` AS `page3`) AS `page3` ON `page3`.`pageid` = `pages`.`id`
    /* --- end page3 --- */
    
    
    /* --- join runningnb --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `runningnb`.`data` AS `runningnb`
    FROM `field_runningnb` AS `runningnb`) AS `runningnb` ON `runningnb`.`pageid` = `pages`.`id`
    /* --- end runningnb --- */
    
    
    /* --- join additnb --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `additnb`.`data` AS `additnb`
    FROM `field_additnb` AS `additnb`) AS `additnb` ON `additnb`.`pageid` = `pages`.`id`
    /* --- end additnb --- */
    
    
    /* --- join abbrevat --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `abbrevat`.`data` AS `abbrevat`
    FROM `field_abbrevat` AS `abbrevat`) AS `abbrevat` ON `abbrevat`.`pageid` = `pages`.`id`
    /* --- end abbrevat --- */
    
) AS `rockfinder` ON `pwfinder`.`id` = `rockfinder`.`id`
/* end rockfinder */) AS at LEFT JOIN (SELECT
    `rockfinder`.*
FROM
    /* original pw query */
    (SELECT pages.id
    FROM `pages`
    LEFT JOIN pages_access ON (pages_access.pages_id=pages.id AND pages_access.templates_id IN(2,3))
    WHERE (pages.templates_id=45)
    AND (pages.status<1024)
    AND pages.templates_id NOT IN(2,3)
    AND pages_access.pages_id IS NULL
    GROUP BY pages.id ) as `pwfinder`

/* rockfinder */
LEFT JOIN (    SELECT
      `pages`.`id` AS `id`,
      `abbrev`.`abbrev` AS `abbrev`,
      `author_editor`.`author_editor` AS `author_editor`,
      `booktitle`.`booktitle` AS `booktitle`
    FROM
      `pages`
    
    /* --- join abbrev --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `abbrev`.`data` AS `abbrev`
    FROM `field_abbrev` AS `abbrev`) AS `abbrev` ON `abbrev`.`pageid` = `pages`.`id`
    /* --- end abbrev --- */
    
    
    /* --- join author_editor --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `author_editor`.`data` AS `author_editor`
    FROM `field_author_editor` AS `author_editor`) AS `author_editor` ON `author_editor`.`pageid` = `pages`.`id`
    /* --- end author_editor --- */
    
    
    /* --- join booktitle --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `booktitle`.`data` AS `booktitle`
    FROM `field_booktitle` AS `booktitle`) AS `booktitle` ON `booktitle`.`pageid` = `pages`.`id`
    /* --- end booktitle --- */
    
) AS `rockfinder` ON `pwfinder`.`id` = `rockfinder`.`id`
/* end rockfinder */) as m6books ON (at.abbrevat = m6books.abbrev);
# Time: 190616  9:07:39
# User@Host: root[root] @ localhost []
# Thread_id: 10  Schema: x  QC_hit: No
# Query_time: 9.203892  Lock_time: 0.001161  Rows_sent: 36276  Rows_examined: 515142
# Rows_affected: 0  Bytes_sent: 5495003
SET timestamp=1560665259;
SELECT * FROM (SELECT
    `rockfinder`.*
FROM
    /* original pw query */
    (SELECT pages.id
    FROM `pages`
    LEFT JOIN pages_access ON (pages_access.pages_id=pages.id AND pages_access.templates_id IN(2,3))
    WHERE (pages.templates_id=43)
    AND (pages.status<1024)
    AND pages_access.pages_id IS NULL
    AND pages.templates_id NOT IN(2,3)
    GROUP BY pages.id ) as `pwfinder`

/* rockfinder */
LEFT JOIN (    SELECT
      `pages`.`id` AS `id`,
      `code`.`code` AS `code`,
      `nb`.`nb` AS `nb`,
      `variation`.`variation` AS `variation`,
      `name`.`name` AS `name`,
      `page1`.`page1` AS `page1`,
      `page2`.`page2` AS `page2`,
      `page3`.`page3` AS `page3`,
      `runningnb`.`runningnb` AS `runningnb`,
      `additnb`.`additnb` AS `additnb`,
      `abbrevat`.`abbrevat` AS `abbrevat`
    FROM
      `pages`
    
    /* --- join code --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `code`.`data` AS `code`
    FROM `field_code` AS `code`) AS `code` ON `code`.`pageid` = `pages`.`id`
    /* --- end code --- */
    
    
    /* --- join nb --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `nb`.`data` AS `nb`
    FROM `field_nb` AS `nb`) AS `nb` ON `nb`.`pageid` = `pages`.`id`
    /* --- end nb --- */
    
    
    /* --- join variation --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `variation`.`data` AS `variation`
    FROM `field_variation` AS `variation`) AS `variation` ON `variation`.`pageid` = `pages`.`id`
    /* --- end variation --- */
    
    
    /* --- join name --- */
    LEFT JOIN (SELECT `id` AS `pageid`, `name` FROM `pages` AS `name`) AS `name` ON `name`.`pageid` = `pages`.`id`
    /* --- end name --- */
    
    
    /* --- join page1 --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `page1`.`data` AS `page1`
    FROM `field_page1` AS `page1`) AS `page1` ON `page1`.`pageid` = `pages`.`id`
    /* --- end page1 --- */
    
    
    /* --- join page2 --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `page2`.`data` AS `page2`
    FROM `field_page2` AS `page2`) AS `page2` ON `page2`.`pageid` = `pages`.`id`
    /* --- end page2 --- */
    
    
    /* --- join page3 --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `page3`.`data` AS `page3`
    FROM `field_page3` AS `page3`) AS `page3` ON `page3`.`pageid` = `pages`.`id`
    /* --- end page3 --- */
    
    
    /* --- join runningnb --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `runningnb`.`data` AS `runningnb`
    FROM `field_runningnb` AS `runningnb`) AS `runningnb` ON `runningnb`.`pageid` = `pages`.`id`
    /* --- end runningnb --- */
    
    
    /* --- join additnb --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `additnb`.`data` AS `additnb`
    FROM `field_additnb` AS `additnb`) AS `additnb` ON `additnb`.`pageid` = `pages`.`id`
    /* --- end additnb --- */
    
    
    /* --- join abbrevat --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `abbrevat`.`data` AS `abbrevat`
    FROM `field_abbrevat` AS `abbrevat`) AS `abbrevat` ON `abbrevat`.`pageid` = `pages`.`id`
    /* --- end abbrevat --- */
    
) AS `rockfinder` ON `pwfinder`.`id` = `rockfinder`.`id`
/* end rockfinder */) AS at LEFT JOIN (SELECT
    `rockfinder`.*
FROM
    /* original pw query */
    (SELECT pages.id
    FROM `pages`
    LEFT JOIN pages_access ON (pages_access.pages_id=pages.id AND pages_access.templates_id IN(2,3))
    WHERE (pages.templates_id=45)
    AND (pages.status<1024)
    AND pages.templates_id NOT IN(2,3)
    AND pages_access.pages_id IS NULL
    GROUP BY pages.id ) as `pwfinder`

/* rockfinder */
LEFT JOIN (    SELECT
      `pages`.`id` AS `id`,
      `abbrev`.`abbrev` AS `abbrev`,
      `author_editor`.`author_editor` AS `author_editor`,
      `booktitle`.`booktitle` AS `booktitle`
    FROM
      `pages`
    
    /* --- join abbrev --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `abbrev`.`data` AS `abbrev`
    FROM `field_abbrev` AS `abbrev`) AS `abbrev` ON `abbrev`.`pageid` = `pages`.`id`
    /* --- end abbrev --- */
    
    
    /* --- join author_editor --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `author_editor`.`data` AS `author_editor`
    FROM `field_author_editor` AS `author_editor`) AS `author_editor` ON `author_editor`.`pageid` = `pages`.`id`
    /* --- end author_editor --- */
    
    
    /* --- join booktitle --- */
    LEFT JOIN (SELECT
      `pages_id` AS `pageid`,
      `booktitle`.`data` AS `booktitle`
    FROM `field_booktitle` AS `booktitle`) AS `booktitle` ON `booktitle`.`pageid` = `pages`.`id`
    /* --- end booktitle --- */
    
) AS `rockfinder` ON `pwfinder`.`id` = `rockfinder`.`id`
/* end rockfinder */) as m6books ON (at.abbrevat = m6books.abbrev);


 

My MySQL settings on the server are:
 

Spoiler

 

[mysqld]
port            = 3306
socket          = /run/mysqld/mysqld.sock
skip-external-locking
key_buffer_size = 32M
max_allowed_packet = 256M
table_open_cache = 2048
sort_buffer_size = 8M
net_buffer_length = 8K
read_buffer_size = 2M
read_rnd_buffer_size = 16M
myisam_sort_buffer_size = 128M
init_connect = 'SET collation_connection = utf8mb4_unicode_ci,NAMES utf8mb4'
collation_server = utf8mb4_unicode_ci
character_set_client = utf8mb4
character_set_server = utf8mb4
performance_schema = on
query_cache_size = 0

innodb_data_file_path = ibdata1:10M:autoextend
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 120
innodb_stats_on_metadata = 0
innodb_buffer_pool_instances = 2
innodb_flush_method = O_DIRECT

 

Results from mysqltuner:

Spoiler

-------- Storage Engine Statistics -----------------------------------------------------------------
[--] Status: +Aria +CSV +InnoDB +MEMORY +MRG_MyISAM +MyISAM +PERFORMANCE_SCHEMA +SEQUENCE
[--] Data in InnoDB tables: 55.1M (Tables: 92)
[--] Data in MyISAM tables: 981.2K (Tables: 31)
[OK] Total fragmented tables: 0
 
-------- Analysis Performance Metrics --------------------------------------------------------------
[--] innodb_stats_on_metadata: OFF
[OK] No stat updates during querying INFORMATION_SCHEMA.
 
-------- Security Recommendations ------------------------------------------------------------------
[OK] There are no anonymous accounts for any database users
[OK] All database users have passwords assigned
[!!] There is no basic password file list!
 
-------- CVE Security Recommendations --------------------------------------------------------------
[--] Skipped due to --cvefile option undefined
 
-------- Performance Metrics -----------------------------------------------------------------------
[--] Up for: 19s (10 q [0.526 qps], 15 conn, TX: 57K, RX: 1K)
[--] Reads / Writes: 100% / 0%
[--] Binary logging is enabled (GTID MODE: OFF)
[--] Physical Memory     : 3.8G
[--] Max MySQL memory    : 6.2G
[--] Other process memory: 0B
[--] Total buffers: 2.2G global + 26.5M per thread (151 max threads)
[--] P_S Max memory usage: 104M
[--] Galera GCache Max memory usage: 0B
[OK] Maximum reached memory usage: 2.3G (60.37% of installed RAM)
[!!] Maximum possible memory usage: 6.2G (162.06% of installed RAM)
[!!] Overall possible memory usage with other process exceeded memory
[OK] Slow queries: 0% (0/10)
[OK] Highest usage of available connections: 0% (1/151)
[!!] Aborted connections: 6.67%  (1/15)
[--] Skipped name resolution test due to skip_networking=ON in system variables.
[OK] Query cache is disabled by default due to mutex contention on multiprocessor machines.
[OK] No Sort requiring temporary tables
[OK] No joins without indexes
[OK] Temporary tables created on disk: 0% (0 on disk / 4 total)
[OK] Thread cache hit rate: 93% (1 created / 15 connections)
[OK] Table cache hit rate: 64% (11 open / 17 opened)
[OK] Open file limit used: 0% (26/4K)
[OK] Table locks acquired immediately: 100% (18 immediate / 18 locks)
[OK] Binlog cache memory access: 0% (0 Memory / 0 Total)
 
-------- Performance schema ------------------------------------------------------------------------
[--] Memory used by P_S: 104.0M
[--] Sys schema is installed.
 
-------- ThreadPool Metrics ------------------------------------------------------------------------
[--] ThreadPool stat is enabled.
[--] Thread Pool Size: 4 thread(s).
[--] Using default value is good enough for your version (10.3.15-MariaDB-log)
 
-------- MyISAM Metrics ----------------------------------------------------------------------------
[!!] Key buffer used: 18.3% (6M used / 33M cache)
[OK] Key buffer size / total MyISAM indexes: 32.0M/502.0K
 
-------- InnoDB Metrics ----------------------------------------------------------------------------
[--] InnoDB is enabled.
[--] InnoDB Thread Concurrency: 0
[OK] InnoDB File per table is activated
[OK] InnoDB buffer pool / data size: 2.0G/55.1M
[OK] Ratio InnoDB log file size / InnoDB Buffer pool size: 256.0M * 2/2.0G should be equal to 25%
[OK] InnoDB buffer pool instances: 2
[--] Number of InnoDB Buffer Pool Chunk : 16 for 2 Buffer Pool Instance(s)
[OK] Innodb_buffer_pool_size aligned with Innodb_buffer_pool_chunk_size & Innodb_buffer_pool_instances
[!!] InnoDB Read buffer efficiency: 60.52% (9061 hits/ 14972 total)
[!!] InnoDB Write Log efficiency: 0% (1 hits/ 0 total)
[OK] InnoDB log waits: 0.00% (0 waits / 1 writes)
 
-------- AriaDB Metrics ----------------------------------------------------------------------------
[--] AriaDB is enabled.
[OK] Aria pagecache size / total Aria indexes: 128.0M/1B
 
-------- TokuDB Metrics ----------------------------------------------------------------------------
[--] TokuDB is disabled.
 
-------- XtraDB Metrics ----------------------------------------------------------------------------
[--] XtraDB is disabled.
 
-------- Galera Metrics ----------------------------------------------------------------------------
[--] Galera is disabled.
 
-------- Replication Metrics -----------------------------------------------------------------------
[--] Galera Synchronous replication: NO
[--] No replication slave(s) for this server.
[--] Binlog format: MIXED
[--] XA support enabled: ON
[--] Semi synchronous replication Master: OFF
[--] Semi synchronous replication Slave: OFF
[--] This is a standalone server
 
-------- Recommendations ---------------------------------------------------------------------------
General recommendations:
    MySQL was started within the last 24 hours - recommendations may be inaccurate
    Reduce your overall MySQL memory footprint for system stability
    Dedicate this server to your database for highest performance.
    Reduce or eliminate unclosed connections and network issues

 

Link to comment
Share on other sites

20 hours ago, Beluga said:

I have considered moving to static JS data as the data in the db does not change very often.

So would caching be an (easy) option?

20 hours ago, Beluga said:

Below is the slow query log - for some reason it contains two identical queries, each taking over 9 seconds. I wonder why that is? Due to ajax? Does this happen to others?

At the moment this is how RockGrid works: It makes one query to get one row (so the query should have limit=0,1) so that it knows which columns to setup for the grid. Then the second request is to get all data (and this is also used for all subsequent requests when reloading the grid).

This is not the best solution, but I have no plans to change that for RockGrid. I start working on RockTabulator today where it will load all the data at the first request and display it instantly 🙂 

  • Like 4
Link to comment
Share on other sites

2 hours ago, bernhard said:

So would caching be an (easy) option?

At the moment this is how RockGrid works: It makes one query to get one row (so the query should have limit=0,1) so that it knows which columns to setup for the grid. Then the second request is to get all data (and this is also used for all subsequent requests when reloading the grid).

This is not the best solution, but I have no plans to change that for RockGrid. I start working on RockTabulator today where it will load all the data at the first request and display it instantly 🙂 

Yep, caching might be nice going forward. Anyway, I can solve this right now with the static JS (well, in theory - have not tried yet what the effect on load time is). It is great to hear you have a plan for RockTabulator regarding this!

Link to comment
Share on other sites

  • 2 months later...

The newest version of RockGrid now supports RockFinder2 as data source 😎

$finder = new RockFinder2();
$finder->find('template=basic-page');
$finder->addColumns([
  'title',
  'body'
]);
$this->setData($finder);

Data is available on the JS side via the RockFinder2 property in the GridItem object:

xbyUN7Y.png

  • Like 5
Link to comment
Share on other sites

Another little helpful update: Added support for colDef callbacks.

Before:

  col = grid.getColDef('id');
  col = RockGrid.colDefs.rowActions(col);

  col = grid.getColDef('created');
  col.headerName = 'Datum';
  col = RockGrid.colDefs.date(col);

After:


  grid.getColDef('id', function(col) {
    col = RockGrid.colDefs.rowActions(col);
  });
  
  grid.getColDef('created', function(col) {
    col.headerName = 'Datum';
    col = RockGrid.colDefs.date(col);
  });

The benefit is that before if the column did not exist for whatever reason (eg the column is hidden for some users) the JS broke and stopped execution because "col" was undefined and setting options on an undefined column definition doesn't work.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

My first attempt at RockFinder & RockGrid and truly impressed. Well done @bernhard!

Have already created my dataset using joins, changing column headings and the tip for Select Options in my custom php file to display the option's title rather than the value in a column. All good.

Problem arises with the filter for the Select Options field, column is project_status, with column header changed to 'Status'. I've no idea how to change the filter from the PW assigned index value to the text value of the field.  See examples:

1. Full data set

1906379616_Screenshot2019-09-0617_37_47.png.e0c2b7abe08d27c672dcc70a20381c05.png

2. Using a text entry in the filter, eg starting to type 'draft'

1028955936_Screenshot2019-09-0617_38_00.png.4ece236c378671965fc04cf78ee274fd.png

3. Entering the PW assigned select options index for 'draft'

504013311_Screenshot2019-09-0617_38_17.png.3c6ef082e03d65721f3dfa02ea83ff7e.png

I'm guessing it needs a custom filter and would appreciate help and guidance.

TIA

psy

 

Link to comment
Share on other sites

Hi Psy,

In aggrid you have two concepts: valueGetters (https://www.ag-grid.com/javascript-grid-value-getters/) and cellRenderers (https://www.ag-grid.com/javascript-grid-cell-rendering-components/)

The filter filters the RAW VALUE of the cell, not the rendered value. You can either change the valueGetter of the cell or do another "workaround". But that's something conceptional when you are working with aggrid and you have to decide when to take which approach.

Have you tried double-clicking the cell, then it should filter for the value of the cell automatically. A triple click removes the filter from that column.

Link to comment
Share on other sites

11 minutes ago, psy said:

My first attempt at RockFinder & RockGrid and truly impressed. Well done @bernhard!

Thx, one can do a of great stuff with those tools and I think not many know about that... 🙂 But RockTabulator and RockFinder2 will make things a lot easier (if everything goes well).

  • Like 1
Link to comment
Share on other sites

7 minutes ago, bernhard said:

Have you tried double-clicking the cell, then it should filter for the value of the cell automatically. A triple click removes the filter from that column.

Well that worked, thanks! Not very user friendly though. The general public wont get it 😞

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By LuisM
      Symprowire is a PHP MVC Framework based and built on Symfony using ProcessWire 3.x as DBAL and Service-Provider
      It acts as a Drop-In Replacement Module to handle the Request/Response outside the ProcessWire Admin. Even tough Symfony or any other mature MVC Framework could be intimidating at first, Symprowire tries to abstract Configuration and Symfony Internals away as much as possible to give you a quick start and lift the heavy work for you.
      The main Goal is to give an easy path to follow an MVC Approach during development with ProcessWire and open up the available eco-system.
      You can find the GitHub Repo and more Information here: https://github.com/Luis85/symprowire
      Documentation
      The Symprowire Wiki https://github.com/Luis85/symprowire/wiki How to create a simple Blog with Symprowire https://github.com/Luis85/symprowire/wiki/Symprowire-Blog-Tutorial Last Update
      16.07.2021 // RC 1 v0.6.0 centralized ProcessWire access trough out the Application by wrapping to a Service https://github.com/Luis85/symprowire/releases/tag/v0.6.0-rc-1 Requirements
      PHP ^7.4 Fresh ProcessWire ^3.0.181 with a Blank Profile Composer 2 (v1 should work, not recommended) The usual Symfony Requirements Features
      Twig Dependency Injection Monolog for Symprowire Support for .env YAML Configuration Symfony Console and Console Commands Symfony Webprofiler Full ProcessWire access inside your Controller and Services Webpack Encore support Caveats
      Symfony is no small Framework and will come with a price in terms of Memory Usage and added Overhead. To give you a taste I installed Tracy Debugger alongside to compare ProcessWire profiling with the included Symfony Webprofiler

      So in a fresh install Symprowire would atleast add another 2MB of Memory usage and around 40ms in response time, should be less in production due to the added overhead of the Webprofiler in dev env
       
    • By FireWire
      Hello community!

      I want to share a new module I've been working on that I think could be a big boost for multi-language ProcessWire sites.

      Some background, I was looking for a way for our company website to be efficiently translated as working with human translators was pretty laborious and a lack of updating content created a divergence between languages. I, and several other devs here, have talked about translation integrations and have recognized the power that DeepL has. DeepL is an AI deep learning powered service that delivers translation quality beyond any automated service available. After access to the API was opened up to the US, I built Fluency, a DeepL translation integration for ProcessWire.
      Fluency brings automated translation to every multi-language field in the admin, and also provides a translation tool allowing the user to translate their text to any language without it being inside a template's field. With Fluency you can:
      Translate any plain textarea or text input Translate any CKEditor content (yes, with markup) Translate page names for fully localized URLs on every page Translate your in-template translation function wrapped strings Translate modules Fluency is free, and now so is DeepL
      Since this module was first built DeepL has introduced free Developer accounts that allow anyone to start using Fluency at zero cost and beginning with the version 0.3.0 release Fluency now supports free DeepL accounts. As of June 2021 DeepL supports translation to 26 languages and continues to offer more!
      Installation and usage is completely plug and play. Whether you're building a new multi-language site, need to update a site to multi-language, or simply want to stop manually translating a site and make any language a one-click deal, it could not be easier to do it. Fluency works by having you match the languages configured in ProcessWIre to DeepL's. You can have your site translating to any or all of the languages DeepL translates to in minutes (quite literally).
      Let's break out the screenshots...
      When the default language tab is shown, a message is displayed to let users know that translation is available. Clicking on each tab shows a link that says "Translate from English". Clicking it shows an animated overlay with the word "Translating..." cycling through each language and a light gradient shift. Have a CKEditor field? All good. Fluency will translated it and use DeepL's ability to translate text within HTML tags. CKEditor fields can be translated as easily and accurately as text/textarea fields.

      Repeaters and AJAX created fields also have translation enabled thanks to a JavaScript MutationObserver that searches for multi-language fields and adds translation as they're inserted into the DOM. If there's a multi-language field on the page, it will have translation added.

      Same goes for image description fields. Multi-language SEO friendly images are good to go.

      Creating a new page from one of your templates? Translate your title, and also translate your page name for native language URLs. (Not available for Russian, Chinese, or Japanese languages due to URL limitations). These can be changed in the "Settings" tab for any page as well so whether you're translating new pages or existing pages, you control the URLs everywhere.

      Language configuration pages are no different. Translate the names of your languages and search for both Site Translation Files (including all of your modules)

      Translate all of the static text in your templates as well. Notice that the placeholders are retained. DeepL is pretty good at recognizing and keeping non-translatable strings like that. If it is changed, it's easy to fix manually.

      Fluency adds a "Translate" item to the CMS header. When clicked this opens up a modal with a full translation tool that lets the user translate any language to any language. No need to leave the admin if you need to translate content from a secondary language back to the default ProcessWire language. There is also a button to get the current API usage statistics. DeepL account owners can set billing limitations via character count to control costs. This may help larger sites or sites being retrofitted keep an eye on their usage. Fluency can be used by users having roles given the fluency-translate permission.

      It couldn't be easier to add Fluency to your new or existing website. Simply add your API key and you're shown what languages are currently available for translation from/to as provided by DeepL. This list and all configuration options are taken live from the API so when DeepL releases new languages you can add them to your site without any work. No module updates, just an easy configuration. Just match the language you configured in ProcessWire to the DeepL language you want it to be associated with and you're done. Fluency also allows you to create a list of words/phrases that will not be translated which can prevent items such as brands and company names from being translated when they shouldn't

       
      Limitations:
      No "translate page" - Translating multiple fields can be done by clicking multiple translation links on multiple fields at once but engineering a "one click page translate" is not feasible from a user experience standpoint. The time it takes to translate one field can be a second or two, but cumulatively that may take much longer (CKEditor fields are slower than plain text fields). There may be a workaround in the future but it isn't currently on the roadmap. No "translate site" - Same thing goes for translating an entire website at once. It would be great, but it would be a very intense process and take a very (very) long time. There may be a workaround in the future but it isn't on the roadmap. No current support for Inline CKEditor fields - Handling for CKEditor on-demand hasn't been implemented yet, this is planned for a future release though and can be done. I just forgot about it because I've never really used that feature personally.. Alpha release - This module is in alpha. Releases should be stable and usable, but there may be edge case issues. Test the module thoroughly and please report any bugs via a Github issue on the repository or respond here. Please note that the browser plugin for Grammarly conflicts with Fluency (as it does with many web applications). To address this issue it is recommended that you disable Grammarly when using Fluency, or open the admin to edit pages in a private window where Grammarly may not be loaded. This is an issue that may not have a resolution as creating a workaround may not be possible. If you have insight as to how this may be solved please visit the Github page and file a bugfix ticket.
      Requirements:
      ProcessWire  3.0+ UIKit Admin Theme That's Fluency in a nutshell. A core effort in this module is to create it so that there is nothing DeepL related hard-coded in that would require updating it when DeepL offers new languages. I would like this to be a future-friendly module that doesn't require developer work to keep it up-to-date.
      The Module Is Free
      This is my first real module and I want to give it back to the community as thanks. This is the best CMS I've worked with (thank you Ryan & contributors) and a great community (thank you dear reader).
      DeepL Developer Accounts
      In addition to paid Pro Developer accounts, DeepL now offers no-cost free accounts. Now all ProcessWire developers and users can use Fluency at no cost.
      Learn more about free and paid accounts by visiting the DeepL website. Sign up for a Developer account, get an API key, and start using Fluency today.
      Download & Feedback
      Download the latest version here
      https://github.com/SkyLundy/Fluency-Translation/archive/main.zip
      Github repository:
      https://github.com/SkyLundy/Fluency-Translation
      File issues and feature requests here (your feedback and testing is greatly appreciated):
      https://github.com/SkyLundy/Fluency-Translation/issues
       
      Thank you! ¡Gracias! Ich danke Ihnen! Merci! Obrigado! Grazie! Dank u wel! Dziękuję! Спасибо! ありがとうございます! 谢谢你!

    • By tcnet
      PageViewStatistic for ProcessWire is a module to log page visits of the CMS. The records including some basic information like IP-address, browser, operating system, requested page and originate page. Please note that this module doesn't claim to be the best or most accurate.
      Advantages
      One of the biggest advantage is that this module doesn't require any external service like Google Analytics or similar. You don't have to modify your templates either. There is also no Javascript or image required.
      Disadvantages
      There is only one disadvantage. This module doesn't record visits if the browser loads the page from its browser cache. To prevent the browser from loading the page from its cache, add the following meta tags to the header of your page:
      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> How to use
      The records can be accessed via the Setup-menu of the CMS backend. The first dropdown control changes the view mode.

      Detailed records
      View mode "Detailed records" shows all visits of the selected day individually with IP-address, browser, operating system, requested page and originate page. Click the update button to see new added records.

      Cached visitor records
      View modes other than "Detailed records" are cached visitor counts which will be collected on a daily basis from the detailed records. This procedure ensures a faster display even with a large number of data records. Another advantage is that the detailed records can be deleted while the cache remains. The cache can be updated manually or automatically in a specified time period. Multiple visits from the same IP address on the same day are counted as a single visitor.

      Upgrade from older versions
      Cached visitor counts is new in version 1.0.8. If you just upgraded from an older version you might expire a delay or even an error 500 if you display cached visitor counts. The reason for this is that the cache has to be created from the records. This can take longer if your database contains many records. Sometimes it might hit the maximally execution time. Don't worry about that and keep reloading the page until the cache is completely created.
      Special Feature
      PageViewStatistic for ProcessWire can record the time a visitor viewed the page. This feature is deactivated by default. To activate open the module configuration page and activate "Record view time". If activated you will find a new column "S." in the records which means the time of view in seconds. With every page request, a Javascript code is inserted directly after the <body> tag. Every time the visitor switches to another tab or closes the tab, this script reports the number of seconds the tab was visible. The initial page request is recorded only as a hyphen (-).

      New in version 1.1.0
      A new feature comes with version 1.1.0 which offers to record user names of loggedin visitors. Just activate "Record user names" and "Record loggedin user" in the module settings.
      Settings
      You can access the module settings by clicking the Configuration button at the bottom of the records page. The settings page is also available in the menu: Modules->Configure->ProcessPageViewStat.
      IP2Location
      This module uses the IP2Location database from: http://www.ip2location.com. This database is required to obtain the country from the IP address. IP2Location updates this database at the begin of every month. The settings of ProcessPageViewStat offers the ability to automatically download the database monthly. Please note, that automatically download will not work if your webspace doesn't allow allow_url_fopen.
      Dragscroll
      This module uses DragScroll. A JavaScript available from: http://github.com/asvd/dragscroll. Dragscroll adds the ability in view mode "Day" to drag the records horizontally with the mouse pointer.
      parseUserAgentStringClass
      This module uses the PHP class parseUserAgentStringClass available from: http://www.toms-world.org/blog/parseuseragentstring/. This class is required to filter out the browser type and operating system from the server request.
    • By clsource
      Inertia Adapter ProcessWire Module
      Hello! Long time no see.
      I created this module so you can use Inertia.js (https://inertiajs.com/) with ProcessWire.
      Description
      Inertia allows you to create fully client-side rendered, single-page apps, without much of the complexity that comes with modern SPAs. It does this by leveraging existing server-side frameworks.
      Inertia isn’t a framework, nor is it a replacement to your existing server-side or client-side frameworks. Rather, it’s designed to work with them. Think of Inertia as glue that connects the two. Inertia comes with three official client-side adapters (React, Vue, and Svelte).
      This is an adapter for ProcessWire. Inertia replaces PHP views altogether by returning JavaScript components from controller actions. Those components can be built with your frontend framework of choice.
      Links
      - https://github.com/joyofpw/inertia
      - https://github.com/joyofpw/inertia-svelte-mix-pw
      - https://inertiajs.com/
      Screenshots


       
    • By sms77io
      Hi all,
      we made a small module for sending SMS via Sms77.io. It supports sending to one and multiple users.
      You can download it from GitHub and follow the instructions on how to install it - it is quite easy. An API key is required for sending, get yours for free @ Sms77 and receive 0,50 €.
      Hope this helps somebody and we are open for improvement suggestions!
       
      Best regards
      André
×
×
  • Create New...