Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F18111603
D9572.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D9572.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -354,6 +354,7 @@
'rsrc/js/application/countdown/timer.js' => '361e3ed3',
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'fa187a68',
+ 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '3be3eef5',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'aa077691',
'rsrc/js/application/differential/ChangesetViewManager.js' => 'db09a523',
'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => 'f2441746',
@@ -555,6 +556,7 @@
'javelin-behavior-dark-console' => 'e9fdb5e5',
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
'javelin-behavior-dashboard-move-panels' => 'fa187a68',
+ 'javelin-behavior-dashboard-query-panel-select' => '3be3eef5',
'javelin-behavior-dashboard-tab-panel' => 'aa077691',
'javelin-behavior-device' => '03d6ed07',
'javelin-behavior-differential-add-reviewers-and-ccs' => '533a187b',
@@ -1113,6 +1115,11 @@
1 => 'javelin-dom',
2 => 'phortune-credit-card-form',
),
+ '3be3eef5' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ ),
'40b1ff90' =>
array(
0 => 'javelin-behavior',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1497,6 +1497,7 @@
'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php',
'PhabricatorDashboardPanelSearchApplicationCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php',
'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php',
+ 'PhabricatorDashboardPanelSearchQueryCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php',
'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php',
'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php',
'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php',
@@ -4317,6 +4318,7 @@
'PhabricatorDashboardPanelRenderingEngine' => 'Phobject',
'PhabricatorDashboardPanelSearchApplicationCustomField' => 'PhabricatorStandardCustomField',
'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine',
+ 'PhabricatorDashboardPanelSearchQueryCustomField' => 'PhabricatorStandardCustomField',
'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
@@ -120,6 +120,13 @@
->setViewer($viewer)
->readFieldsFromStorage($panel);
+ if ($is_create && !$request->isFormPost()) {
+ $panel->requireImplementation()->initializeFieldsFromRequest(
+ $panel,
+ $field_list,
+ $request);
+ }
+
$validation_exception = null;
// NOTE: We require 'edit' to distinguish between the "Choose a Type"
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php
--- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php
+++ b/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php
@@ -30,6 +30,7 @@
}
return id(new AphrontFormSelectControl())
+ ->setID($this->getFieldControlID())
->setLabel($this->getFieldName())
->setCaption($this->getCaption())
->setName($this->getFieldKey())
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php
@@ -0,0 +1,67 @@
+<?php
+
+final class PhabricatorDashboardPanelSearchQueryCustomField
+ extends PhabricatorStandardCustomField {
+
+ public function getFieldType() {
+ return 'search.query';
+ }
+
+ public function shouldAppearInApplicationSearch() {
+ return false;
+ }
+
+ public function renderEditControl(array $handles) {
+
+ $engines = id(new PhutilSymbolLoader())
+ ->setAncestorClass('PhabricatorApplicationSearchEngine')
+ ->loadObjects();
+
+ $value = $this->getFieldValue();
+
+ $queries = array();
+ foreach ($engines as $engine_class => $engine) {
+ $engine->setViewer($this->getViewer());
+ $engine_queries = $engine->loadEnabledNamedQueries();
+ $query_map = mpull($engine_queries, 'getQueryName', 'getQueryKey');
+ asort($query_map);
+
+ foreach ($query_map as $key => $name) {
+ $queries[$engine_class][] = array('key' => $key, 'name' => $name);
+ if ($key == $value) {
+ $seen = true;
+ }
+ }
+ }
+
+ if (strlen($value) && !$seen) {
+ $name = pht('Custom Query ("%s")', $value);
+ } else {
+ $name = pht('(None)');
+ }
+
+ $options = array($value => $name);
+
+ $app_control_key = $this->getFieldConfigValue('control.application');
+ Javelin::initBehavior(
+ 'dashboard-query-panel-select',
+ array(
+ 'applicationID' => $this->getFieldControlID($app_control_key),
+ 'queryID' => $this->getFieldControlID(),
+ 'options' => $queries,
+ 'value' => array(
+ 'key' => strlen($value) ? $value : null,
+ 'name' => $name
+ )
+ ));
+
+ return id(new AphrontFormSelectControl())
+ ->setID($this->getFieldControlID())
+ ->setLabel($this->getFieldName())
+ ->setCaption($this->getCaption())
+ ->setName($this->getFieldKey())
+ ->setValue($this->getFieldValue())
+ ->setOptions($options);
+ }
+
+}
diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php
--- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php
+++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php
@@ -12,6 +12,13 @@
PhabricatorDashboardPanel $panel,
PhabricatorDashboardPanelRenderingEngine $engine);
+ public function initializeFieldsFromRequest(
+ PhabricatorDashboardPanel $panel,
+ PhabricatorCustomFieldList $field_list,
+ AphrontRequest $request) {
+ return;
+ }
+
/**
* Should this panel pull content in over AJAX?
*
diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php
--- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php
+++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php
@@ -25,16 +25,45 @@
),
'key' => array(
'name' => pht('Query'),
- 'type' => 'text',
+ 'type' => 'search.query',
+ 'control.application' => 'class',
),
'limit' => array(
- 'name' => pht('Maximum Number of Items'),
- 'caption' => pht('Leave this blank for the default number of items'),
+ 'name' => pht('Limit'),
+ 'caption' => pht('Leave this blank for the default number of items.'),
'type' => 'text',
),
);
}
+ public function initializeFieldsFromRequest(
+ PhabricatorDashboardPanel $panel,
+ PhabricatorCustomFieldList $field_list,
+ AphrontRequest $request) {
+
+ $map = array();
+ if (strlen($request->getStr('engine'))) {
+ $map['class'] = $request->getStr('engine');
+ }
+
+ if (strlen($request->getStr('query'))) {
+ $map['key'] = $request->getStr('query');
+ }
+
+ $full_map = array();
+ foreach ($map as $key => $value) {
+ $full_map["std:dashboard:core:{$key}"] = $value;
+ }
+
+ foreach ($field_list->getFields() as $field) {
+ $field_key = $field->getFieldKey();
+ if (isset($full_map[$field_key])) {
+ $field->setValueFromStorage($full_map[$field_key]);
+ }
+ }
+ }
+
+
public function renderPanelContent(
PhabricatorUser $viewer,
PhabricatorDashboardPanel $panel,
diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php
--- a/src/applications/search/controller/PhabricatorApplicationSearchController.php
+++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php
@@ -174,6 +174,9 @@
pht('Save Custom Query...'));
}
+ // TODO: A "Create Dashboard Panel" action goes here somewhere once
+ // we sort out T5307.
+
$form->appendChild($submit);
$filter_view = id(new AphrontListFilterView())->appendChild($form);
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
@@ -391,4 +391,9 @@
return $this->getFieldValue();
}
+ public function getFieldControlID($key = null) {
+ $key = coalesce($key, $this->getRawStandardFieldKey());
+ return 'std:control:'.$key;
+ }
+
}
diff --git a/webroot/rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js b/webroot/rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js
@@ -0,0 +1,64 @@
+/**
+ * @provides javelin-behavior-dashboard-query-panel-select
+ * @requires javelin-behavior
+ * javelin-dom
+ */
+
+/**
+ * When editing a "Query" panel on dashboards, make the "Query" selector control
+ * dynamically update in response to changes to the "Engine" selector control.
+ */
+JX.behavior('dashboard-query-panel-select', function(config) {
+
+ var app_control = JX.$(config.applicationID);
+ var query_control = JX.$(config.queryID);
+
+ // If we have a currently-selected query, add it to the appropriate group
+ // in the options list if it does not already exist.
+ if (config.value.key !== null) {
+ var app = app_control.value;
+ if (!(app in config.options)) {
+ config.options[app] = [];
+ }
+
+ var found = false;
+ for (var ii = 0; ii < config.options[app].length; ii++) {
+ if (config.options[app][ii].key == config.value.key) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ config.options[app] = [config.value].concat(config.options[app]);
+ }
+ }
+
+ // When the user changes the selected search engine, update the query
+ // control to show avialable queries for that engine.
+ function update() {
+ var app = app_control.value;
+
+ var old_value = query_control.value;
+ var new_value = null;
+
+ var options = config.options[app] || [];
+ var nodes = [];
+ for (var ii = 0; ii < options.length; ii++) {
+ if (new_value === null) {
+ new_value = options[ii].key;
+ }
+ if (options[ii].key == old_value) {
+ new_value = options[ii].key;
+ }
+ nodes.push(JX.$N('option', {value: options[ii].key}, options[ii].name));
+ }
+
+ JX.DOM.setContent(query_control, nodes);
+ query_control.value = new_value;
+ }
+
+ JX.DOM.listen(app_control, 'change', null, function(e) { update(); });
+ update();
+
+});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Aug 13 2025, 11:12 AM (9 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
8370180
Default Alt Text
D9572.diff (12 KB)
Attached To
Mode
D9572: Make query panels editable by normal humans
Attached
Detach File
Event Timeline
Log In to Comment