]>
Commit | Line | Data |
---|---|---|
458e534c EK |
1 | /* |
2 | * Base class for all the multitab config panels | |
9a4c279d DC |
3 | * |
4 | * How to use this: | |
5 | * | |
6 | * You create a subclass of this, and then define your wanted tabs | |
7 | * as items like this: | |
8 | * | |
9 | * items: [{ | |
10 | * title: "myTitle", | |
11 | * xytpe: "somextype", | |
12 | * iconCls: 'fa fa-icon', | |
13 | * groups: ['somegroup'], | |
14 | * expandedOnInit: true, | |
15 | * itemId: 'someId' | |
16 | * }] | |
17 | * | |
18 | * this has to be in the declarative syntax, else we | |
19 | * cannot save them for later | |
20 | * (so no Ext.create or Ext.apply of an item in the subclass) | |
21 | * | |
22 | * the groups array expects the itemids of the items | |
23 | * which are the parents, which have to come before they | |
24 | * are used | |
25 | * | |
26 | * if you want following the tree: | |
27 | * | |
28 | * Option1 | |
29 | * Option2 | |
30 | * -> SubOption1 | |
31 | * -> SubSubOption1 | |
32 | * | |
33 | * the suboption1 group array has to look like this: | |
34 | * groups: ['itemid-of-option2'] | |
35 | * | |
36 | * and of subsuboption1: | |
37 | * groups: ['itemid-of-option2', 'itemid-of-suboption1'] | |
38 | * | |
39 | * setting the expandedOnInit determines if the item/group is expanded | |
40 | * initially (false by default) | |
458e534c | 41 | */ |
55ed1090 DM |
42 | Ext.define('PVE.panel.Config', { |
43 | extend: 'Ext.panel.Panel', | |
44 | alias: 'widget.pvePanelConfig', | |
45 | ||
ec505260 TL |
46 | showSearch: true, // add a resource grid with a search button as first tab |
47 | viewFilter: undefined, // a filter to pass to that resource grid | |
458e534c | 48 | |
375d2918 DC |
49 | tbarSpacing: true, // if true, adds a spacer after the title in tbar |
50 | ||
9a4c279d DC |
51 | dockedItems: [{ |
52 | // this is needed for the overflow handler | |
53 | xtype: 'toolbar', | |
54 | overflowHandler: 'scroller', | |
55 | dock: 'left', | |
56 | style: { | |
9a4c279d | 57 | padding: 0, |
f6710aac | 58 | margin: 0, |
9a4c279d | 59 | }, |
df22311b | 60 | cls: 'pve-toolbar-bg', |
9a4c279d DC |
61 | items: { |
62 | xtype: 'treelist', | |
63 | itemId: 'menu', | |
c8d72c05 | 64 | ui: 'pve-nav', |
9a4c279d DC |
65 | expanderOnly: true, |
66 | expanderFirst: false, | |
67 | animation: false, | |
68 | singleExpand: false, | |
69 | listeners: { | |
70 | selectionchange: function(treeList, selection) { | |
928028c1 DC |
71 | if (!selection) { |
72 | return; | |
73 | } | |
ee390345 DJ |
74 | let view = this.up('panel'); |
75 | view.suspendLayout = true; | |
76 | view.activateCard(selection.data.id); | |
77 | view.suspendLayout = false; | |
78 | view.updateLayout(); | |
9a4c279d DC |
79 | }, |
80 | itemclick: function(treelist, info) { | |
81 | var olditem = treelist.getSelection(); | |
82 | var newitem = info.node; | |
83 | ||
df22311b | 84 | // when clicking on the expand arrow, we don't select items, but still want the original behaviour |
9a4c279d DC |
85 | if (info.select === false) { |
86 | return; | |
87 | } | |
88 | ||
df22311b | 89 | // click on a different, open item then leave it open, else toggle the clicked item |
9a4c279d DC |
90 | if (olditem.data.id !== newitem.data.id && |
91 | newitem.data.expanded === true) { | |
92 | info.toggle = false; | |
93 | } else { | |
94 | info.toggle = true; | |
95 | } | |
f6710aac TL |
96 | }, |
97 | }, | |
98 | }, | |
9a4c279d DC |
99 | }, |
100 | { | |
101 | xtype: 'toolbar', | |
102 | itemId: 'toolbar', | |
103 | dock: 'top', | |
104 | height: 36, | |
f6710aac | 105 | overflowHandler: 'scroller', |
9a4c279d DC |
106 | }], |
107 | ||
108 | firstItem: '', | |
109 | layout: 'card', | |
110 | border: 0, | |
111 | ||
86ca2794 DM |
112 | // used for automated test |
113 | selectById: function(cardid) { | |
114 | var me = this; | |
115 | ||
116 | var root = me.store.getRoot(); | |
117 | var selection = root.findChild('id', cardid, true); | |
118 | ||
119 | if (selection) { | |
63b6b7ce | 120 | selection.expand(); |
86ca2794 DM |
121 | var menu = me.down('#menu'); |
122 | menu.setSelection(selection); | |
123 | return cardid; | |
124 | } | |
ee390345 | 125 | return ''; |
86ca2794 DM |
126 | }, |
127 | ||
9a4c279d DC |
128 | activateCard: function(cardid) { |
129 | var me = this; | |
130 | if (me.savedItems[cardid]) { | |
131 | var curcard = me.getLayout().getActiveItem(); | |
132 | var newcard = me.add(me.savedItems[cardid]); | |
a50de124 | 133 | me.helpButton.setOnlineHelp(newcard.onlineHelp || me.onlineHelp); |
9a4c279d DC |
134 | if (curcard) { |
135 | me.setActiveItem(cardid); | |
136 | me.remove(curcard, true); | |
137 | ||
138 | // trigger state change | |
139 | ||
140 | var ncard = cardid; | |
141 | // Note: '' is alias for first tab. | |
142 | // First tab can be 'search' or something else | |
143 | if (cardid === me.firstItem) { | |
144 | ncard = ''; | |
145 | } | |
146 | if (me.hstateid) { | |
147 | me.sp.set(me.hstateid, { value: ncard }); | |
148 | } | |
149 | } | |
150 | } | |
151 | }, | |
152 | ||
55ed1090 DM |
153 | initComponent: function() { |
154 | var me = this; | |
155 | ||
156 | var stateid = me.hstateid; | |
157 | ||
9a4c279d | 158 | me.sp = Ext.state.Manager.getProvider(); |
55ed1090 | 159 | |
cececa1d | 160 | var activeTab; // leaving this undefined means items[0] will be the default tab |
55ed1090 | 161 | |
55ed1090 | 162 | if (stateid) { |
ee390345 | 163 | let state = me.sp.get(stateid); |
55ed1090 | 164 | if (state && state.value) { |
8dc7c7af | 165 | // if this tab does not exist, it chooses the first |
9a4c279d | 166 | activeTab = state.value; |
55ed1090 DM |
167 | } |
168 | } | |
169 | ||
9a4c279d DC |
170 | // get title |
171 | var title = me.title || me.pveSelNode.data.text; | |
172 | me.title = undefined; | |
55ed1090 | 173 | |
9a4c279d | 174 | // create toolbar |
55ed1090 DM |
175 | var tbar = me.tbar || []; |
176 | me.tbar = undefined; | |
177 | ||
9cc74dfe | 178 | if (!me.onlineHelp) { |
ea5d9c35 TL |
179 | let typeToOnlineHelp = { |
180 | 'type/lxc': 'chapter-pct.html', | |
181 | 'type/node': 'chapter-sysadmin.html', | |
182 | 'type/pool': 'chapter-pveum.html#_pools', | |
183 | 'type/qemu': 'chapter-qm.html', | |
184 | 'type/storage': 'chapter-pvesm.html', | |
185 | }; | |
186 | me.onlineHelp = typeToOnlineHelp[me.pveSelNode.data.id]; | |
9cc74dfe DC |
187 | } |
188 | ||
375d2918 DC |
189 | if (me.tbarSpacing) { |
190 | tbar.unshift('->'); | |
191 | } | |
55ed1090 DM |
192 | tbar.unshift({ |
193 | xtype: 'tbtext', | |
194 | text: title, | |
f6710aac | 195 | baseCls: 'x-panel-header-text', |
55ed1090 DM |
196 | }); |
197 | ||
672a6270 | 198 | me.helpButton = Ext.create('Proxmox.button.Help', { |
9cc74dfe DC |
199 | hidden: false, |
200 | listenToGlobalEvent: false, | |
f6710aac | 201 | onlineHelp: me.onlineHelp || undefined, |
9cc74dfe DC |
202 | }); |
203 | ||
204 | tbar.push(me.helpButton); | |
205 | ||
9a4c279d | 206 | me.dockedItems[1].items = tbar; |
55ed1090 | 207 | |
9a4c279d DC |
208 | // include search tab |
209 | me.items = me.items || []; | |
55ed1090 | 210 | if (me.showSearch) { |
9a4c279d | 211 | me.items.unshift({ |
7e27f5d1 DC |
212 | itemId: 'search', |
213 | title: gettext('Search'), | |
9a4c279d DC |
214 | iconCls: 'fa fa-search', |
215 | xtype: 'pveResourceGrid', | |
f6710aac | 216 | pveSelNode: me.pveSelNode, |
55ed1090 DM |
217 | }); |
218 | } | |
219 | ||
9a4c279d | 220 | me.savedItems = {}; |
9a4c279d DC |
221 | if (me.items[0]) { |
222 | me.firstItem = me.items[0].itemId; | |
223 | } | |
55ed1090 | 224 | |
9a4c279d DC |
225 | me.store = Ext.create('Ext.data.TreeStore', { |
226 | root: { | |
f6710aac TL |
227 | expanded: true, |
228 | }, | |
9a4c279d DC |
229 | }); |
230 | var root = me.store.getRoot(); | |
a83c659a | 231 | me.insertNodes(me.items); |
55ed1090 | 232 | |
9a4c279d DC |
233 | delete me.items; |
234 | me.defaults = me.defaults || {}; | |
235 | Ext.apply(me.defaults, { | |
236 | pveSelNode: me.pveSelNode, | |
237 | viewFilter: me.viewFilter, | |
238 | workspace: me.workspace, | |
f6710aac | 239 | border: 0, |
55ed1090 DM |
240 | }); |
241 | ||
242 | me.callParent(); | |
243 | ||
9a4c279d DC |
244 | var menu = me.down('#menu'); |
245 | var selection = root.findChild('id', activeTab, true) || root.firstChild; | |
246 | var node = selection; | |
247 | while (node !== root) { | |
248 | node.expand(); | |
249 | node = node.parentNode; | |
250 | } | |
251 | menu.setStore(me.store); | |
252 | menu.setSelection(selection); | |
253 | ||
254 | // on a state change, | |
255 | // select the new item | |
55ed1090 | 256 | var statechange = function(sp, key, state) { |
9a4c279d | 257 | // it the state change is for this panel |
53e3ea84 | 258 | if (stateid && key === stateid && state) { |
9a4c279d DC |
259 | // get active item |
260 | var acard = me.getLayout().getActiveItem().itemId; | |
261 | // get the itemid of the new value | |
262 | var ncard = state.value || me.firstItem; | |
ee390345 | 263 | if (ncard && acard !== ncard) { |
9a4c279d DC |
264 | // select the chosen item |
265 | menu.setSelection(root.findChild('id', ncard, true) || root.firstChild); | |
55ed1090 DM |
266 | } |
267 | } | |
268 | }; | |
269 | ||
270 | if (stateid) { | |
9a4c279d | 271 | me.mon(me.sp, 'statechange', statechange); |
55ed1090 | 272 | } |
a83c659a FE |
273 | }, |
274 | ||
275 | insertNodes: function(items) { | |
276 | var me = this; | |
277 | var root = me.store.getRoot(); | |
278 | ||
279 | items.forEach(function(item) { | |
f6710aac | 280 | var treeitem = Ext.create('Ext.data.TreeModel', { |
a83c659a FE |
281 | id: item.itemId, |
282 | text: item.title, | |
283 | iconCls: item.iconCls, | |
284 | leaf: true, | |
f6710aac | 285 | expanded: item.expandedOnInit, |
a83c659a FE |
286 | }); |
287 | item.header = false; | |
288 | if (me.savedItems[item.itemId] !== undefined) { | |
289 | throw "itemId already exists, please use another"; | |
290 | } | |
291 | me.savedItems[item.itemId] = item; | |
292 | ||
293 | var group; | |
294 | var curnode = root; | |
295 | ||
296 | // get/create the group items | |
297 | while (Ext.isArray(item.groups) && item.groups.length > 0) { | |
298 | group = item.groups.shift(); | |
299 | ||
300 | var child = curnode.findChild('id', group); | |
301 | if (child === null) { | |
302 | // did not find the group item | |
303 | // so add it where we are | |
304 | break; | |
305 | } | |
306 | curnode = child; | |
307 | } | |
308 | ||
309 | // insert the item | |
310 | ||
311 | // lets see if it already exists | |
312 | var node = curnode.findChild('id', item.itemId); | |
313 | ||
314 | if (node === null) { | |
315 | curnode.appendChild(treeitem); | |
316 | } else { | |
317 | // should not happen! | |
318 | throw "id already exists"; | |
319 | } | |
320 | }); | |
321 | }, | |
55ed1090 | 322 | }); |