]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/panel/ConfigPanel.js
ui: config panel: fix onlineHelp mapping targets
[pve-manager.git] / www / manager6 / panel / ConfigPanel.js
CommitLineData
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
42Ext.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 179 let typeToOnlineHelp = {
7f74dabc
TL
180 'type/lxc': 'chapter_pct',
181 'type/node': 'chapter_system_administration',
182 'type/pool': 'pveum_pools',
183 'type/qemu': 'chapter_virtual_machines',
184 'type/sdn': 'chapter_pvesdn',
185 'type/storage': 'chapter_storage',
ea5d9c35
TL
186 };
187 me.onlineHelp = typeToOnlineHelp[me.pveSelNode.data.id];
9cc74dfe
DC
188 }
189
375d2918
DC
190 if (me.tbarSpacing) {
191 tbar.unshift('->');
192 }
55ed1090
DM
193 tbar.unshift({
194 xtype: 'tbtext',
195 text: title,
f6710aac 196 baseCls: 'x-panel-header-text',
55ed1090
DM
197 });
198
672a6270 199 me.helpButton = Ext.create('Proxmox.button.Help', {
9cc74dfe
DC
200 hidden: false,
201 listenToGlobalEvent: false,
f6710aac 202 onlineHelp: me.onlineHelp || undefined,
9cc74dfe
DC
203 });
204
205 tbar.push(me.helpButton);
206
9a4c279d 207 me.dockedItems[1].items = tbar;
55ed1090 208
9a4c279d
DC
209 // include search tab
210 me.items = me.items || [];
55ed1090 211 if (me.showSearch) {
9a4c279d 212 me.items.unshift({
7e27f5d1
DC
213 itemId: 'search',
214 title: gettext('Search'),
9a4c279d
DC
215 iconCls: 'fa fa-search',
216 xtype: 'pveResourceGrid',
f6710aac 217 pveSelNode: me.pveSelNode,
55ed1090
DM
218 });
219 }
220
9a4c279d 221 me.savedItems = {};
9a4c279d
DC
222 if (me.items[0]) {
223 me.firstItem = me.items[0].itemId;
224 }
55ed1090 225
9a4c279d
DC
226 me.store = Ext.create('Ext.data.TreeStore', {
227 root: {
f6710aac
TL
228 expanded: true,
229 },
9a4c279d
DC
230 });
231 var root = me.store.getRoot();
a83c659a 232 me.insertNodes(me.items);
55ed1090 233
9a4c279d
DC
234 delete me.items;
235 me.defaults = me.defaults || {};
236 Ext.apply(me.defaults, {
237 pveSelNode: me.pveSelNode,
238 viewFilter: me.viewFilter,
239 workspace: me.workspace,
f6710aac 240 border: 0,
55ed1090
DM
241 });
242
243 me.callParent();
244
9a4c279d
DC
245 var menu = me.down('#menu');
246 var selection = root.findChild('id', activeTab, true) || root.firstChild;
247 var node = selection;
248 while (node !== root) {
249 node.expand();
250 node = node.parentNode;
251 }
252 menu.setStore(me.store);
253 menu.setSelection(selection);
254
255 // on a state change,
256 // select the new item
55ed1090 257 var statechange = function(sp, key, state) {
9a4c279d 258 // it the state change is for this panel
53e3ea84 259 if (stateid && key === stateid && state) {
9a4c279d
DC
260 // get active item
261 var acard = me.getLayout().getActiveItem().itemId;
262 // get the itemid of the new value
263 var ncard = state.value || me.firstItem;
ee390345 264 if (ncard && acard !== ncard) {
9a4c279d
DC
265 // select the chosen item
266 menu.setSelection(root.findChild('id', ncard, true) || root.firstChild);
55ed1090
DM
267 }
268 }
269 };
270
271 if (stateid) {
9a4c279d 272 me.mon(me.sp, 'statechange', statechange);
55ed1090 273 }
a83c659a
FE
274 },
275
276 insertNodes: function(items) {
277 var me = this;
278 var root = me.store.getRoot();
279
280 items.forEach(function(item) {
f6710aac 281 var treeitem = Ext.create('Ext.data.TreeModel', {
a83c659a
FE
282 id: item.itemId,
283 text: item.title,
284 iconCls: item.iconCls,
285 leaf: true,
f6710aac 286 expanded: item.expandedOnInit,
a83c659a
FE
287 });
288 item.header = false;
289 if (me.savedItems[item.itemId] !== undefined) {
290 throw "itemId already exists, please use another";
291 }
292 me.savedItems[item.itemId] = item;
293
294 var group;
295 var curnode = root;
296
297 // get/create the group items
298 while (Ext.isArray(item.groups) && item.groups.length > 0) {
299 group = item.groups.shift();
300
301 var child = curnode.findChild('id', group);
302 if (child === null) {
303 // did not find the group item
304 // so add it where we are
305 break;
306 }
307 curnode = child;
308 }
309
310 // insert the item
311
312 // lets see if it already exists
313 var node = curnode.findChild('id', item.itemId);
314
315 if (node === null) {
316 curnode.appendChild(treeitem);
317 } else {
318 // should not happen!
319 throw "id already exists";
320 }
321 });
322 },
55ed1090 323});