From: Dominik Csapak <d.csapak@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH manager v3 04/13] ui: add pending grid
Date: Fri, 15 May 2026 10:44:22 +0200 [thread overview]
Message-ID: <20260515085349.1123127-5-d.csapak@proxmox.com> (raw)
In-Reply-To: <20260515085349.1123127-1-d.csapak@proxmox.com>
A new grid type that gets its data from a PendingObjectGrid and displays
a parsed property string in various columns. Each column shows its own
pending changes so that this can be seen more easily.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/Makefile | 1 +
www/manager6/grid/PendingGrid.js | 134 +++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
create mode 100644 www/manager6/grid/PendingGrid.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 280a9ca6..c2c1dffb 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -100,6 +100,7 @@ JSSRC= \
grid/FirewallAliases.js \
grid/FirewallOptions.js \
grid/FirewallRules.js \
+ grid/PendingGrid.js \
grid/PoolMembers.js \
grid/Replication.js \
grid/ResourceGrid.js \
diff --git a/www/manager6/grid/PendingGrid.js b/www/manager6/grid/PendingGrid.js
new file mode 100644
index 00000000..e2d7b6c3
--- /dev/null
+++ b/www/manager6/grid/PendingGrid.js
@@ -0,0 +1,134 @@
+/* It's main use is to be a 'sub grid' for a 'PendingObjectGrid, for qemu/HardwareView
+ * and lxc/Resources.
+ */
+Ext.define('PVE.grid.PendingGrid', {
+ extend: 'Ext.grid.Panel',
+ alias: 'widget.pvePendingGrid',
+
+ /// the original store of the PendingObjectGrid, used for retrieving data
+ rstore: undefined,
+
+ /// the filter function to filter only relevant data from rstore
+ storeFilter: function (_rec) {
+ return true;
+ },
+
+ /// the parser for the data, should return an object
+ recordParser: function (key, value) {
+ let parsed = PVE.Parser.parsePropertyString(value);
+ return {
+ key,
+ ...parsed,
+ };
+ },
+
+ pendingRenderer: function (originalRenderer) {
+ originalRenderer ??= Ext.htmlEncode;
+ return function (val, mD, rec, rowIdx, colIdx, store, view) {
+ // add a ''pending parameter'
+ let txt = originalRenderer(val, mD, rec, rowIdx, colIdx, store, view, false);
+ let pendingTxt;
+
+ let pending = rec.get('pending');
+ if (pending) {
+ let dataIndex = view.up().getColumns()[colIdx].dataIndex;
+ let value = pending[dataIndex];
+ pendingTxt = originalRenderer(value, mD, rec, rowIdx, colIdx, store, view, true);
+ }
+
+ if (pendingTxt && txt && pendingTxt !== txt) {
+ txt += '<br />';
+ txt += `<span style="color: darkorange">${pendingTxt}</span>`;
+ }
+ if (pending && pendingTxt && (!txt || !rec.data.raw)) {
+ txt = `<span style="color: orange">${pendingTxt}</span>`;
+ }
+ if (pending && !pendingTxt && txt) {
+ txt = `<div style="color: darkorange; text-decoration: line-through;">${txt}</div>`;
+ }
+ if (rec.data.deleted && txt) {
+ txt = `<div style="color: darkorange; text-decoration: line-through;">${txt}</div>`;
+ }
+
+ return txt;
+ };
+ },
+
+ updateData: function () {
+ let me = this;
+ let records = [];
+ let data = me.rstore.getData();
+ (data.getSource() ?? data).each(function (rec) {
+ if (!me.storeFilter(rec)) {
+ return;
+ }
+
+ let key = rec.get('key');
+ let value = rec.get('value');
+ let deleted = rec.get('delete');
+
+ let parsed = me.recordParser(key, value);
+ if (parsed) {
+ parsed.raw = value;
+ }
+
+ let pending = rec.get('pending');
+ let parsedPending;
+ if (pending) {
+ parsedPending = me.recordParser(key, pending);
+ parsedPending.id = key;
+ parsedPending.raw = pending;
+ }
+
+ records.push({
+ ...parsed,
+ id: key,
+ key,
+ pending: parsedPending,
+ deleted,
+ });
+ });
+
+ me.getStore().setData(records);
+ },
+
+ store: {},
+
+ columns: [],
+
+ initComponent: function () {
+ let me = this;
+
+ if (!me.rstore) {
+ throw new 'no rstore defined'();
+ }
+
+ let columns = [];
+
+ // overwrite renderer to be pending
+ //
+ // CAUTION: don't modify the original column objects, rather copy them
+ for (const column of me.columns ?? []) {
+ let originalRenderer = column.renderer;
+ // might be a string (named scope)
+ if (Ext.isString(originalRenderer)) {
+ let renderString = originalRenderer.toString();
+ originalRenderer = function () {
+ return Ext.callback(renderString, me.scope, arguments, 0, me);
+ };
+ }
+
+ let renderer = me.pendingRenderer(originalRenderer);
+ columns.push({
+ ...column,
+ renderer,
+ });
+ }
+
+ me.columns = columns;
+
+ me.callParent();
+
+ me.mon(me.rstore, 'refresh', me.updateData, me);
+ },
+});
--
2.47.3
next prev parent reply other threads:[~2026-05-15 8:54 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-15 8:44 [PATCH manager v3 00/13] ui: split out disks and nics into grids Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 01/13] ui: utils: factor out 'media=cdrom' check Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 02/13] ui: factor out the guest key nic regex check Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 03/13] ui: parser: qemu drive: allow '-' in key names Dominik Csapak
2026-05-15 8:44 ` Dominik Csapak [this message]
2026-05-15 8:44 ` [PATCH manager v3 05/13] ui: revert button: add parentXType and reloadCallback Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 06/13] ui: button: add config remove button Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 07/13] ui: qemu: hardware: wrap in container Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 08/13] ui: qemu: introduce hardware disk grid Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 09/13] ui: qemu: introduce hardware net grid Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 10/13] ui: qemu: hardware view: separate disks into own grid Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 11/13] ui: qemu: hardware view: separate nics " Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 12/13] ui: qemu: hardware view: inline edit/remove/revert button in general grid Dominik Csapak
2026-05-15 8:44 ` [PATCH manager v3 13/13] ui: qemu: hardware view: inline 'add efi' menuitem Dominik Csapak
2026-05-15 9:18 ` [PATCH manager v3 00/13] ui: split out disks and nics into grids Dominik Csapak
2026-05-15 9:20 ` Dominik Csapak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260515085349.1123127-5-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox