]> git.proxmox.com Git - proxmox-widget-toolkit.git/blame - src/grid/ObjectGrid.js
tree-wide typo fixes
[proxmox-widget-toolkit.git] / src / grid / ObjectGrid.js
CommitLineData
017a6376 1/** Renders a list of key values objects
52d3f3b0
TL
2
3Mandatory Config Parameters:
06694509 4
017a6376 5rows: an object container where each property is a key-value object we want to render
06694509 6
52d3f3b0
TL
7 rows: {
8 keyboard: {
9 header: gettext('Keyboard Layout'),
10 editor: 'Your.KeyboardEdit',
11 required: true
12 },
13 // ...
14 },
15
16Convenience Helper:
17
18As alternative you can use the common add-row helper like `add_text_row`, but you need to
19call it in an overridden initComponent before `me.callParent(arguments)` gets executed.
20
21For a declarative approach you can use the `gridRows` configuration to pass an array of
22objects with each having at least a `xtype` to match `add_XTYPE_row` and a field-name
23property, for example:
06694509 24
52d3f3b0
TL
25 gridRows: [
26 {
27 xtype: 'text',
28 name: 'http-proxy',
29 text: gettext('HTTP proxy'),
30 defaultValue: Proxmox.Utils.noneText,
31 vtype: 'HttpProxy',
32 deleteEmpty: true,
33 },
34 ],
35
36Optional Configs:
37
38disabled:: setting this parameter to true will disable selection and focus on
39 the proxmoxObjectGrid as well as greying out input elements. Useful for a
40 readonly tabular display
41
42*/
06694509
DM
43Ext.define('Proxmox.grid.ObjectGrid', {
44 extend: 'Ext.grid.GridPanel',
45 alias: ['widget.proxmoxObjectGrid'],
bc9ae602
TL
46
47 // can be used as declarative replacement over manually calling the add_XYZ_row helpers,
48 // see top-level doc-comment above for details/example
49 gridRows: [],
50
06694509
DM
51 disabled: false,
52 hideHeaders: true,
53
4297e795
DM
54 monStoreErrors: false,
55
8f7370ee 56 add_combobox_row: function(name, text, opts) {
05a977a2 57 let me = this;
8f7370ee
DM
58
59 opts = opts || {};
60 me.rows = me.rows || {};
61
62 me.rows[name] = {
63 required: true,
64 defaultValue: opts.defaultValue,
65 header: text,
66 renderer: opts.renderer,
67 editor: {
68 xtype: 'proxmoxWindowEdit',
69 subject: text,
7d16f8b3 70 onlineHelp: opts.onlineHelp,
37d8d602 71 fieldDefaults: {
01031528 72 labelWidth: opts.labelWidth || 100,
37d8d602 73 },
8f7370ee
DM
74 items: {
75 xtype: 'proxmoxKVComboBox',
76 name: name,
77 comboItems: opts.comboItems,
78 value: opts.defaultValue,
01031528 79 deleteEmpty: !!opts.deleteEmpty,
8f7370ee
DM
80 emptyText: opts.defaultValue,
81 labelWidth: Proxmox.Utils.compute_min_label_width(
82 text, opts.labelWidth),
01031528
TL
83 fieldLabel: text,
84 },
85 },
8f7370ee
DM
86 };
87 },
88
5dea30d0 89 add_text_row: function(name, text, opts) {
05a977a2 90 let me = this;
5dea30d0
DM
91
92 opts = opts || {};
c2ea0137 93 me.rows = me.rows || {};
5dea30d0
DM
94
95 me.rows[name] = {
96 required: true,
97 defaultValue: opts.defaultValue,
98 header: text,
99 renderer: opts.renderer,
100 editor: {
101 xtype: 'proxmoxWindowEdit',
102 subject: text,
7d16f8b3 103 onlineHelp: opts.onlineHelp,
37d8d602 104 fieldDefaults: {
01031528 105 labelWidth: opts.labelWidth || 100,
37d8d602 106 },
5dea30d0
DM
107 items: {
108 xtype: 'proxmoxtextfield',
109 name: name,
01031528 110 deleteEmpty: !!opts.deleteEmpty,
5dea30d0 111 emptyText: opts.defaultValue,
d00e8b94 112 labelWidth: Proxmox.Utils.compute_min_label_width(text, opts.labelWidth),
85d85d15 113 vtype: opts.vtype,
01031528
TL
114 fieldLabel: text,
115 },
116 },
5dea30d0
DM
117 };
118 },
119
0e49da6d 120 add_boolean_row: function(name, text, opts) {
05a977a2 121 let me = this;
0e49da6d
DM
122
123 opts = opts || {};
c2ea0137 124 me.rows = me.rows || {};
0e49da6d 125
0e49da6d
DM
126 me.rows[name] = {
127 required: true,
128 defaultValue: opts.defaultValue || 0,
129 header: text,
130 renderer: opts.renderer || Proxmox.Utils.format_boolean,
131 editor: {
132 xtype: 'proxmoxWindowEdit',
133 subject: text,
7d16f8b3 134 onlineHelp: opts.onlineHelp,
37d8d602 135 fieldDefaults: {
01031528 136 labelWidth: opts.labelWidth || 100,
37d8d602 137 },
0e49da6d
DM
138 items: {
139 xtype: 'proxmoxcheckbox',
140 name: name,
141 uncheckedValue: 0,
01031528
TL
142 defaultValue: opts.defaultValue || 0,
143 checked: !!opts.defaultValue,
144 deleteDefaultValue: !!opts.deleteDefaultValue,
d00e8b94 145 labelWidth: Proxmox.Utils.compute_min_label_width(text, opts.labelWidth),
01031528
TL
146 fieldLabel: text,
147 },
148 },
0e49da6d
DM
149 };
150 },
151
152 add_integer_row: function(name, text, opts) {
05a977a2 153 let me = this;
0e49da6d 154
01031528 155 opts = opts || {};
c2ea0137 156 me.rows = me.rows || {};
0e49da6d 157
0e49da6d
DM
158 me.rows[name] = {
159 required: true,
160 defaultValue: opts.defaultValue,
161 header: text,
0d5c5e14 162 renderer: opts.renderer,
0e49da6d
DM
163 editor: {
164 xtype: 'proxmoxWindowEdit',
165 subject: text,
7d16f8b3 166 onlineHelp: opts.onlineHelp,
37d8d602 167 fieldDefaults: {
01031528 168 labelWidth: opts.labelWidth || 100,
37d8d602 169 },
0e49da6d
DM
170 items: {
171 xtype: 'proxmoxintegerfield',
172 name: name,
173 minValue: opts.minValue,
174 maxValue: opts.maxValue,
175 emptyText: gettext('Default'),
01031528 176 deleteEmpty: !!opts.deleteEmpty,
0e49da6d 177 value: opts.defaultValue,
d00e8b94 178 labelWidth: Proxmox.Utils.compute_min_label_width(text, opts.labelWidth),
01031528
TL
179 fieldLabel: text,
180 },
181 },
0e49da6d
DM
182 };
183 },
184
7ec6cd9e
DM
185 editorConfig: {}, // default config passed to editor
186
187 run_editor: function() {
05a977a2 188 let me = this;
7ec6cd9e 189
05a977a2
TL
190 let sm = me.getSelectionModel();
191 let rec = sm.getSelection()[0];
7ec6cd9e
DM
192 if (!rec) {
193 return;
194 }
195
05a977a2
TL
196 let rows = me.rows;
197 let rowdef = rows[rec.data.key];
7ec6cd9e
DM
198 if (!rowdef.editor) {
199 return;
200 }
201
05a977a2
TL
202 let win;
203 let config;
7ec6cd9e
DM
204 if (Ext.isString(rowdef.editor)) {
205 config = Ext.apply({
206 confid: rec.data.key,
01031528 207 }, me.editorConfig);
7ec6cd9e
DM
208 win = Ext.create(rowdef.editor, config);
209 } else {
210 config = Ext.apply({
211 confid: rec.data.key,
01031528 212 }, me.editorConfig);
7ec6cd9e
DM
213 Ext.apply(config, rowdef.editor);
214 win = Ext.createWidget(rowdef.editor.xtype, config);
215 win.load();
216 }
217
218 win.show();
219 win.on('destroy', me.reload, me);
220 },
221
222 reload: function() {
05a977a2 223 let me = this;
7ec6cd9e
DM
224 me.rstore.load();
225 },
226
06694509 227 getObjectValue: function(key, defaultValue) {
05a977a2
TL
228 let me = this;
229 let rec = me.store.getById(key);
06694509
DM
230 if (rec) {
231 return rec.data.value;
232 }
233 return defaultValue;
234 },
235
236 renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
05a977a2
TL
237 let me = this;
238 let rows = me.rows;
239 let rowdef = rows && rows[key] ? rows[key] : {};
06694509
DM
240 return rowdef.header || key;
241 },
242
243 renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
05a977a2
TL
244 let me = this;
245 let rows = me.rows;
246 let key = record.data.key;
247 let rowdef = rows && rows[key] ? rows[key] : {};
06694509 248
05a977a2 249 let renderer = rowdef.renderer;
06694509
DM
250 if (renderer) {
251 return renderer(value, metaData, record, rowIndex, colIndex, store);
252 }
253
254 return value;
255 },
256
9307eda4 257 listeners: {
ce9a0f27 258 itemkeydown: function(view, record, item, index, e) {
9307eda4 259 if (e.getKey() === e.ENTER) {
ce9a0f27
DC
260 this.pressedIndex = index;
261 }
262 },
263 itemkeyup: function(view, record, item, index, e) {
05a977a2 264 if (e.getKey() === e.ENTER && index === this.pressedIndex) {
9307eda4
DC
265 this.run_editor();
266 }
ce9a0f27
DC
267
268 this.pressedIndex = undefined;
01031528 269 },
9307eda4
DC
270 },
271
01031528 272 initComponent: function() {
05a977a2 273 let me = this;
06694509 274
bc9ae602
TL
275 for (const rowdef of me.gridRows || []) {
276 let addFn = me[`add_${rowdef.xtype}_row`];
277 if (typeof addFn !== 'function') {
278 throw `unknown object-grid row xtype '${rowdef.xtype}'`;
279 } else if (typeof rowdef.name !== 'string') {
280 throw `object-grid row need a valid name string-property!`;
281 } else {
282 addFn.call(me, rowdef.name, rowdef.text || rowdef.name, rowdef);
283 }
284 }
285
05a977a2 286 let rows = me.rows;
06694509
DM
287
288 if (!me.rstore) {
289 if (!me.url) {
290 throw "no url specified";
291 }
292
293 me.rstore = Ext.create('Proxmox.data.ObjectStore', {
294 url: me.url,
295 interval: me.interval,
296 extraParams: me.extraParams,
01031528 297 rows: me.rows,
06694509
DM
298 });
299 }
300
4f1b9b8c
TL
301 let rstore = me.rstore;
302 let store = Ext.create('Proxmox.data.DiffStore', {
303 rstore: rstore,
06694509 304 sorters: [],
01031528 305 filters: [],
06694509
DM
306 });
307
308 if (rows) {
f0f898d2 309 for (const [key, rowdef] of Object.entries(rows)) {
06694509
DM
310 if (Ext.isDefined(rowdef.defaultValue)) {
311 store.add({ key: key, value: rowdef.defaultValue });
312 } else if (rowdef.required) {
313 store.add({ key: key, value: undefined });
314 }
f0f898d2 315 }
06694509
DM
316 }
317
318 if (me.sorterFn) {
319 store.sorters.add(Ext.create('Ext.util.Sorter', {
01031528 320 sorterFn: me.sorterFn,
06694509
DM
321 }));
322 }
323
324 store.filters.add(Ext.create('Ext.util.Filter', {
325 filterFn: function(item) {
326 if (rows) {
05a977a2 327 let rowdef = rows[item.data.key];
01031528 328 if (!rowdef || rowdef.visible === false) {
06694509
DM
329 return false;
330 }
331 }
332 return true;
01031528 333 },
06694509
DM
334 }));
335
336 Proxmox.Utils.monStoreErrors(me, rstore);
337
338 Ext.applyIf(me, {
339 store: store,
340 stateful: false,
341 columns: [
342 {
343 header: gettext('Name'),
344 width: me.cwidth1 || 200,
345 dataIndex: 'key',
01031528 346 renderer: me.renderKey,
06694509
DM
347 },
348 {
349 flex: 1,
350 header: gettext('Value'),
351 dataIndex: 'value',
01031528
TL
352 renderer: me.renderValue,
353 },
354 ],
06694509
DM
355 });
356
357 me.callParent();
4297e795
DM
358
359 if (me.monStoreErrors) {
360 Proxmox.Utils.monStoreErrors(me, me.store);
361 }
01031528 362 },
06694509 363});