Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php
12242 views
1
<?php
2
3
final class PhabricatorDashboardPanelTabsController
4
extends PhabricatorDashboardController {
5
6
private $contextObject;
7
8
private function setContextObject($context_object) {
9
$this->contextObject = $context_object;
10
return $this;
11
}
12
13
private function getContextObject() {
14
return $this->contextObject;
15
}
16
17
public function handleRequest(AphrontRequest $request) {
18
$viewer = $this->getViewer();
19
20
$panel = id(new PhabricatorDashboardPanelQuery())
21
->setViewer($viewer)
22
->withIDs(array($request->getURIData('id')))
23
->requireCapabilities(
24
array(
25
PhabricatorPolicyCapability::CAN_VIEW,
26
PhabricatorPolicyCapability::CAN_EDIT,
27
))
28
->executeOne();
29
if (!$panel) {
30
return new Aphront404Response();
31
}
32
33
$tabs_type = id(new PhabricatorDashboardTabsPanelType())
34
->getPanelTypeKey();
35
36
// This controller may only be used to edit tab panels.
37
$panel_type = $panel->getPanelType();
38
if ($panel_type !== $tabs_type) {
39
return new Aphront404Response();
40
}
41
42
$op = $request->getURIData('op');
43
$after = $request->getStr('after');
44
if (!phutil_nonempty_string($after)) {
45
$after = null;
46
}
47
48
$target = $request->getStr('target');
49
if (!phutil_nonempty_string($target)) {
50
$target = null;
51
}
52
53
$impl = $panel->getImplementation();
54
$config = $impl->getPanelConfiguration($panel);
55
56
$cancel_uri = $panel->getURI();
57
58
if ($after !== null) {
59
$found = false;
60
foreach ($config as $key => $spec) {
61
if ((string)$key === $after) {
62
$found = true;
63
break;
64
}
65
}
66
67
if (!$found) {
68
return $this->newDialog()
69
->setTitle(pht('Adjacent Tab Not Found'))
70
->appendParagraph(
71
pht(
72
'Adjacent tab ("%s") was not found on this panel. It may have '.
73
'been removed.',
74
$after))
75
->addCancelButton($cancel_uri);
76
}
77
}
78
79
if ($target !== null) {
80
$found = false;
81
foreach ($config as $key => $spec) {
82
if ((string)$key === $target) {
83
$found = true;
84
break;
85
}
86
}
87
88
if (!$found) {
89
return $this->newDialog()
90
->setTitle(pht('Target Tab Not Found'))
91
->appendParagraph(
92
pht(
93
'Target tab ("%s") was not found on this panel. It may have '.
94
'been removed.',
95
$target))
96
->addCancelButton($cancel_uri);
97
}
98
}
99
100
// Tab panels may be edited from the panel page, or from the context of
101
// a dashboard. If we're editing from a dashboard, we want to redirect
102
// back to the dashboard after making changes.
103
104
$context_phid = $request->getStr('contextPHID');
105
$context = null;
106
if (phutil_nonempty_string($context_phid)) {
107
$context = id(new PhabricatorObjectQuery())
108
->setViewer($viewer)
109
->withPHIDs(array($context_phid))
110
->executeOne();
111
if (!$context) {
112
return new Aphront404Response();
113
}
114
115
switch (phid_get_type($context_phid)) {
116
case PhabricatorDashboardDashboardPHIDType::TYPECONST:
117
$cancel_uri = $context->getURI();
118
break;
119
case PhabricatorDashboardPanelPHIDType::TYPECONST:
120
$cancel_uri = $context->getURI();
121
break;
122
default:
123
return $this->newDialog()
124
->setTitle(pht('Context Object Unsupported'))
125
->appendParagraph(
126
pht(
127
'Context object ("%s") has unsupported type. Panels should '.
128
'be rendered from the context of a dashboard or another '.
129
'panel.',
130
$context_phid))
131
->addCancelButton($cancel_uri);
132
}
133
134
$this->setContextObject($context);
135
}
136
137
switch ($op) {
138
case 'add':
139
return $this->handleAddOperation($panel, $after, $cancel_uri);
140
case 'remove':
141
return $this->handleRemoveOperation($panel, $target, $cancel_uri);
142
case 'move':
143
return $this->handleMoveOperation($panel, $target, $after, $cancel_uri);
144
case 'rename':
145
return $this->handleRenameOperation($panel, $target, $cancel_uri);
146
}
147
}
148
149
private function handleAddOperation(
150
PhabricatorDashboardPanel $panel,
151
$after,
152
$cancel_uri) {
153
$request = $this->getRequest();
154
$viewer = $this->getViewer();
155
156
$panel_phid = null;
157
$errors = array();
158
if ($request->isFormPost()) {
159
$panel_phid = $request->getArr('panelPHID');
160
$panel_phid = head($panel_phid);
161
162
$add_panel = id(new PhabricatorDashboardPanelQuery())
163
->setViewer($viewer)
164
->withPHIDs(array($panel_phid))
165
->executeOne();
166
if (!$add_panel) {
167
$errors[] = pht('You must select a valid panel.');
168
}
169
170
if (!$errors) {
171
$add_panel_config = array(
172
'name' => null,
173
'panelID' => $add_panel->getID(),
174
);
175
$add_panel_key = Filesystem::readRandomCharacters(12);
176
177
$impl = $panel->getImplementation();
178
$old_config = $impl->getPanelConfiguration($panel);
179
$new_config = array();
180
if ($after === null) {
181
$new_config = $old_config;
182
$new_config[] = $add_panel_config;
183
} else {
184
foreach ($old_config as $key => $value) {
185
$new_config[$key] = $value;
186
if ((string)$key === $after) {
187
$new_config[$add_panel_key] = $add_panel_config;
188
}
189
}
190
}
191
192
$xactions = array();
193
194
$xactions[] = $panel->getApplicationTransactionTemplate()
195
->setTransactionType(
196
PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
197
->setNewValue($new_config);
198
199
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
200
->setContentSourceFromRequest($request)
201
->setActor($viewer)
202
->setContinueOnNoEffect(true)
203
->setContinueOnMissingFields(true);
204
205
$editor->applyTransactions($panel, $xactions);
206
207
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
208
}
209
}
210
211
if ($panel_phid) {
212
$v_panel = array($panel_phid);
213
} else {
214
$v_panel = array();
215
}
216
217
$form = id(new AphrontFormView())
218
->setViewer($viewer)
219
->appendControl(
220
id(new AphrontFormTokenizerControl())
221
->setDatasource(new PhabricatorDashboardPanelDatasource())
222
->setLimit(1)
223
->setName('panelPHID')
224
->setLabel(pht('Panel'))
225
->setValue($v_panel));
226
227
return $this->newEditDialog()
228
->setTitle(pht('Choose Dashboard Panel'))
229
->setErrors($errors)
230
->addHiddenInput('after', $after)
231
->appendForm($form)
232
->addCancelButton($cancel_uri)
233
->addSubmitButton(pht('Add Panel'));
234
}
235
236
private function handleRemoveOperation(
237
PhabricatorDashboardPanel $panel,
238
$target,
239
$cancel_uri) {
240
$request = $this->getRequest();
241
$viewer = $this->getViewer();
242
243
$panel_phid = null;
244
$errors = array();
245
if ($request->isFormPost()) {
246
$impl = $panel->getImplementation();
247
$old_config = $impl->getPanelConfiguration($panel);
248
249
$new_config = $this->removePanel($old_config, $target);
250
$this->writePanelConfig($panel, $new_config);
251
252
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
253
}
254
255
return $this->newEditDialog()
256
->setTitle(pht('Remove tab?'))
257
->addHiddenInput('target', $target)
258
->appendParagraph(pht('Really remove this tab?'))
259
->addCancelButton($cancel_uri)
260
->addSubmitButton(pht('Remove Tab'));
261
}
262
263
private function handleRenameOperation(
264
PhabricatorDashboardPanel $panel,
265
$target,
266
$cancel_uri) {
267
$request = $this->getRequest();
268
$viewer = $this->getViewer();
269
270
$impl = $panel->getImplementation();
271
$old_config = $impl->getPanelConfiguration($panel);
272
273
$spec = $old_config[$target];
274
$name = idx($spec, 'name');
275
276
if ($request->isFormPost()) {
277
$name = $request->getStr('name');
278
279
$new_config = $this->renamePanel($old_config, $target, $name);
280
$this->writePanelConfig($panel, $new_config);
281
282
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
283
}
284
285
$form = id(new AphrontFormView())
286
->setViewer($viewer)
287
->appendControl(
288
id(new AphrontFormTextControl())
289
->setValue($name)
290
->setName('name')
291
->setLabel(pht('Tab Name')));
292
293
return $this->newEditDialog()
294
->setTitle(pht('Rename Panel'))
295
->addHiddenInput('target', $target)
296
->appendForm($form)
297
->addCancelButton($cancel_uri)
298
->addSubmitButton(pht('Rename Tab'));
299
}
300
301
private function handleMoveOperation(
302
PhabricatorDashboardPanel $panel,
303
$target,
304
$after,
305
$cancel_uri) {
306
$request = $this->getRequest();
307
$viewer = $this->getViewer();
308
309
$move = $request->getStr('move');
310
311
$impl = $panel->getImplementation();
312
$old_config = $impl->getPanelConfiguration($panel);
313
314
$is_next = ($move === 'next');
315
if ($target === $after) {
316
return $this->newDialog()
317
->setTitle(pht('Impossible!'))
318
->appendParagraph(
319
pht(
320
'You can not move a tab relative to itself.'))
321
->addCancelButton($cancel_uri);
322
} else if ($is_next && ((string)last_key($old_config) === $target)) {
323
return $this->newDialog()
324
->setTitle(pht('Impossible!'))
325
->appendParagraph(
326
pht(
327
'This is already the last tab. It can not move any farther to '.
328
'the right.'))
329
->addCancelButton($cancel_uri);
330
} else if ((string)head_key($old_config) === $target) {
331
return $this->newDialog()
332
->setTitle(pht('Impossible!'))
333
->appendParagraph(
334
pht(
335
'This is already the first tab. It can not move any farther to '.
336
'the left.'))
337
->addCancelButton($cancel_uri);
338
}
339
340
if ($request->hasCSRF()) {
341
$new_config = array();
342
foreach ($old_config as $old_key => $old_spec) {
343
$old_key = (string)$old_key;
344
345
$is_after = ($old_key === $after);
346
347
if (!$is_after) {
348
if ($old_key === $target) {
349
continue;
350
}
351
}
352
353
if ($is_after && !$is_next) {
354
$new_config[$target] = $old_config[$target];
355
}
356
357
$new_config[$old_key] = $old_spec;
358
359
if ($is_after && $is_next) {
360
$new_config[$target] = $old_config[$target];
361
}
362
}
363
364
$this->writePanelConfig($panel, $new_config);
365
366
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
367
}
368
369
if ($is_next) {
370
$prompt = pht('Move this tab to the right?');
371
} else {
372
$prompt = pht('Move this tab to the left?');
373
}
374
375
return $this->newEditDialog()
376
->setTitle(pht('Move Tab'))
377
->addHiddenInput('target', $target)
378
->addHiddenInput('after', $after)
379
->addHiddenInput('move', $move)
380
->appendParagraph($prompt)
381
->addCancelButton($cancel_uri)
382
->addSubmitButton(pht('Move Tab'));
383
}
384
385
private function writePanelConfig(
386
PhabricatorDashboardPanel $panel,
387
array $config) {
388
$request = $this->getRequest();
389
$viewer = $this->getViewer();
390
391
$xactions = array();
392
393
$xactions[] = $panel->getApplicationTransactionTemplate()
394
->setTransactionType(
395
PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
396
->setNewValue($config);
397
398
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
399
->setContentSourceFromRequest($request)
400
->setActor($viewer)
401
->setContinueOnNoEffect(true)
402
->setContinueOnMissingFields(true);
403
404
return $editor->applyTransactions($panel, $xactions);
405
}
406
407
private function removePanel(array $config, $target) {
408
$result = array();
409
410
foreach ($config as $key => $panel_spec) {
411
if ((string)$key === $target) {
412
continue;
413
}
414
$result[$key] = $panel_spec;
415
}
416
417
return $result;
418
}
419
420
private function renamePanel(array $config, $target, $name) {
421
$config[$target]['name'] = $name;
422
return $config;
423
}
424
425
protected function newEditDialog() {
426
$dialog = $this->newDialog()
427
->setWidth(AphrontDialogView::WIDTH_FORM);
428
429
$context = $this->getContextObject();
430
if ($context) {
431
$dialog->addHiddenInput('contextPHID', $context->getPHID());
432
}
433
434
return $dialog;
435
}
436
437
}
438
439