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