]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - src/grid/ObjectGrid.js
tree-wide typo fixes
[proxmox-widget-toolkit.git] / src / grid / ObjectGrid.js
1 /** Renders a list of key values objects
2
3 Mandatory Config Parameters:
4
5 rows: an object container where each property is a key-value object we want to render
6
7 rows: {
8 keyboard: {
9 header: gettext('Keyboard Layout'),
10 editor: 'Your.KeyboardEdit',
11 required: true
12 },
13 // ...
14 },
15
16 Convenience Helper:
17
18 As alternative you can use the common add-row helper like `add_text_row`, but you need to
19 call it in an overridden initComponent before `me.callParent(arguments)` gets executed.
20
21 For a declarative approach you can use the `gridRows` configuration to pass an array of
22 objects with each having at least a `xtype` to match `add_XTYPE_row` and a field-name
23 property, for example:
24
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
36 Optional Configs:
37
38 disabled:: 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 */
43 Ext.define('Proxmox.grid.ObjectGrid', {
44 extend: 'Ext.grid.GridPanel',
45 alias: ['widget.proxmoxObjectGrid'],
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
51 disabled: false,
52 hideHeaders: true,
53
54 monStoreErrors: false,
55
56 add_combobox_row: function(name, text, opts) {
57 let me = this;
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,
70 onlineHelp: opts.onlineHelp,
71 fieldDefaults: {
72 labelWidth: opts.labelWidth || 100,
73 },
74 items: {
75 xtype: 'proxmoxKVComboBox',
76 name: name,
77 comboItems: opts.comboItems,
78 value: opts.defaultValue,
79 deleteEmpty: !!opts.deleteEmpty,
80 emptyText: opts.defaultValue,
81 labelWidth: Proxmox.Utils.compute_min_label_width(
82 text, opts.labelWidth),
83 fieldLabel: text,
84 },
85 },
86 };
87 },
88
89 add_text_row: function(name, text, opts) {
90 let me = this;
91
92 opts = opts || {};
93 me.rows = me.rows || {};
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,
103 onlineHelp: opts.onlineHelp,
104 fieldDefaults: {
105 labelWidth: opts.labelWidth || 100,
106 },
107 items: {
108 xtype: 'proxmoxtextfield',
109 name: name,
110 deleteEmpty: !!opts.deleteEmpty,
111 emptyText: opts.defaultValue,
112 labelWidth: Proxmox.Utils.compute_min_label_width(text, opts.labelWidth),
113 vtype: opts.vtype,
114 fieldLabel: text,
115 },
116 },
117 };
118 },
119
120 add_boolean_row: function(name, text, opts) {
121 let me = this;
122
123 opts = opts || {};
124 me.rows = me.rows || {};
125
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,
134 onlineHelp: opts.onlineHelp,
135 fieldDefaults: {
136 labelWidth: opts.labelWidth || 100,
137 },
138 items: {
139 xtype: 'proxmoxcheckbox',
140 name: name,
141 uncheckedValue: 0,
142 defaultValue: opts.defaultValue || 0,
143 checked: !!opts.defaultValue,
144 deleteDefaultValue: !!opts.deleteDefaultValue,
145 labelWidth: Proxmox.Utils.compute_min_label_width(text, opts.labelWidth),
146 fieldLabel: text,
147 },
148 },
149 };
150 },
151
152 add_integer_row: function(name, text, opts) {
153 let me = this;
154
155 opts = opts || {};
156 me.rows = me.rows || {};
157
158 me.rows[name] = {
159 required: true,
160 defaultValue: opts.defaultValue,
161 header: text,
162 renderer: opts.renderer,
163 editor: {
164 xtype: 'proxmoxWindowEdit',
165 subject: text,
166 onlineHelp: opts.onlineHelp,
167 fieldDefaults: {
168 labelWidth: opts.labelWidth || 100,
169 },
170 items: {
171 xtype: 'proxmoxintegerfield',
172 name: name,
173 minValue: opts.minValue,
174 maxValue: opts.maxValue,
175 emptyText: gettext('Default'),
176 deleteEmpty: !!opts.deleteEmpty,
177 value: opts.defaultValue,
178 labelWidth: Proxmox.Utils.compute_min_label_width(text, opts.labelWidth),
179 fieldLabel: text,
180 },
181 },
182 };
183 },
184
185 editorConfig: {}, // default config passed to editor
186
187 run_editor: function() {
188 let me = this;
189
190 let sm = me.getSelectionModel();
191 let rec = sm.getSelection()[0];
192 if (!rec) {
193 return;
194 }
195
196 let rows = me.rows;
197 let rowdef = rows[rec.data.key];
198 if (!rowdef.editor) {
199 return;
200 }
201
202 let win;
203 let config;
204 if (Ext.isString(rowdef.editor)) {
205 config = Ext.apply({
206 confid: rec.data.key,
207 }, me.editorConfig);
208 win = Ext.create(rowdef.editor, config);
209 } else {
210 config = Ext.apply({
211 confid: rec.data.key,
212 }, me.editorConfig);
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() {
223 let me = this;
224 me.rstore.load();
225 },
226
227 getObjectValue: function(key, defaultValue) {
228 let me = this;
229 let rec = me.store.getById(key);
230 if (rec) {
231 return rec.data.value;
232 }
233 return defaultValue;
234 },
235
236 renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
237 let me = this;
238 let rows = me.rows;
239 let rowdef = rows && rows[key] ? rows[key] : {};
240 return rowdef.header || key;
241 },
242
243 renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
244 let me = this;
245 let rows = me.rows;
246 let key = record.data.key;
247 let rowdef = rows && rows[key] ? rows[key] : {};
248
249 let renderer = rowdef.renderer;
250 if (renderer) {
251 return renderer(value, metaData, record, rowIndex, colIndex, store);
252 }
253
254 return value;
255 },
256
257 listeners: {
258 itemkeydown: function(view, record, item, index, e) {
259 if (e.getKey() === e.ENTER) {
260 this.pressedIndex = index;
261 }
262 },
263 itemkeyup: function(view, record, item, index, e) {
264 if (e.getKey() === e.ENTER && index === this.pressedIndex) {
265 this.run_editor();
266 }
267
268 this.pressedIndex = undefined;
269 },
270 },
271
272 initComponent: function() {
273 let me = this;
274
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
286 let rows = me.rows;
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,
297 rows: me.rows,
298 });
299 }
300
301 let rstore = me.rstore;
302 let store = Ext.create('Proxmox.data.DiffStore', {
303 rstore: rstore,
304 sorters: [],
305 filters: [],
306 });
307
308 if (rows) {
309 for (const [key, rowdef] of Object.entries(rows)) {
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 }
315 }
316 }
317
318 if (me.sorterFn) {
319 store.sorters.add(Ext.create('Ext.util.Sorter', {
320 sorterFn: me.sorterFn,
321 }));
322 }
323
324 store.filters.add(Ext.create('Ext.util.Filter', {
325 filterFn: function(item) {
326 if (rows) {
327 let rowdef = rows[item.data.key];
328 if (!rowdef || rowdef.visible === false) {
329 return false;
330 }
331 }
332 return true;
333 },
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',
346 renderer: me.renderKey,
347 },
348 {
349 flex: 1,
350 header: gettext('Value'),
351 dataIndex: 'value',
352 renderer: me.renderValue,
353 },
354 ],
355 });
356
357 me.callParent();
358
359 if (me.monStoreErrors) {
360 Proxmox.Utils.monStoreErrors(me, me.store);
361 }
362 },
363 });