1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 10:12:41 +01:00

Allow Doorkeeper references to have multiple display variations (full, short, etc.)

Summary:
Ref T13102. An install has a custom rule for bridging JIRA references via Doorkeeper and would like to be able to render them as `JIRA-123` instead of `JIRA JIRA-123 Full JIRA title`.

I think it's reasonable to imagine future support upstream for `JIRA-123`, `{JIRA-123}`, and so on, although we do not support these today. We can take a small step toward eventual support by letting the rendering pipeline understand different view modes.

This adds an optional `name` (the default text rendered before we do the OAuth sync) and an optional `view`, which can be `short` or `full`.

Test Plan:
I tested this primarily with Asana, since it's less of a pain to set up than JIRA. The logic should be similar, hopefully.

I changed `DoorkeeperAsanaRemarkupRule` to specify `name` and `view`, e.g `'view' => (mt_rand(0, 1) ? 'short' : 'full')`. Then I made a bunch of Asana references in a comment and saw them randomly go short or long.

Maniphest Tasks: T13102

Differential Revision: https://secure.phabricator.com/D19215
This commit is contained in:
epriestley 2018-03-13 11:09:22 -07:00
parent a4a390fe2d
commit 2b19f91936
6 changed files with 98 additions and 30 deletions

View file

@ -10,7 +10,7 @@ return array(
'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65', 'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => 'c218ed53', 'core.pkg.css' => 'c218ed53',
'core.pkg.js' => '8b7400e7', 'core.pkg.js' => '0fabde4f',
'darkconsole.pkg.js' => '1f9a31bc', 'darkconsole.pkg.js' => '1f9a31bc',
'differential.pkg.css' => '113e692c', 'differential.pkg.css' => '113e692c',
'differential.pkg.js' => 'f6d809c0', 'differential.pkg.js' => 'f6d809c0',
@ -391,7 +391,7 @@ return array(
'rsrc/js/application/diffusion/behavior-load-blame.js' => '42126667', 'rsrc/js/application/diffusion/behavior-load-blame.js' => '42126667',
'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947', 'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947',
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc', 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '1db13e70',
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef', 'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab', 'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
@ -608,7 +608,7 @@ return array(
'javelin-behavior-diffusion-jump-to' => '73d09eef', 'javelin-behavior-diffusion-jump-to' => '73d09eef',
'javelin-behavior-diffusion-locate-file' => '6d3e1947', 'javelin-behavior-diffusion-locate-file' => '6d3e1947',
'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc', 'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc',
'javelin-behavior-doorkeeper-tag' => 'e5822781', 'javelin-behavior-doorkeeper-tag' => '1db13e70',
'javelin-behavior-drydock-live-operation-status' => '901935ef', 'javelin-behavior-drydock-live-operation-status' => '901935ef',
'javelin-behavior-durable-column' => '2ae077e1', 'javelin-behavior-durable-column' => '2ae077e1',
'javelin-behavior-editengine-reorder-configs' => 'd7a74243', 'javelin-behavior-editengine-reorder-configs' => 'd7a74243',
@ -1024,6 +1024,13 @@ return array(
'javelin-request', 'javelin-request',
'javelin-uri', 'javelin-uri',
), ),
'1db13e70' => array(
'javelin-behavior',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-magical-init',
),
'1f6794f6' => array( '1f6794f6' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-stratcom', 'javelin-stratcom',
@ -2087,13 +2094,6 @@ return array(
'javelin-behavior', 'javelin-behavior',
'javelin-dom', 'javelin-dom',
), ),
'e5822781' => array(
'javelin-behavior',
'javelin-dom',
'javelin-json',
'javelin-workflow',
'javelin-magical-init',
),
'e74b7517' => array( 'e74b7517' => array(
'javelin-install', 'javelin-install',
'phuix-button-view', 'phuix-button-view',

View file

@ -97,6 +97,7 @@ final class DoorkeeperBridgeJIRA extends DoorkeeperBridge {
$ref->setAttribute('title', idx($fields, 'summary')); $ref->setAttribute('title', idx($fields, 'summary'));
$ref->setAttribute('description', idx($result, 'description')); $ref->setAttribute('description', idx($result, 'description'));
$ref->setAttribute('shortname', $result['key']);
$obj = $ref->getExternalObject(); $obj = $ref->getExternalObject();
if ($obj->getID()) { if ($obj->getID()) {

View file

@ -13,17 +13,13 @@ final class DoorkeeperTagsController extends PhabricatorController {
} }
$refs = array(); $refs = array();
$id_map = array(); foreach ($tags as $key => $tag_spec) {
foreach ($tags as $tag_spec) {
$tag = $tag_spec['ref']; $tag = $tag_spec['ref'];
$ref = id(new DoorkeeperObjectRef()) $ref = id(new DoorkeeperObjectRef())
->setApplicationType($tag[0]) ->setApplicationType($tag[0])
->setApplicationDomain($tag[1]) ->setApplicationDomain($tag[1])
->setObjectType($tag[2]) ->setObjectType($tag[2])
->setObjectID($tag[3]); ->setObjectID($tag[3]);
$key = $ref->getObjectKey();
$id_map[$key] = $tag_spec['id'];
$refs[$key] = $ref; $refs[$key] = $ref;
} }
@ -43,19 +39,30 @@ final class DoorkeeperTagsController extends PhabricatorController {
continue; continue;
} }
$id = $id_map[$key]; $tag_spec = $tags[$key];
$id = $tag_spec['id'];
$view = idx($tag_spec, 'view');
$is_short = ($view == 'short');
if ($is_short) {
$name = $ref->getShortName();
} else {
$name = $ref->getFullName();
}
$tag = id(new PHUITagView()) $tag = id(new PHUITagView())
->setID($id) ->setID($id)
->setName($ref->getFullName()) ->setName($name)
->setHref($uri) ->setHref($uri)
->setType(PHUITagView::TYPE_OBJECT) ->setType(PHUITagView::TYPE_OBJECT)
->setExternal(true) ->setExternal(true)
->render(); ->render();
$results[] = array( $results[] = array(
'id' => $id, 'id' => $id,
'markup' => $tag, 'markup' => $tag,
); );
} }

View file

@ -107,6 +107,13 @@ final class DoorkeeperObjectRef extends Phobject {
pht('External Object')); pht('External Object'));
} }
public function getShortName() {
return coalesce(
$this->getAttribute('shortname'),
$this->getAttribute('name'),
pht('External Object'));
}
public function getObjectKey() { public function getObjectKey() {
if (!$this->objectKey) { if (!$this->objectKey) {
$this->objectKey = PhabricatorHash::digestForIndex( $this->objectKey = PhabricatorHash::digestForIndex(

View file

@ -4,11 +4,41 @@ abstract class DoorkeeperRemarkupRule extends PhutilRemarkupRule {
const KEY_TAGS = 'doorkeeper.tags'; const KEY_TAGS = 'doorkeeper.tags';
const VIEW_FULL = 'full';
const VIEW_SHORT = 'short';
public function getPriority() { public function getPriority() {
return 350.0; return 350.0;
} }
protected function addDoorkeeperTag(array $spec) { protected function addDoorkeeperTag(array $spec) {
PhutilTypeSpec::checkMap(
$spec,
array(
'href' => 'string',
'tag' => 'map<string, wild>',
'name' => 'optional string',
'view' => 'optional string',
));
$spec = $spec + array(
'view' => self::VIEW_FULL,
);
$views = array(
self::VIEW_FULL,
self::VIEW_SHORT,
);
$views = array_fuse($views);
if (!isset($views[$spec['view']])) {
throw new Exception(
pht(
'Unsupported Doorkeeper tag view mode "%s". Supported modes are: %s.',
$spec['view'],
implode(', ', $views)));
}
$key = self::KEY_TAGS; $key = self::KEY_TAGS;
$engine = $this->getEngine(); $engine = $this->getEngine();
$token = $engine->storeText(get_class($this)); $token = $engine->storeText(get_class($this));
@ -36,19 +66,26 @@ abstract class DoorkeeperRemarkupRule extends PhutilRemarkupRule {
$refs = array(); $refs = array();
foreach ($tags as $spec) { foreach ($tags as $spec) {
$tag_id = celerity_generate_unique_node_id(); $href = $spec['href'];
$name = idx($spec, 'name', $href);
$refs[] = array( $this->assertFlatText($href);
'id' => $tag_id, $this->assertFlatText($name);
) + $spec['tag'];
if ($this->getEngine()->isTextMode()) { if ($this->getEngine()->isTextMode()) {
$view = $spec['href']; $view = "{$name} <{$href}>";
} else { } else {
$tag_id = celerity_generate_unique_node_id();
$refs[] = array(
'id' => $tag_id,
'view' => $spec['view'],
) + $spec['tag'];
$view = id(new PHUITagView()) $view = id(new PHUITagView())
->setID($tag_id) ->setID($tag_id)
->setName($this->assertFlatText($spec['href'])) ->setName($name)
->setHref($this->assertFlatText($spec['href'])) ->setHref($href)
->setType(PHUITagView::TYPE_OBJECT) ->setType(PHUITagView::TYPE_OBJECT)
->setExternal(true); ->setExternal(true);
} }
@ -56,7 +93,9 @@ abstract class DoorkeeperRemarkupRule extends PhutilRemarkupRule {
$engine->overwriteStoredText($spec['token'], $view); $engine->overwriteStoredText($spec['token'], $view);
} }
Javelin::initBehavior('doorkeeper-tag', array('tags' => $refs)); if ($refs) {
Javelin::initBehavior('doorkeeper-tag', array('tags' => $refs));
}
$engine->setTextMetadata($key, array()); $engine->setTextMetadata($key, array());
} }

View file

@ -40,9 +40,19 @@ JX.behavior('doorkeeper-tag', function(config, statics) {
}; };
for (var ii = 0; ii < tags.length; ii++) { for (var ii = 0; ii < tags.length; ii++) {
var tag_key = tags[ii].ref.join('@'); var key_parts = [];
key_parts = key_parts.concat(tags[ii].ref);
key_parts.push(tags[ii].view);
var tag_key = key_parts.join(' ');
if (tag_key in statics.cache) { if (tag_key in statics.cache) {
have.push({id: tags[ii].id, markup: statics.cache[tag_key]}); have.push(
{
id: tags[ii].id,
markup: statics.cache[tag_key]
});
} else { } else {
need.push(tags[ii]); need.push(tags[ii]);
keys[tags[ii].id] = tag_key; keys[tags[ii].id] = tag_key;
@ -54,7 +64,11 @@ JX.behavior('doorkeeper-tag', function(config, statics) {
} }
if (need.length) { if (need.length) {
new JX.Workflow('/doorkeeper/tags/', {tags: JX.JSON.stringify(need)}) var data = {
tags: JX.JSON.stringify(need)
};
new JX.Workflow('/doorkeeper/tags/', data)
.setHandler(function(r) { draw(r.tags); }) .setHandler(function(r) { draw(r.tags); })
.start(); .start();
} }