* [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable
@ 2023-02-22 7:51 Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 1/6] ui: remove 'Storage View' Dominik Csapak
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
this series allows configuring the sorting of the resource tree
options are the sort-field, if guest types are grouped and if templates
are grouped seperately. it's configurable via browser local storage
the first 2 patches are not really related but popped up during
development
changes from v2:
* improved browser local storage notice
* added padding between the view selector and the button
changes from v1:
* drop the datacenter config options for now
* rename TreeSortingEdit into TreeSortingEdit
* since we don't have a fallback besides the default, display the
defauls in the dropdowns
* don't use booleanfield anymore (because of above change)
* rename sp into localStorage
* use fieldDefaults
* refactor stuff into PVE.UIOptions (a new singleton)
* remove storage view
* remove booleanfield()
Dominik Csapak (6):
ui: remove 'Storage View'
ui: remove unused booleanfield
ui: refactor ui option related methods into UIOptions
ui: refactor refreshing the the resource store/tree
ui: add window for changing tree related options
fix #1408: ui: ResourceTree: sort the tree according to tree-sorting
options
www/manager6/Makefile | 3 +-
www/manager6/UIOptions.js | 107 ++++++++++++++++++++++++
www/manager6/Utils.js | 92 +-------------------
www/manager6/Workspace.js | 29 ++++++-
www/manager6/data/ResourceStore.js | 2 +-
www/manager6/dc/OptionView.js | 23 ++---
www/manager6/form/Boolean.js | 10 ---
www/manager6/form/GlobalSearchField.js | 2 +-
www/manager6/form/Tag.js | 6 +-
www/manager6/form/TagColorGrid.js | 2 +-
www/manager6/form/TagEdit.js | 10 +--
www/manager6/form/ViewSelector.js | 7 --
www/manager6/tree/ResourceTree.js | 56 ++++++++++---
www/manager6/window/TreeSettingsEdit.js | 87 +++++++++++++++++++
14 files changed, 290 insertions(+), 146 deletions(-)
create mode 100644 www/manager6/UIOptions.js
delete mode 100644 www/manager6/form/Boolean.js
create mode 100644 www/manager6/window/TreeSettingsEdit.js
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] [PATCH manager v3 1/6] ui: remove 'Storage View'
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
@ 2023-02-22 7:51 ` Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 2/6] ui: remove unused booleanfield Dominik Csapak
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
it is basically the 'Server View' but with less content, and has often
times lead to confusion when uses accidentally selected it.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/form/ViewSelector.js | 7 -------
1 file changed, 7 deletions(-)
diff --git a/www/manager6/form/ViewSelector.js b/www/manager6/form/ViewSelector.js
index 45fabd7ef..e25547c41 100644
--- a/www/manager6/form/ViewSelector.js
+++ b/www/manager6/form/ViewSelector.js
@@ -26,13 +26,6 @@ Ext.define('PVE.form.ViewSelector', {
text: gettext('Folder View'),
groups: ['type'],
},
- storage: {
- text: gettext('Storage View'),
- groups: ['node'],
- filterfn: function(node) {
- return node.data.type === 'storage' || node.data.type === 'node';
- },
- },
pool: {
text: gettext('Pool View'),
groups: ['pool'],
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] [PATCH manager v3 2/6] ui: remove unused booleanfield
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 1/6] ui: remove 'Storage View' Dominik Csapak
@ 2023-02-22 7:51 ` Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 3/6] ui: refactor ui option related methods into UIOptions Dominik Csapak
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
it's not used anymore, does not belong into pve-manager (rather in
proxmox-widget-toolkit), does not have a proper alias.
it's simple enough to recreate should we ever need it again
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/Makefile | 1 -
www/manager6/form/Boolean.js | 10 ----------
2 files changed, 11 deletions(-)
delete mode 100644 www/manager6/form/Boolean.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 05afeda40..6a0cb73b7 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -19,7 +19,6 @@ JSSRC= \
form/AgentFeatureSelector.js \
form/BackupModeSelector.js \
form/BandwidthSelector.js \
- form/Boolean.js \
form/BridgeSelector.js \
form/BusTypeSelector.js \
form/CPUModelSelector.js \
diff --git a/www/manager6/form/Boolean.js b/www/manager6/form/Boolean.js
deleted file mode 100644
index f67c72445..000000000
--- a/www/manager6/form/Boolean.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
- extend: 'Proxmox.form.KVComboBox',
- alias: ['widget.booleanfield'],
- comboItems: [
- ['__default__', gettext('Default')],
- [1, gettext('Yes')],
- [0, gettext('No')],
- ],
-});
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] [PATCH manager v3 3/6] ui: refactor ui option related methods into UIOptions
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 1/6] ui: remove 'Storage View' Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 2/6] ui: remove unused booleanfield Dominik Csapak
@ 2023-02-22 7:51 ` Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 4/6] ui: refactor refreshing the the resource store/tree Dominik Csapak
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
a new singleton like Utils/Parser, intended for holding stuff for
ui options, such as the tag settings/overrides
no behavioural change intended
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/Makefile | 1 +
www/manager6/UIOptions.js | 92 ++++++++++++++++++++++++++
www/manager6/Utils.js | 92 +-------------------------
www/manager6/Workspace.js | 2 +-
www/manager6/data/ResourceStore.js | 2 +-
www/manager6/dc/OptionView.js | 22 +++---
www/manager6/form/GlobalSearchField.js | 2 +-
www/manager6/form/Tag.js | 6 +-
www/manager6/form/TagColorGrid.js | 2 +-
www/manager6/form/TagEdit.js | 10 +--
www/manager6/tree/ResourceTree.js | 2 +-
11 files changed, 119 insertions(+), 114 deletions(-)
create mode 100644 www/manager6/UIOptions.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 6a0cb73b7..2c487655f 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -4,6 +4,7 @@ JSSRC= \
Parser.js \
StateProvider.js \
Utils.js \
+ UIOptions.js \
Toolkit.js \
VNCConsole.js \
button/ConsoleButton.js \
diff --git a/www/manager6/UIOptions.js b/www/manager6/UIOptions.js
new file mode 100644
index 000000000..c80a7c859
--- /dev/null
+++ b/www/manager6/UIOptions.js
@@ -0,0 +1,92 @@
+Ext.define('PVE.UIOptions', {
+ singleton: true,
+
+ options: {
+ 'allowed-tags': [],
+ },
+
+ update: function() {
+ Proxmox.Utils.API2Request({
+ url: '/cluster/options',
+ method: 'GET',
+ success: function(response) {
+ for (const option of ['allowed-tags', 'console', 'tag-style']) {
+ PVE.UIOptions.options[option] = response?.result?.data?.[option];
+ }
+
+ PVE.UIOptions.updateTagList(PVE.UIOptions.options['allowed-tags']);
+ PVE.UIOptions.updateTagSettings(PVE.UIOptions.options['tag-style']);
+ },
+ });
+ },
+
+ tagList: [],
+
+ updateTagList: function(tags) {
+ PVE.UIOptions.tagList = [...new Set([...tags])].sort();
+ },
+
+ parseTagOverrides: function(overrides) {
+ let colors = {};
+ (overrides || "").split(';').forEach(color => {
+ if (!color) {
+ return;
+ }
+ let [tag, color_hex, font_hex] = color.split(':');
+ let r = parseInt(color_hex.slice(0, 2), 16);
+ let g = parseInt(color_hex.slice(2, 4), 16);
+ let b = parseInt(color_hex.slice(4, 6), 16);
+ colors[tag] = [r, g, b];
+ if (font_hex) {
+ colors[tag].push(parseInt(font_hex.slice(0, 2), 16));
+ colors[tag].push(parseInt(font_hex.slice(2, 4), 16));
+ colors[tag].push(parseInt(font_hex.slice(4, 6), 16));
+ }
+ });
+ return colors;
+ },
+
+ tagOverrides: {},
+
+ updateTagOverrides: function(colors) {
+ let sp = Ext.state.Manager.getProvider();
+ let color_state = sp.get('colors', '');
+ let browser_colors = PVE.UIOptions.parseTagOverrides(color_state);
+ PVE.UIOptions.tagOverrides = Ext.apply({}, browser_colors, colors);
+ },
+
+ updateTagSettings: function(style) {
+ let overrides = style?.['color-map'];
+ PVE.UIOptions.updateTagOverrides(PVE.UIOptions.parseTagOverrides(overrides ?? ""));
+
+ let shape = style?.shape ?? 'circle';
+ if (shape === '__default__') {
+ style = 'circle';
+ }
+
+ Ext.ComponentQuery.query('pveResourceTree')[0].setUserCls(`proxmox-tags-${shape}`);
+
+ if (!PVE.data.ResourceStore.isLoading() && PVE.data.ResourceStore.isLoaded()) {
+ PVE.data.ResourceStore.fireEvent('load');
+ }
+ Ext.GlobalEvents.fireEvent('loadedUiOptions');
+ },
+
+ tagTreeStyles: {
+ '__default__': `${Proxmox.Utils.defaultText} (${gettext('Circle')})`,
+ 'full': gettext('Full'),
+ 'circle': gettext('Circle'),
+ 'dense': gettext('Dense'),
+ 'none': Proxmox.Utils.NoneText,
+ },
+
+ tagOrderOptions: {
+ '__default__': `${Proxmox.Utils.defaultText} (${gettext('Alphabetical')})`,
+ 'config': gettext('Configuration'),
+ 'alphabetical': gettext('Alphabetical'),
+ },
+
+ shouldSortTags: function() {
+ return !(PVE.UIOptions.options['tag-style']?.ordering === 'config');
+ },
+});
diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index fcc668c3a..7bf3955a1 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1334,7 +1334,7 @@ Ext.define('PVE.Utils', {
allowSpice = consoles.spice;
allowXtermjs = !!consoles.xtermjs;
}
- let dv = PVE.UIOptions.console || (type === 'kvm' ? 'vv' : 'xtermjs');
+ let dv = PVE.UIOptions.options.console || (type === 'kvm' ? 'vv' : 'xtermjs');
if (dv === 'vv' && !allowSpice) {
dv = allowXtermjs ? 'xtermjs' : 'html5';
} else if (dv === 'xtermjs' && !allowXtermjs) {
@@ -1857,95 +1857,11 @@ Ext.define('PVE.Utils', {
notesTemplateVars: ['cluster', 'guestname', 'node', 'vmid'],
- updateUIOptions: function() {
- Proxmox.Utils.API2Request({
- url: '/cluster/options',
- method: 'GET',
- success: function(response) {
- PVE.UIOptions = {
- 'allowed-tags': [],
- };
- for (const option of ['allowed-tags', 'console', 'tag-style']) {
- PVE.UIOptions[option] = response?.result?.data?.[option];
- }
-
- PVE.Utils.updateTagList(PVE.UIOptions['allowed-tags']);
- PVE.Utils.updateTagSettings(PVE.UIOptions?.['tag-style']);
- },
- });
- },
-
- tagList: [],
-
- updateTagList: function(tags) {
- PVE.Utils.tagList = [...new Set([...tags])].sort();
- },
-
- parseTagOverrides: function(overrides) {
- let colors = {};
- (overrides || "").split(';').forEach(color => {
- if (!color) {
- return;
- }
- let [tag, color_hex, font_hex] = color.split(':');
- let r = parseInt(color_hex.slice(0, 2), 16);
- let g = parseInt(color_hex.slice(2, 4), 16);
- let b = parseInt(color_hex.slice(4, 6), 16);
- colors[tag] = [r, g, b];
- if (font_hex) {
- colors[tag].push(parseInt(font_hex.slice(0, 2), 16));
- colors[tag].push(parseInt(font_hex.slice(2, 4), 16));
- colors[tag].push(parseInt(font_hex.slice(4, 6), 16));
- }
- });
- return colors;
- },
-
- tagOverrides: {},
-
- updateTagOverrides: function(colors) {
- let sp = Ext.state.Manager.getProvider();
- let color_state = sp.get('colors', '');
- let browser_colors = PVE.Utils.parseTagOverrides(color_state);
- PVE.Utils.tagOverrides = Ext.apply({}, browser_colors, colors);
- },
-
- updateTagSettings: function(style) {
- let overrides = style?.['color-map'];
- PVE.Utils.updateTagOverrides(PVE.Utils.parseTagOverrides(overrides ?? ""));
-
- let shape = style?.shape ?? 'circle';
- if (shape === '__default__') {
- style = 'circle';
- }
-
- Ext.ComponentQuery.query('pveResourceTree')[0].setUserCls(`proxmox-tags-${shape}`);
-
- if (!PVE.data.ResourceStore.isLoading() && PVE.data.ResourceStore.isLoaded()) {
- PVE.data.ResourceStore.fireEvent('load');
- }
- Ext.GlobalEvents.fireEvent('loadedUiOptions');
- },
-
- tagTreeStyles: {
- '__default__': `${Proxmox.Utils.defaultText} (${gettext('Circle')})`,
- 'full': gettext('Full'),
- 'circle': gettext('Circle'),
- 'dense': gettext('Dense'),
- 'none': Proxmox.Utils.NoneText,
- },
-
- tagOrderOptions: {
- '__default__': `${Proxmox.Utils.defaultText} (${gettext('Alphabetical')})`,
- 'config': gettext('Configuration'),
- 'alphabetical': gettext('Alphabetical'),
- },
-
renderTags: function(tagstext, overrides) {
let text = '';
if (tagstext) {
let tags = (tagstext.split(/[,; ]/) || []).filter(t => !!t);
- if (PVE.Utils.shouldSortTags()) {
+ if (PVE.UIOptions.shouldSortTags()) {
tags = tags.sort((a, b) => {
let alc = a.toLowerCase();
let blc = b.toLowerCase();
@@ -1960,10 +1876,6 @@ Ext.define('PVE.Utils', {
return text;
},
- shouldSortTags: function() {
- return !(PVE.UIOptions?.['tag-style']?.ordering === 'config');
- },
-
tagCharRegex: /^[a-z0-9+_.-]+$/i,
verificationStateOrder: {
diff --git a/www/manager6/Workspace.js b/www/manager6/Workspace.js
index d0f7ff760..a3872b560 100644
--- a/www/manager6/Workspace.js
+++ b/www/manager6/Workspace.js
@@ -158,7 +158,7 @@ Ext.define('PVE.StdWorkspace', {
},
});
- PVE.Utils.updateUIOptions();
+ PVE.UIOptions.update();
Proxmox.Utils.API2Request({
url: '/cluster/sdn',
diff --git a/www/manager6/data/ResourceStore.js b/www/manager6/data/ResourceStore.js
index 91473a547..f3a5c4d81 100644
--- a/www/manager6/data/ResourceStore.js
+++ b/www/manager6/data/ResourceStore.js
@@ -295,7 +295,7 @@ Ext.define('PVE.data.ResourceStore', {
},
tags: {
header: gettext('Tags'),
- renderer: (value) => PVE.Utils.renderTags(value, PVE.Utils.tagOverrides),
+ renderer: (value) => PVE.Utils.renderTags(value, PVE.UIOptions.tagOverrides),
type: 'string',
sortable: true,
flex: 1,
diff --git a/www/manager6/dc/OptionView.js b/www/manager6/dc/OptionView.js
index 9c803beef..4435876dd 100644
--- a/www/manager6/dc/OptionView.js
+++ b/www/manager6/dc/OptionView.js
@@ -358,11 +358,11 @@ Ext.define('PVE.dc.OptionView', {
if (value === undefined) {
return gettext('No Overrides');
}
- let colors = PVE.Utils.parseTagOverrides(value?.['color-map']);
+ let colors = PVE.UIOptions.parseTagOverrides(value?.['color-map']);
let shape = value.shape;
- let shapeText = PVE.Utils.tagTreeStyles[shape ?? '__default__'];
+ let shapeText = PVE.UIOptions.tagTreeStyles[shape ?? '__default__'];
let txt = Ext.String.format(gettext("Tree Shape: {0}"), shapeText);
- let orderText = PVE.Utils.tagOrderOptions[value.ordering ?? '__default__'];
+ let orderText = PVE.UIOptions.tagOrderOptions[value.ordering ?? '__default__'];
txt += `, ${Ext.String.format(gettext("Ordering: {0}"), orderText)}`;
if (value['case-sensitive']) {
txt += `, ${gettext('Case-Sensitive')}`;
@@ -453,7 +453,7 @@ Ext.define('PVE.dc.OptionView', {
],
},
store: {
- data: Object.entries(PVE.Utils.tagTreeStyles).map(v => ({
+ data: Object.entries(PVE.UIOptions.tagTreeStyles).map(v => ({
value: v[0],
display: v[1],
})),
@@ -466,7 +466,7 @@ Ext.define('PVE.dc.OptionView', {
name: 'ordering',
xtype: 'proxmoxKVComboBox',
fieldLabel: gettext('Ordering'),
- comboItems: Object.entries(PVE.Utils.tagOrderOptions),
+ comboItems: Object.entries(PVE.UIOptions.tagOrderOptions),
defaultValue: '__default__',
value: '__default__',
deleteEmpty: true,
@@ -503,7 +503,7 @@ Ext.define('PVE.dc.OptionView', {
let mode = value?.['user-allow'] ?? 'free';
let list = value?.['user-allow-list']?.join(',') ?? '';
let modeTxt = Ext.String.format(gettext('Mode: {0}'), mode);
- let overrides = PVE.Utils.tagOverrides;
+ let overrides = PVE.UIOptions.tagOverrides;
let tags = PVE.Utils.renderTags(list, overrides);
let listTxt = tags !== '' ? `, ${gettext('Pre-defined:')} ${tags}` : '';
return `${modeTxt}${listTxt}`;
@@ -520,7 +520,7 @@ Ext.define('PVE.dc.OptionView', {
if (value === undefined) {
return gettext('No Registered Tags');
}
- let overrides = PVE.Utils.tagOverrides;
+ let overrides = PVE.UIOptions.tagOverrides;
return PVE.Utils.renderTags(value.join(','), overrides);
},
header: gettext('Registered Tags'),
@@ -559,13 +559,13 @@ Ext.define('PVE.dc.OptionView', {
}
var rec = store.getById('console');
- PVE.UIOptions.console = rec.data.value;
+ PVE.UIOptions.options.console = rec.data.value;
if (rec.data.value === '__default__') {
- delete PVE.UIOptions.console;
+ delete PVE.UIOptions.options.console;
}
- PVE.UIOptions['tag-style'] = store.getById('tag-style')?.data?.value;
- PVE.Utils.updateTagSettings(PVE.UIOptions['tag-style']);
+ PVE.UIOptions.options['tag-style'] = store.getById('tag-style')?.data?.value;
+ PVE.UIOptions.updateTagSettings(PVE.UIOptions.options['tag-style']);
});
me.on('activate', me.rstore.startUpdate);
diff --git a/www/manager6/form/GlobalSearchField.js b/www/manager6/form/GlobalSearchField.js
index 8e815d4f5..c009ac8b7 100644
--- a/www/manager6/form/GlobalSearchField.js
+++ b/www/manager6/form/GlobalSearchField.js
@@ -80,7 +80,7 @@ Ext.define('PVE.form.GlobalSearchField', {
flex: 1,
dataIndex: 'text',
renderer: function(value, mD, rec) {
- let overrides = PVE.Utils.tagOverrides;
+ let overrides = PVE.UIOptions.tagOverrides;
let tags = PVE.Utils.renderTags(rec.data.tags, overrides);
return `${value}${tags}`;
},
diff --git a/www/manager6/form/Tag.js b/www/manager6/form/Tag.js
index 6fda2e848..be72d7ba9 100644
--- a/www/manager6/form/Tag.js
+++ b/www/manager6/form/Tag.js
@@ -61,7 +61,7 @@ Ext.define('Proxmox.form.Tag', {
userCls: 'proxmox-tags-full',
displayField: 'tag',
itemTpl: [
- '{[Proxmox.Utils.getTagElement(values.tag, PVE.Utils.tagOverrides)]}',
+ '{[Proxmox.Utils.getTagElement(values.tag, PVE.UIOptions.tagOverrides)]}',
],
store: [],
listeners: {
@@ -76,7 +76,7 @@ Ext.define('Proxmox.form.Tag', {
});
}
me.picker.getStore()?.clearFilter();
- let taglist = PVE.Utils.tagList.filter(v => !me.filter.includes(v)).map(v => ({ tag: v }));
+ let taglist = PVE.UIOptions.tagList.filter(v => !me.filter.includes(v)).map(v => ({ tag: v }));
if (taglist.length < 1) {
return;
}
@@ -154,7 +154,7 @@ Ext.define('Proxmox.form.Tag', {
setColor: function(tag) {
let me = this;
- let rgb = PVE.Utils.tagOverrides[tag] ?? Proxmox.Utils.stringToRGB(tag);
+ let rgb = PVE.UIOptions.tagOverrides[tag] ?? Proxmox.Utils.stringToRGB(tag);
let cls = Proxmox.Utils.getTextContrastClass(rgb);
let color = Proxmox.Utils.rgbToCss(rgb);
diff --git a/www/manager6/form/TagColorGrid.js b/www/manager6/form/TagColorGrid.js
index 3ad8e07f0..310f18e66 100644
--- a/www/manager6/form/TagColorGrid.js
+++ b/www/manager6/form/TagColorGrid.js
@@ -295,7 +295,7 @@ Ext.define('PVE.form.TagColorGrid', {
dataIndex: 'tag',
xtype: 'widgetcolumn',
onWidgetAttach: function(col, widget, rec) {
- widget.getStore().setData(PVE.Utils.tagList.map(v => ({ tag: v })));
+ widget.getStore().setData(PVE.UIOptions.tagList.map(v => ({ tag: v })));
},
widget: {
xtype: 'combobox',
diff --git a/www/manager6/form/TagEdit.js b/www/manager6/form/TagEdit.js
index e1cd4af67..094f44626 100644
--- a/www/manager6/form/TagEdit.js
+++ b/www/manager6/form/TagEdit.js
@@ -41,7 +41,7 @@ Ext.define('PVE.panel.TagEditContainer', {
onRender: function(v) {
let me = this;
let view = me.getView();
- view.toggleCls('hide-handles', PVE.Utils.shouldSortTags());
+ view.toggleCls('hide-handles', PVE.UIOptions.shouldSortTags());
view.dragzone = Ext.create('Ext.dd.DragZone', v.getEl(), {
getDragData: function(e) {
@@ -53,7 +53,7 @@ Ext.define('PVE.panel.TagEditContainer', {
let cmp = Ext.getCmp(sourceId);
let ddel = document.createElement('div');
ddel.classList.add('proxmox-tags-full');
- ddel.innerHTML = Proxmox.Utils.getTagElement(cmp.tag, PVE.Utils.tagOverrides);
+ ddel.innerHTML = Proxmox.Utils.getTagElement(cmp.tag, PVE.UIOptions.tagOverrides);
let repairXY = Ext.fly(source).getXY();
cmp.setDisabled(true);
ddel.id = Ext.id();
@@ -141,7 +141,7 @@ Ext.define('PVE.panel.TagEditContainer', {
// get a current tag list for editing
if (editMode) {
- PVE.Utils.updateUIOptions();
+ PVE.UIOptions.update();
}
me.forEachTag((tag) => {
@@ -192,7 +192,7 @@ Ext.define('PVE.panel.TagEditContainer', {
let view = me.getView();
let vm = me.getViewModel();
let index = view.items.length - 5;
- if (PVE.Utils.shouldSortTags() && !isNew) {
+ if (PVE.UIOptions.shouldSortTags() && !isNew) {
index = view.items.findIndexBy(tagField => {
if (tagField.reference === 'noTagsField') {
return false;
@@ -255,7 +255,7 @@ Ext.define('PVE.panel.TagEditContainer', {
me.getViewModel().set('canEdit', view.canEdit);
me.mon(Ext.GlobalEvents, 'loadedUiOptions', () => {
- view.toggleCls('hide-handles', PVE.Utils.shouldSortTags());
+ view.toggleCls('hide-handles', PVE.UIOptions.shouldSortTags());
me.loadTags(me.oldTags, true); // refresh tag colors and order
});
},
diff --git a/www/manager6/tree/ResourceTree.js b/www/manager6/tree/ResourceTree.js
index 5c92d4128..7fcdfed5d 100644
--- a/www/manager6/tree/ResourceTree.js
+++ b/www/manager6/tree/ResourceTree.js
@@ -116,7 +116,7 @@ Ext.define('PVE.tree.ResourceTree', {
}
}
- info.text += PVE.Utils.renderTags(info.tags, PVE.Utils.tagOverrides);
+ info.text += PVE.Utils.renderTags(info.tags, PVE.UIOptions.tagOverrides);
info.text = status + info.text;
},
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] [PATCH manager v3 4/6] ui: refactor refreshing the the resource store/tree
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
` (2 preceding siblings ...)
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 3/6] ui: refactor ui option related methods into UIOptions Dominik Csapak
@ 2023-02-22 7:51 ` Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 5/6] ui: add window for changing tree related options Dominik Csapak
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
we'll need it elsewhere too, and it was rather hidden in the
updateTagSettings call.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/UIOptions.js | 13 ++++++++-----
www/manager6/dc/OptionView.js | 1 +
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/www/manager6/UIOptions.js b/www/manager6/UIOptions.js
index c80a7c859..dcdf01ee1 100644
--- a/www/manager6/UIOptions.js
+++ b/www/manager6/UIOptions.js
@@ -16,6 +16,7 @@ Ext.define('PVE.UIOptions', {
PVE.UIOptions.updateTagList(PVE.UIOptions.options['allowed-tags']);
PVE.UIOptions.updateTagSettings(PVE.UIOptions.options['tag-style']);
+ PVE.UIOptions.fireUIConfigChanged();
},
});
},
@@ -65,11 +66,6 @@ Ext.define('PVE.UIOptions', {
}
Ext.ComponentQuery.query('pveResourceTree')[0].setUserCls(`proxmox-tags-${shape}`);
-
- if (!PVE.data.ResourceStore.isLoading() && PVE.data.ResourceStore.isLoaded()) {
- PVE.data.ResourceStore.fireEvent('load');
- }
- Ext.GlobalEvents.fireEvent('loadedUiOptions');
},
tagTreeStyles: {
@@ -89,4 +85,11 @@ Ext.define('PVE.UIOptions', {
shouldSortTags: function() {
return !(PVE.UIOptions.options['tag-style']?.ordering === 'config');
},
+
+ fireUIConfigChanged: function() {
+ if (!PVE.data.ResourceStore.isLoading() && PVE.data.ResourceStore.isLoaded()) {
+ PVE.data.ResourceStore.fireEvent('load');
+ }
+ Ext.GlobalEvents.fireEvent('loadedUiOptions');
+ },
});
diff --git a/www/manager6/dc/OptionView.js b/www/manager6/dc/OptionView.js
index 4435876dd..f36a68560 100644
--- a/www/manager6/dc/OptionView.js
+++ b/www/manager6/dc/OptionView.js
@@ -566,6 +566,7 @@ Ext.define('PVE.dc.OptionView', {
PVE.UIOptions.options['tag-style'] = store.getById('tag-style')?.data?.value;
PVE.UIOptions.updateTagSettings(PVE.UIOptions.options['tag-style']);
+ PVE.UIOptions.fireUIConfigChanged();
});
me.on('activate', me.rstore.startUpdate);
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] [PATCH manager v3 5/6] ui: add window for changing tree related options
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
` (3 preceding siblings ...)
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 4/6] ui: refactor refreshing the the resource store/tree Dominik Csapak
@ 2023-02-22 7:51 ` Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 6/6] fix #1408: ui: ResourceTree: sort the tree according to tree-sorting options Dominik Csapak
2023-02-22 10:43 ` [pve-devel] applied-series: [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Thomas Lamprecht
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
such as the sorting/grouping of guests. saves them in the browser local
storage under 'pve-tree-sorting'
adds a button for it next to the the view selector
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/Makefile | 1 +
www/manager6/Workspace.js | 27 +++++++-
www/manager6/window/TreeSettingsEdit.js | 87 +++++++++++++++++++++++++
3 files changed, 113 insertions(+), 2 deletions(-)
create mode 100644 www/manager6/window/TreeSettingsEdit.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 2c487655f..b73b729ad 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -119,6 +119,7 @@ JSSRC= \
window/ScheduleSimulator.js \
window/Wizard.js \
window/GuestDiskReassign.js \
+ window/TreeSettingsEdit.js \
ha/Fencing.js \
ha/GroupEdit.js \
ha/GroupSelector.js \
diff --git a/www/manager6/Workspace.js b/www/manager6/Workspace.js
index a3872b560..a2fbc0be9 100644
--- a/www/manager6/Workspace.js
+++ b/www/manager6/Workspace.js
@@ -223,7 +223,10 @@ Ext.define('PVE.StdWorkspace', {
let appState = Ext.create('PVE.StateProvider');
Ext.state.Manager.setProvider(appState);
- let selview = Ext.create('PVE.form.ViewSelector');
+ let selview = Ext.create('PVE.form.ViewSelector', {
+ flex: 1,
+ padding: '0 5 0 0',
+ });
let rtree = Ext.createWidget('pveResourceTree', {
viewFilter: selview.getViewFilter(),
@@ -449,7 +452,27 @@ Ext.define('PVE.StdWorkspace', {
margin: '0 0 0 5',
split: true,
width: 300,
- items: [selview, rtree],
+ items: [
+ {
+ xtype: 'container',
+ layout: 'hbox',
+ padding: '0 0 5 0',
+ items: [
+ selview,
+ {
+ xtype: 'button',
+ iconCls: 'fa fa-fw fa-gear',
+ handler: () => {
+ Ext.create('PVE.window.TreeSettingsEdit', {
+ autoShow: true,
+ apiCallDone: () => PVE.UIOptions.fireUIConfigChanged(),
+ });
+ },
+ },
+ ],
+ },
+ rtree,
+ ],
listeners: {
resize: function(panel, width, height) {
var viewWidth = me.getSize().width;
diff --git a/www/manager6/window/TreeSettingsEdit.js b/www/manager6/window/TreeSettingsEdit.js
new file mode 100644
index 000000000..8f9b10b17
--- /dev/null
+++ b/www/manager6/window/TreeSettingsEdit.js
@@ -0,0 +1,87 @@
+Ext.define('PVE.window.TreeSettingsEdit', {
+ extend: 'Proxmox.window.Edit',
+ alias: 'widget.pveTreeSettingsEdit',
+
+ title: gettext('Tree Settings'),
+
+ isCreate: false,
+
+ // we don't want an url, we override submit(), but it is needed by the parent class
+ url: 'bogus',
+
+ fieldDefaults: {
+ labelWidth: 120,
+ },
+
+ items: [
+ {
+ xtype: 'inputpanel',
+ items: [
+ {
+ xtype: 'proxmoxKVComboBox',
+ name: 'sort-field',
+ fieldLabel: gettext('Sort Field'),
+ comboItems: [
+ ['__default__', `${Proxmox.Utils.defaultText} (VMID)`],
+ ['vmid', 'VMID'],
+ ['name', gettext('Name')],
+ ],
+ defaultValue: '__default__',
+ value: '__default__',
+ deleteEmpty: false,
+ },
+ {
+ xtype: 'proxmoxKVComboBox',
+ name: 'group-templates',
+ fieldLabel: gettext('Group Templates'),
+ comboItems: [
+ ['__default__', `${Proxmox.Utils.defaultText} (${gettext("Yes")})`],
+ [1, gettext('Yes')],
+ [0, gettext('No')],
+ ],
+ defaultValue: '__default__',
+ value: '__default__',
+ deleteEmpty: false,
+ },
+ {
+ xtype: 'proxmoxKVComboBox',
+ name: 'group-guest-types',
+ fieldLabel: gettext('Group Types'),
+ comboItems: [
+ ['__default__', `${Proxmox.Utils.defaultText} (${gettext("Yes")})`],
+ [1, gettext('Yes')],
+ [0, gettext('No')],
+ ],
+ defaultValue: '__default__',
+ value: '__default__',
+ deleteEmpty: false,
+ },
+ {
+ xtype: 'displayfield',
+ userCls: 'pmx-hint',
+ value: gettext('Settings are saved in the local storage of the browser'),
+ },
+ ],
+ },
+ ],
+
+ submit: function() {
+ let me = this;
+
+ let localStorage = Ext.state.Manager.getProvider();
+ localStorage.set('pve-tree-sorting', me.down('inputpanel').getValues() || null);
+
+ me.apiCallDone();
+ me.close();
+ },
+
+ initComponent: function() {
+ let me = this;
+
+ me.callParent();
+
+ let localStorage = Ext.state.Manager.getProvider();
+ me.down('inputpanel').setValues(localStorage.get('pve-tree-sorting'));
+ },
+
+});
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] [PATCH manager v3 6/6] fix #1408: ui: ResourceTree: sort the tree according to tree-sorting options
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
` (4 preceding siblings ...)
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 5/6] ui: add window for changing tree related options Dominik Csapak
@ 2023-02-22 7:51 ` Dominik Csapak
2023-02-22 10:43 ` [pve-devel] applied-series: [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Thomas Lamprecht
6 siblings, 0 replies; 8+ messages in thread
From: Dominik Csapak @ 2023-02-22 7:51 UTC (permalink / raw)
To: pve-devel
Considers the newly added options from browser local storage. We have to
save the last sorting mechanism there, so we can detect if it changes
and trigger the movement/text changes (otherwise the tree nodes won't
be updated/moved)
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
www/manager6/UIOptions.js | 12 +++++++
www/manager6/tree/ResourceTree.js | 54 ++++++++++++++++++++++++-------
2 files changed, 54 insertions(+), 12 deletions(-)
diff --git a/www/manager6/UIOptions.js b/www/manager6/UIOptions.js
index dcdf01ee1..cb5a17552 100644
--- a/www/manager6/UIOptions.js
+++ b/www/manager6/UIOptions.js
@@ -86,6 +86,18 @@ Ext.define('PVE.UIOptions', {
return !(PVE.UIOptions.options['tag-style']?.ordering === 'config');
},
+ getTreeSortingValue: function(key) {
+ let localStorage = Ext.state.Manager.getProvider();
+ let browserValues = localStorage.get('pve-tree-sorting');
+ let defaults = {
+ 'sort-field': 'vmid',
+ 'group-templates': true,
+ 'group-guest-types': true,
+ };
+
+ return browserValues?.[key] ?? defaults[key];
+ },
+
fireUIConfigChanged: function() {
if (!PVE.data.ResourceStore.isLoading() && PVE.data.ResourceStore.isLoaded()) {
PVE.data.ResourceStore.fireEvent('load');
diff --git a/www/manager6/tree/ResourceTree.js b/www/manager6/tree/ResourceTree.js
index 7fcdfed5d..7d7900b59 100644
--- a/www/manager6/tree/ResourceTree.js
+++ b/www/manager6/tree/ResourceTree.js
@@ -44,24 +44,34 @@ Ext.define('PVE.tree.ResourceTree', {
// private
nodeSortFn: function(node1, node2) {
+ let me = this;
let n1 = node1.data, n2 = node2.data;
if (!n1.groupbyid === !n2.groupbyid) {
- // first sort (group) by type
- if (n1.type > n2.type) {
- return 1;
- } else if (n1.type < n2.type) {
- return -1;
+ let n1IsGuest = n1.type === 'qemu' || n1.type === 'lxc';
+ let n2IsGuest = n2.type === 'qemu' || n2.type === 'lxc';
+ if (me['group-guest-types'] || !n1IsGuest || !n2IsGuest) {
+ // first sort (group) by type
+ if (n1.type > n2.type) {
+ return 1;
+ } else if (n1.type < n2.type) {
+ return -1;
+ }
}
+
// then sort (group) by ID
- if (n1.type === 'qemu' || n2.type === 'lxc') {
- if (!n1.template !== !n2.template) {
+ if (n1IsGuest) {
+ if (me['group-templates'] && (!n1.template !== !n2.template)) {
return n1.template ? 1 : -1; // sort templates after regular VMs
}
- if (n1.vmid > n2.vmid) { // prefer VMID as metric for guests
- return 1;
- } else if (n1.vmid < n2.vmid) {
- return -1;
+ if (me['sort-field'] === 'vmid') {
+ if (n1.vmid > n2.vmid) { // prefer VMID as metric for guests
+ return 1;
+ } else if (n1.vmid < n2.vmid) {
+ return -1;
+ }
+ } else {
+ return n1.name.localeCompare(n2.name);
}
}
// same types but not a guest
@@ -115,6 +125,11 @@ Ext.define('PVE.tree.ResourceTree', {
status += '</div> ';
}
}
+ if (Ext.isNumeric(info.vmid) && info.vmid > 0) {
+ if (PVE.UIOptions.getTreeSortingValue('sort-field') !== 'vmid') {
+ info.text = `${info.name} (${String(info.vmid)})`;
+ }
+ }
info.text += PVE.Utils.renderTags(info.tags, PVE.UIOptions.tagOverrides);
@@ -203,8 +218,22 @@ Ext.define('PVE.tree.ResourceTree', {
return me.addChildSorted(node, info);
},
+ saveSortingOptions: function() {
+ let me = this;
+ let changed = false;
+ for (const key of ['sort-field', 'group-templates', 'group-guest-types']) {
+ let newValue = PVE.UIOptions.getTreeSortingValue(key);
+ if (me[key] !== newValue) {
+ me[key] = newValue;
+ changed = true;
+ }
+ }
+ return changed;
+ },
+
initComponent: function() {
let me = this;
+ me.saveSortingOptions();
let rstore = PVE.data.ResourceStore;
let sp = Ext.state.Manager.getProvider();
@@ -242,6 +271,7 @@ Ext.define('PVE.tree.ResourceTree', {
let sm = me.getSelectionModel();
let lastsel = sm.getSelection()[0];
let parents = [];
+ let sorting_changed = me.saveSortingOptions();
for (let node = lastsel; node; node = node.parentNode) {
parents.push(node);
}
@@ -258,7 +288,7 @@ Ext.define('PVE.tree.ResourceTree', {
// getById() use find(), which is slow (ExtJS4 DP5)
let item = rstore.data.get(olditem.data.id);
- let changed = false, moved = false;
+ let changed = sorting_changed, moved = sorting_changed;
if (item) {
// test if any grouping attributes changed, catches migrated tree-nodes in server view too
for (const attr of moveCheckAttrs) {
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [pve-devel] applied-series: [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
` (5 preceding siblings ...)
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 6/6] fix #1408: ui: ResourceTree: sort the tree according to tree-sorting options Dominik Csapak
@ 2023-02-22 10:43 ` Thomas Lamprecht
6 siblings, 0 replies; 8+ messages in thread
From: Thomas Lamprecht @ 2023-02-22 10:43 UTC (permalink / raw)
To: Proxmox VE development discussion, Dominik Csapak
Am 22/02/2023 um 08:51 schrieb Dominik Csapak:
> this series allows configuring the sorting of the resource tree
>
> options are the sort-field, if guest types are grouped and if templates
> are grouped seperately. it's configurable via browser local storage
>
> the first 2 patches are not really related but popped up during
> development
>
> changes from v2:
> * improved browser local storage notice
> * added padding between the view selector and the button
>
> changes from v1:
> * drop the datacenter config options for now
> * rename TreeSortingEdit into TreeSortingEdit
> * since we don't have a fallback besides the default, display the
> defauls in the dropdowns
> * don't use booleanfield anymore (because of above change)
> * rename sp into localStorage
> * use fieldDefaults
> * refactor stuff into PVE.UIOptions (a new singleton)
> * remove storage view
> * remove booleanfield()
>
> Dominik Csapak (6):
> ui: remove 'Storage View'
> ui: remove unused booleanfield
> ui: refactor ui option related methods into UIOptions
> ui: refactor refreshing the the resource store/tree
> ui: add window for changing tree related options
> fix #1408: ui: ResourceTree: sort the tree according to tree-sorting
> options
>
applied, thanks!
As talked off-list, I made three small followups
1) make settings button stand less out
2) making window a bit wider and claryfing the field labels (mostly that the
type grouping only affects guests)
3) change the bogus url to '#'
for the record only, as we also talked off list: it might be nice to apply
changes live, so that one can see the effect in the background already.
But the current settings are relatively straight forward and after initial
setup its unlikely to change, so there's not _that_ much friction as is.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-02-22 10:44 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-22 7:51 [pve-devel] [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 1/6] ui: remove 'Storage View' Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 2/6] ui: remove unused booleanfield Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 3/6] ui: refactor ui option related methods into UIOptions Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 4/6] ui: refactor refreshing the the resource store/tree Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 5/6] ui: add window for changing tree related options Dominik Csapak
2023-02-22 7:51 ` [pve-devel] [PATCH manager v3 6/6] fix #1408: ui: ResourceTree: sort the tree according to tree-sorting options Dominik Csapak
2023-02-22 10:43 ` [pve-devel] applied-series: [PATCH manager v3 0/6] fix #1408: ui: make tree sorting configurable Thomas Lamprecht
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox