Add "Flags" to allow users to collect the things they love
Summary: Flags are a personal collection of things you want to take a look at later. You can use several different colors and add notes. Not really sure if this is actually a good idea or not but it was easy to build. Planned features: - Allow Herald rules to add flags. - In the "edit flag" dialog, have a "[x] Subscribe Me" checkbox that CCs you. - Support Diffusion. - Support Phriction. - Always show flags on an object if you have them (in every view)? - Edit dialog feels a little heavy? - More filtering in /flag/ tool. - Add a top-level links somewhere? Test Plan: Added, edited and removed flags from things. Viewed flags in flag view. Reviewers: aran, btrahan Reviewed By: btrahan CC: aran, epriestley, Koolvin Maniphest Tasks: T1041 Differential Revision: https://secure.phabricator.com/D2024
2
resources/sql/patches/120.noop.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
/* Do nothing, patch 121 got committed before there was a patch 120. */
|
||||
SELECT 1;
|
16
resources/sql/patches/122.flag.sql
Normal file
|
@ -0,0 +1,16 @@
|
|||
CREATE DATABASE phabricator_flag COLLATE utf8_general_ci;
|
||||
|
||||
CREATE TABLE phabricator_flag.flag (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
ownerPHID varchar(64) COLLATE utf8_bin NOT NULL,
|
||||
type varchar(4) COLLATE utf8_bin NOT NULL,
|
||||
objectPHID varchar(64) COLLATE utf8_bin NOT NULL,
|
||||
reasonPHID varchar(64) COLLATE utf8_bin NOT NULL,
|
||||
color INT UNSIGNED NOT NULL,
|
||||
note varchar(255) COLLATE utf8_general_ci,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
|
||||
UNIQUE KEY (ownerPHID, type, objectPHID),
|
||||
KEY (objectPHID)
|
||||
) ENGINE=InnoDB;
|
|
@ -172,7 +172,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'differential-changeset-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/13983f98/rsrc/css/application/differential/changeset-view.css',
|
||||
'uri' => '/res/238f435d/rsrc/css/application/differential/changeset-view.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1595,6 +1595,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/feed/feed.css',
|
||||
),
|
||||
'phabricator-flag-css' =>
|
||||
array(
|
||||
'uri' => '/res/81d9e551/rsrc/css/application/flag/flag.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/flag/flag.css',
|
||||
),
|
||||
'phabricator-jump-nav' =>
|
||||
array(
|
||||
'uri' => '/res/8bdc0fc3/rsrc/css/application/directory/phabricator-jump-nav.css',
|
||||
|
@ -2030,7 +2039,7 @@ celerity_register_resource_map(array(
|
|||
'uri' => '/res/pkg/21d01ed8/core.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'8a5929ca' =>
|
||||
'90c90e95' =>
|
||||
array(
|
||||
'name' => 'differential.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -2048,7 +2057,7 @@ celerity_register_resource_map(array(
|
|||
10 => 'phabricator-content-source-view-css',
|
||||
11 => 'differential-local-commits-view-css',
|
||||
),
|
||||
'uri' => '/res/pkg/8a5929ca/differential.pkg.css',
|
||||
'uri' => '/res/pkg/90c90e95/differential.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'9b256876' =>
|
||||
|
@ -2155,7 +2164,7 @@ celerity_register_resource_map(array(
|
|||
'aphront-crumbs-view-css' => '82263727',
|
||||
'aphront-dialog-view-css' => '82263727',
|
||||
'aphront-form-view-css' => '82263727',
|
||||
'aphront-headsup-action-list-view-css' => '8a5929ca',
|
||||
'aphront-headsup-action-list-view-css' => '90c90e95',
|
||||
'aphront-list-filter-view-css' => '82263727',
|
||||
'aphront-pager-view-css' => '82263727',
|
||||
'aphront-panel-view-css' => '82263727',
|
||||
|
@ -2163,16 +2172,16 @@ celerity_register_resource_map(array(
|
|||
'aphront-table-view-css' => '82263727',
|
||||
'aphront-tokenizer-control-css' => '82263727',
|
||||
'aphront-typeahead-control-css' => '82263727',
|
||||
'differential-changeset-view-css' => '8a5929ca',
|
||||
'differential-core-view-css' => '8a5929ca',
|
||||
'differential-changeset-view-css' => '90c90e95',
|
||||
'differential-core-view-css' => '90c90e95',
|
||||
'differential-inline-comment-editor' => '9b256876',
|
||||
'differential-local-commits-view-css' => '8a5929ca',
|
||||
'differential-revision-add-comment-css' => '8a5929ca',
|
||||
'differential-revision-comment-css' => '8a5929ca',
|
||||
'differential-revision-comment-list-css' => '8a5929ca',
|
||||
'differential-revision-detail-css' => '8a5929ca',
|
||||
'differential-revision-history-css' => '8a5929ca',
|
||||
'differential-table-of-contents-css' => '8a5929ca',
|
||||
'differential-local-commits-view-css' => '90c90e95',
|
||||
'differential-revision-add-comment-css' => '90c90e95',
|
||||
'differential-revision-comment-css' => '90c90e95',
|
||||
'differential-revision-comment-list-css' => '90c90e95',
|
||||
'differential-revision-detail-css' => '90c90e95',
|
||||
'differential-revision-history-css' => '90c90e95',
|
||||
'differential-table-of-contents-css' => '90c90e95',
|
||||
'diffusion-commit-view-css' => '61f9d480',
|
||||
'javelin-behavior' => '4fbae2af',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => '2af849fb',
|
||||
|
@ -2221,7 +2230,7 @@ celerity_register_resource_map(array(
|
|||
'maniphest-task-summary-css' => '31583232',
|
||||
'maniphest-transaction-detail-css' => '31583232',
|
||||
'phabricator-app-buttons-css' => '82263727',
|
||||
'phabricator-content-source-view-css' => '8a5929ca',
|
||||
'phabricator-content-source-view-css' => '90c90e95',
|
||||
'phabricator-core-buttons-css' => '82263727',
|
||||
'phabricator-core-css' => '82263727',
|
||||
'phabricator-directory-css' => '82263727',
|
||||
|
@ -2231,7 +2240,7 @@ celerity_register_resource_map(array(
|
|||
'phabricator-keyboard-shortcut' => '21d01ed8',
|
||||
'phabricator-keyboard-shortcut-manager' => '21d01ed8',
|
||||
'phabricator-menu-item' => '21d01ed8',
|
||||
'phabricator-object-selector-css' => '8a5929ca',
|
||||
'phabricator-object-selector-css' => '90c90e95',
|
||||
'phabricator-paste-file-upload' => '21d01ed8',
|
||||
'phabricator-remarkup-css' => '82263727',
|
||||
'phabricator-shaped-request' => '9b256876',
|
||||
|
|
|
@ -142,6 +142,8 @@ phutil_register_library_map(array(
|
|||
'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download',
|
||||
'ConduitAPI_file_info_Method' => 'applications/conduit/method/file/info',
|
||||
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
|
||||
'ConduitAPI_flag_Method' => 'applications/conduit/method/flag/base',
|
||||
'ConduitAPI_flag_query_Method' => 'applications/conduit/method/flag/query',
|
||||
'ConduitAPI_macro_Method' => 'applications/conduit/method/macro/base',
|
||||
'ConduitAPI_macro_query_Method' => 'applications/conduit/method/macro/query',
|
||||
'ConduitAPI_maniphest_Method' => 'applications/conduit/method/maniphest/base',
|
||||
|
@ -594,6 +596,16 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileUploadController' => 'applications/files/controller/upload',
|
||||
'PhabricatorFileUploadException' => 'applications/files/exception/upload',
|
||||
'PhabricatorFileUploadView' => 'applications/files/view/upload',
|
||||
'PhabricatorFlag' => 'applications/flag/storage/flag',
|
||||
'PhabricatorFlagColor' => 'applications/flag/constants/color',
|
||||
'PhabricatorFlagConstants' => 'applications/flag/constants/base',
|
||||
'PhabricatorFlagController' => 'applications/flag/controller/base',
|
||||
'PhabricatorFlagDAO' => 'applications/flag/storage/base',
|
||||
'PhabricatorFlagDeleteController' => 'applications/flag/controller/delete',
|
||||
'PhabricatorFlagEditController' => 'applications/flag/controller/edit',
|
||||
'PhabricatorFlagListController' => 'applications/flag/controller/list',
|
||||
'PhabricatorFlagListView' => 'applications/flag/view/list',
|
||||
'PhabricatorFlagQuery' => 'applications/flag/query/flag',
|
||||
'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector',
|
||||
'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing',
|
||||
'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
|
||||
|
@ -1052,6 +1064,8 @@ phutil_register_library_map(array(
|
|||
'ConduitAPI_file_download_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_file_info_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_flag_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_flag_query_Method' => 'ConduitAPI_flag_Method',
|
||||
'ConduitAPI_macro_Method' => 'ConduitAPIMethod',
|
||||
'ConduitAPI_macro_query_Method' => 'ConduitAPI_macro_Method',
|
||||
'ConduitAPI_maniphest_Method' => 'ConduitAPIMethod',
|
||||
|
@ -1409,6 +1423,14 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileTransformController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileUploadController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileUploadView' => 'AphrontView',
|
||||
'PhabricatorFlag' => 'PhabricatorFlagDAO',
|
||||
'PhabricatorFlagColor' => 'PhabricatorFlagConstants',
|
||||
'PhabricatorFlagController' => 'PhabricatorController',
|
||||
'PhabricatorFlagDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorFlagDeleteController' => 'PhabricatorFlagController',
|
||||
'PhabricatorFlagEditController' => 'PhabricatorFlagController',
|
||||
'PhabricatorFlagListController' => 'PhabricatorFlagController',
|
||||
'PhabricatorFlagListView' => 'AphrontView',
|
||||
'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon',
|
||||
'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker',
|
||||
'PhabricatorHelpController' => 'PhabricatorController',
|
||||
|
|
|
@ -409,6 +409,13 @@ class AphrontDefaultApplicationConfiguration
|
|||
),
|
||||
|
||||
'/aphlict/' => 'PhabricatorAphlictTestPageController',
|
||||
|
||||
'/flag/' => array(
|
||||
'' => 'PhabricatorFlagListController',
|
||||
'view/(?P<view>[^/]+)/' => 'PhabricatorFlagListController',
|
||||
'edit/(?P<phid>[^/]+)/' => 'PhabricatorFlagEditController',
|
||||
'delete/(?P<id>\d+)/' => 'PhabricatorFlagDeleteController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group conduit
|
||||
*/
|
||||
abstract class ConduitAPI_flag_Method extends ConduitAPIMethod {
|
||||
|
||||
|
||||
}
|
12
src/applications/conduit/method/flag/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/conduit/method/base');
|
||||
|
||||
|
||||
phutil_require_source('ConduitAPI_flag_Method.php');
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group conduit
|
||||
*/
|
||||
final class ConduitAPI_flag_query_Method extends ConduitAPI_flag_Method {
|
||||
|
||||
public function getMethodDescription() {
|
||||
return "Query flag markers.";
|
||||
}
|
||||
|
||||
public function defineParamTypes() {
|
||||
return array(
|
||||
'ownerPHIDs' => 'optional list<phid>',
|
||||
'types' => 'optional list<type>',
|
||||
'objectPHIDs' => 'optional list<phid>',
|
||||
|
||||
'offset' => 'optional int',
|
||||
'limit' => 'optional int (default = 100)',
|
||||
);
|
||||
}
|
||||
|
||||
public function defineReturnType() {
|
||||
return 'list<dict>';
|
||||
}
|
||||
|
||||
public function defineErrorTypes() {
|
||||
return array(
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
|
||||
$query = new PhabricatorFlagQuery();
|
||||
|
||||
$owner_phids = $request->getValue('ownerPHIDs', array());
|
||||
if ($owner_phids) {
|
||||
$query->withOwnerPHIDs($owner_phids);
|
||||
}
|
||||
|
||||
$object_phids = $request->getValue('objectPHIDs', array());
|
||||
if ($object_phids) {
|
||||
$query->withObjectPHIDs($object_phids);
|
||||
}
|
||||
|
||||
$types = $request->getValue('types', array());
|
||||
if ($types) {
|
||||
$query->withTypes($types);
|
||||
}
|
||||
|
||||
$query->needHandles(true);
|
||||
|
||||
$query->setOffset($request->getValue('offset', 0));
|
||||
$query->setLimit($request->getValue('limit', 100));
|
||||
|
||||
$flags = $query->execute();
|
||||
|
||||
$results = array();
|
||||
foreach ($flags as $flag) {
|
||||
$color = $flag->getColor();
|
||||
$uri = PhabricatorEnv::getProductionURI($flag->getHandle()->getURI());
|
||||
|
||||
$results[] = array(
|
||||
'id' => $flag->getID(),
|
||||
'ownerPHID' => $flag->getOwnerPHID(),
|
||||
'type' => $flag->getType(),
|
||||
'objectPHID' => $flag->getObjectPHID(),
|
||||
'reasonPHID' => $flag->getReasonPHID(),
|
||||
'color' => $color,
|
||||
'colorName' => PhabricatorFlagColor::getColorName($color),
|
||||
'note' => $flag->getNote(),
|
||||
'handle' => array(
|
||||
'uri' => $uri,
|
||||
'name' => $flag->getHandle()->getName(),
|
||||
),
|
||||
'dateCreated' => $flag->getDateCreated(),
|
||||
'dateModified' => $flag->getDateModified(),
|
||||
);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
15
src/applications/conduit/method/flag/query/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/conduit/method/flag/base');
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/color');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
|
||||
phutil_require_source('ConduitAPI_flag_query_Method.php');
|
|
@ -164,13 +164,20 @@ final class DifferentialRevisionListController extends DifferentialController {
|
|||
|
||||
$views = $this->buildViews($this->filter, $params['phid'], $revisions);
|
||||
|
||||
$view_objects = ipull($views, 'view');
|
||||
$view_objects = array();
|
||||
foreach ($views as $view) {
|
||||
if (empty($view['special'])) {
|
||||
$view_objects[] = $view['view'];
|
||||
}
|
||||
}
|
||||
$phids = array_mergev(mpull($view_objects, 'getRequiredHandlePHIDs'));
|
||||
$phids[] = $params['phid'];
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
|
||||
foreach ($views as $view) {
|
||||
$view['view']->setHandles($handles);
|
||||
if (empty($view['special'])) {
|
||||
$view['view']->setHandles($handles);
|
||||
}
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader($view['title']);
|
||||
$panel->appendChild($view['view']);
|
||||
|
@ -436,6 +443,26 @@ final class DifferentialRevisionListController extends DifferentialController {
|
|||
'view' => $view,
|
||||
);
|
||||
|
||||
// Flags are sort of private, so only show the flag panel if you're
|
||||
// looking at your own requests.
|
||||
if ($user_phid == $user->getPHID()) {
|
||||
$flags = id(new PhabricatorFlagQuery())
|
||||
->withOwnerPHIDs(array($user_phid))
|
||||
->withTypes(array(PhabricatorPHIDConstants::PHID_TYPE_DREV))
|
||||
->needHandles(true)
|
||||
->execute();
|
||||
|
||||
$view = id(new PhabricatorFlagListView())
|
||||
->setFlags($flags)
|
||||
->setUser($user);
|
||||
|
||||
$views[] = array(
|
||||
'title' => 'Flagged Revisions',
|
||||
'view' => $view,
|
||||
'special' => true,
|
||||
);
|
||||
}
|
||||
|
||||
$view = id(clone $template)
|
||||
->setRevisions($waiting)
|
||||
->setNoDataString("You have no active revisions waiting on others.");
|
||||
|
|
|
@ -11,7 +11,10 @@ phutil_require_module('phabricator', 'aphront/response/redirect');
|
|||
phutil_require_module('phabricator', 'applications/differential/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/differential/query/revision');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/revisionlist');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'applications/flag/view/list');
|
||||
phutil_require_module('phabricator', 'applications/people/storage/user');
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'view/control/pager');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
|
|
|
@ -358,7 +358,8 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
}
|
||||
|
||||
private function getRevisionActions(DifferentialRevision $revision) {
|
||||
$viewer_phid = $this->getRequest()->getUser()->getPHID();
|
||||
$user = $this->getRequest()->getUser();
|
||||
$viewer_phid = $user->getPHID();
|
||||
$viewer_is_owner = ($revision->getAuthorPHID() == $viewer_phid);
|
||||
$viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
|
||||
$viewer_is_cc = in_array($viewer_phid, $revision->getCCPHIDs());
|
||||
|
@ -378,6 +379,28 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
}
|
||||
|
||||
if (!$viewer_is_anonymous) {
|
||||
|
||||
require_celerity_resource('phabricator-flag-css');
|
||||
|
||||
$flag = PhabricatorFlagQuery::loadUserFlag($user, $revision_phid);
|
||||
if ($flag) {
|
||||
$class = PhabricatorFlagColor::getCSSClass($flag->getColor());
|
||||
$color = PhabricatorFlagColor::getColorName($flag->getColor());
|
||||
$links[] = array(
|
||||
'class' => 'flag-clear '.$class,
|
||||
'href' => '/flag/delete/'.$flag->getID().'/',
|
||||
'name' => phutil_escape_html('Remove '.$color.' Flag'),
|
||||
'sigil' => 'workflow',
|
||||
);
|
||||
} else {
|
||||
$links[] = array(
|
||||
'class' => 'flag-add phabricator-flag-ghost',
|
||||
'href' => '/flag/edit/'.$revision_phid.'/',
|
||||
'name' => 'Flag Revision',
|
||||
'sigil' => 'workflow',
|
||||
);
|
||||
}
|
||||
|
||||
if (!$viewer_is_owner && !$viewer_is_reviewer) {
|
||||
$action = $viewer_is_cc ? 'rem' : 'add';
|
||||
$links[] = array(
|
||||
|
|
|
@ -28,6 +28,8 @@ phutil_require_module('phabricator', 'applications/differential/view/revisioncom
|
|||
phutil_require_module('phabricator', 'applications/differential/view/revisiondetail');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/revisionupdatehistory');
|
||||
phutil_require_module('phabricator', 'applications/draft/storage/draft');
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/color');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'applications/markup/syntax');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
|
|
|
@ -74,6 +74,8 @@ final class PhabricatorDirectoryMainController
|
|||
$tasks_panel = null;
|
||||
}
|
||||
|
||||
$flagged_panel = $this->buildFlaggedPanel();
|
||||
|
||||
$jump_panel = $this->buildJumpPanel();
|
||||
$revision_panel = $this->buildRevisionPanel();
|
||||
$app_panel = $this->buildAppPanel();
|
||||
|
@ -87,6 +89,7 @@ final class PhabricatorDirectoryMainController
|
|||
$triage_panel,
|
||||
$revision_panel,
|
||||
$tasks_panel,
|
||||
$flagged_panel,
|
||||
$audit_panel,
|
||||
$commit_panel,
|
||||
);
|
||||
|
@ -193,6 +196,43 @@ final class PhabricatorDirectoryMainController
|
|||
return $panel;
|
||||
}
|
||||
|
||||
private function buildFlaggedPanel() {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$flag_query = id(new PhabricatorFlagQuery())
|
||||
->withOwnerPHIDs(array($user->getPHID()))
|
||||
->needHandles(true)
|
||||
->setLimit(10);
|
||||
|
||||
$flags = $flag_query->execute();
|
||||
|
||||
if (!$flags) {
|
||||
return $this->renderMiniPanel(
|
||||
'No Flags',
|
||||
"You haven't flagged anything.");
|
||||
}
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Flagged Objects');
|
||||
$panel->setCaption("Objects you've flagged.");
|
||||
|
||||
$flag_view = new PhabricatorFlagListView();
|
||||
$flag_view->setFlags($flags);
|
||||
$flag_view->setUser($user);
|
||||
$panel->appendChild($flag_view);
|
||||
|
||||
$panel->addButton(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/flag/',
|
||||
'class' => 'grey button',
|
||||
),
|
||||
"View All Flags \xC2\xBB"));
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
private function buildNeedsTriagePanel(array $projects) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
$user_phid = $user->getPHID();
|
||||
|
|
|
@ -17,6 +17,8 @@ phutil_require_module('phabricator', 'applications/differential/view/revisionlis
|
|||
phutil_require_module('phabricator', 'applications/directory/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/feed/builder/feed');
|
||||
phutil_require_module('phabricator', 'applications/feed/query');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'applications/flag/view/list');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/priority');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/query');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/view/tasklist');
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorFlagConstants {
|
||||
|
||||
}
|
10
src/applications/flag/constants/base/__init__.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagConstants.php');
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlagColor extends PhabricatorFlagConstants {
|
||||
|
||||
const COLOR_RED = 0;
|
||||
const COLOR_ORANGE = 1;
|
||||
const COLOR_YELLOW = 2;
|
||||
const COLOR_GREEN = 3;
|
||||
const COLOR_BLUE = 4;
|
||||
const COLOR_PINK = 5;
|
||||
const COLOR_PURPLE = 6;
|
||||
const COLOR_CHECKERED = 7;
|
||||
|
||||
public static function getColorNameMap() {
|
||||
return array(
|
||||
self::COLOR_RED => 'Red',
|
||||
self::COLOR_ORANGE => 'Orange',
|
||||
self::COLOR_YELLOW => 'Yellow',
|
||||
self::COLOR_GREEN => 'Green',
|
||||
self::COLOR_BLUE => 'Blue',
|
||||
self::COLOR_PINK => 'Pink',
|
||||
self::COLOR_PURPLE => 'Purple',
|
||||
self::COLOR_CHECKERED => 'Checkered',
|
||||
);
|
||||
}
|
||||
|
||||
public static function getColorName($color) {
|
||||
return idx(self::getColorNameMap(), $color, 'Unknown');
|
||||
}
|
||||
|
||||
public static function getCSSClass($color) {
|
||||
return 'phabricator-flag-color-'.(int)$color;
|
||||
}
|
||||
|
||||
}
|
14
src/applications/flag/constants/color/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagColor.php');
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorFlagController extends PhabricatorController {
|
||||
|
||||
public function buildStandardPageResponse($view, array $data) {
|
||||
|
||||
$page = $this->buildStandardPageView();
|
||||
|
||||
$page->setApplicationName('Flag');
|
||||
$page->setBaseURI('/flag/');
|
||||
$page->setTitle(idx($data, 'title'));
|
||||
$page->setGlyph("\xE2\x9A\x90"); // Subtle!
|
||||
$page->appendChild($view);
|
||||
|
||||
$response = new AphrontWebpageResponse();
|
||||
return $response->setContent($page->render());
|
||||
|
||||
}
|
||||
}
|
15
src/applications/flag/controller/base/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/webpage');
|
||||
phutil_require_module('phabricator', 'applications/base/controller/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagController.php');
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlagDeleteController extends PhabricatorFlagController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$flag = id(new PhabricatorFlag())->load($this->id);
|
||||
if (!$flag) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if ($flag->getOwnerPHID() != $user->getPHID()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$flag->delete();
|
||||
|
||||
return id(new AphrontReloadResponse())->setURI('/flag/');
|
||||
}
|
||||
|
||||
}
|
18
src/applications/flag/controller/delete/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/400');
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'aphront/response/reload');
|
||||
phutil_require_module('phabricator', 'applications/flag/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/flag/storage/flag');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagDeleteController.php');
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlagEditController extends PhabricatorFlagController {
|
||||
|
||||
private $phid;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->phid = $data['phid'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$phid = $this->phid;
|
||||
$handles = id(new PhabricatorObjectHandleData(array($phid)))
|
||||
->loadHandles();
|
||||
$handle = $handles[$phid];
|
||||
|
||||
if (!$handle->isComplete()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$flag = PhabricatorFlagQuery::loadUserFlag($user, $phid);
|
||||
|
||||
if (!$flag) {
|
||||
$flag = new PhabricatorFlag();
|
||||
$flag->setOwnerPHID($user->getPHID());
|
||||
$flag->setType($handle->getType());
|
||||
$flag->setObjectPHID($handle->getPHID());
|
||||
$flag->setReasonPHID($user->getPHID());
|
||||
}
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
$flag->setColor($request->getInt('color'));
|
||||
$flag->setNote($request->getStr('note'));
|
||||
$flag->save();
|
||||
|
||||
return id(new AphrontReloadResponse())->setURI('/flag/');
|
||||
}
|
||||
|
||||
$type_name = $handle->getTypeName();
|
||||
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog->setUser($user);
|
||||
|
||||
$dialog->setTitle("Flag {$type_name}");
|
||||
|
||||
$form = new AphrontFormLayoutView();
|
||||
|
||||
$is_new = !$flag->getID();
|
||||
|
||||
if ($is_new) {
|
||||
$form
|
||||
->appendChild(
|
||||
"<p>You can flag this {$type_name} if you want to remember to look ".
|
||||
"at it later.</p><br />");
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setName('color')
|
||||
->setLabel('Flag Color')
|
||||
->setValue($flag->getColor())
|
||||
->setOptions(PhabricatorFlagColor::getColorNameMap()))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)
|
||||
->setName('note')
|
||||
->setLabel('Note')
|
||||
->setValue($flag->getNote()));
|
||||
|
||||
$dialog->appendChild($form);
|
||||
|
||||
$dialog->addCancelButton($handle->getURI());
|
||||
$dialog->addSubmitButton(
|
||||
$is_new ? "Flag {$type_name}" : 'Save');
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
|
||||
}
|
25
src/applications/flag/controller/edit/__init__.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'aphront/response/dialog');
|
||||
phutil_require_module('phabricator', 'aphront/response/reload');
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/color');
|
||||
phutil_require_module('phabricator', 'applications/flag/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'applications/flag/storage/flag');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'view/dialog');
|
||||
phutil_require_module('phabricator', 'view/form/control/select');
|
||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||
phutil_require_module('phabricator', 'view/form/layout');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagEditController.php');
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlagListController extends PhabricatorFlagController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI('/flag/view/'));
|
||||
$nav->addFilter('all', 'Flags');
|
||||
$nav->selectFilter('all', 'all');
|
||||
|
||||
$query = new PhabricatorFlagQuery();
|
||||
$query->withOwnerPHIDs(array($user->getPHID()));
|
||||
$query->needHandles(true);
|
||||
|
||||
$flags = $query->execute();
|
||||
|
||||
$view = new PhabricatorFlagListView();
|
||||
$view->setFlags($flags);
|
||||
$view->setUser($user);
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Flags');
|
||||
$panel->appendChild($view);
|
||||
|
||||
$nav->appendChild($panel);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Flags',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
18
src/applications/flag/controller/list/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/flag/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'applications/flag/view/list');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
|
||||
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagListController.php');
|
170
src/applications/flag/query/flag/PhabricatorFlagQuery.php
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlagQuery {
|
||||
|
||||
private $ownerPHIDs;
|
||||
private $types;
|
||||
private $objectPHIDs;
|
||||
|
||||
private $limit;
|
||||
private $offset;
|
||||
|
||||
private $needHandles;
|
||||
private $needObjects;
|
||||
|
||||
public function withOwnerPHIDs(array $owner_phids) {
|
||||
$this->ownerPHIDs = $owner_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withTypes(array $types) {
|
||||
$this->types = $types;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withObjectPHIDs(array $object_phids) {
|
||||
$this->objectPHIDs = $object_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needHandles($need) {
|
||||
$this->needHandles = $need;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needObjects($need) {
|
||||
$this->needObjects = $need;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLimit($limit) {
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset($offset) {
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function loadUserFlag(PhabricatorUser $user, $object_phid) {
|
||||
// Specifying the type in the query allows us to use a key.
|
||||
return id(new PhabricatorFlag())->loadOneWhere(
|
||||
'ownerPHID = %s AND type = %s AND objectPHID = %s',
|
||||
$user->getPHID(),
|
||||
PhabricatorObjectHandleData::lookupType($object_phid),
|
||||
$object_phid);
|
||||
}
|
||||
|
||||
|
||||
public function execute() {
|
||||
$table = new PhabricatorFlag();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$where = $this->buildWhereClause($conn_r);
|
||||
$limit = $this->buildLimitClause($conn_r);
|
||||
$order = $this->buildOrderClause($conn_r);
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T flag %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$where,
|
||||
$order,
|
||||
$limit);
|
||||
|
||||
$flags = $table->loadAllFromArray($data);
|
||||
|
||||
if ($this->needHandles || $this->needObjects) {
|
||||
$phids = ipull($data, 'objectPHID');
|
||||
$query = new PhabricatorObjectHandleData($phids);
|
||||
|
||||
if ($this->needHandles) {
|
||||
$handles = $query->loadHandles();
|
||||
foreach ($flags as $flag) {
|
||||
$handle = idx($handles, $flag->getObjectPHID());
|
||||
if ($handle) {
|
||||
$flag->attachHandle($handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->needObjects) {
|
||||
$objects = $query->loadObjects();
|
||||
foreach ($flags as $flag) {
|
||||
$object = idx($objects, $flag->getObjectPHID());
|
||||
if ($object) {
|
||||
$flag->attachObject($object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $flags;
|
||||
}
|
||||
|
||||
private function buildWhereClause($conn_r) {
|
||||
|
||||
$where = array();
|
||||
|
||||
if ($this->ownerPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'flag.ownerPHID IN (%Ls)',
|
||||
$this->ownerPHIDs);
|
||||
}
|
||||
|
||||
if ($this->types) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'flag.type IN (%Ls)',
|
||||
$this->types);
|
||||
}
|
||||
|
||||
if ($this->objectPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'flag.objectPHID IN (%Ls)',
|
||||
$this->objectPHIDs);
|
||||
}
|
||||
|
||||
if ($where) {
|
||||
return 'WHERE ('.implode(') AND (', $where).')';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private function buildOrderClause($conn_r) {
|
||||
return 'ORDER BY id DESC';
|
||||
}
|
||||
|
||||
private function buildLimitClause($conn_r) {
|
||||
if ($this->limit && $this->offset) {
|
||||
return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, $this->limit);
|
||||
} else if ($this->limit) {
|
||||
return qsprintf($conn_r, 'LIMIT %d', $this->limit);
|
||||
} else if ($this->offset) {
|
||||
return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, PHP_INT_MAX);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
src/applications/flag/query/flag/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/flag/storage/flag');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagQuery.php');
|
25
src/applications/flag/storage/base/PhabricatorFlagDAO.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorFlagDAO extends PhabricatorLiskDAO {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'flag';
|
||||
}
|
||||
|
||||
}
|
12
src/applications/flag/storage/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/base/storage/lisk');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagDAO.php');
|
55
src/applications/flag/storage/flag/PhabricatorFlag.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlag extends PhabricatorFlagDAO {
|
||||
|
||||
protected $ownerPHID;
|
||||
protected $type;
|
||||
protected $objectPHID;
|
||||
protected $reasonPHID;
|
||||
protected $color = PhabricatorFlagColor::COLOR_BLUE;
|
||||
protected $note;
|
||||
|
||||
private $handle = false;
|
||||
private $object = false;
|
||||
|
||||
public function getObject() {
|
||||
if ($this->object === false) {
|
||||
throw new Exception('Call attachObject() before getObject()!');
|
||||
}
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
public function attachObject($object) {
|
||||
$this->object = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHandle() {
|
||||
if ($this->handle === false) {
|
||||
throw new Exception('Call attachHandle() before getHandle()!');
|
||||
}
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function attachHandle(PhabricatorObjectHandle $handle) {
|
||||
$this->handle = $handle;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
13
src/applications/flag/storage/flag/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/color');
|
||||
phutil_require_module('phabricator', 'applications/flag/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlag.php');
|
105
src/applications/flag/view/list/PhabricatorFlagListView.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorFlagListView extends AphrontView {
|
||||
|
||||
private $flags;
|
||||
private $user;
|
||||
|
||||
public function setFlags(array $flags) {
|
||||
$this->flags = $flags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$user = $this->user;
|
||||
|
||||
require_celerity_resource('phabricator-flag-css');
|
||||
|
||||
$rows = array();
|
||||
foreach ($this->flags as $flag) {
|
||||
$class = PhabricatorFlagColor::getCSSClass($flag->getColor());
|
||||
|
||||
$rows[] = array(
|
||||
phutil_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phabricator-flag-icon '.$class,
|
||||
),
|
||||
''),
|
||||
$flag->getHandle()->renderLink(),
|
||||
phutil_escape_html($flag->getNote()),
|
||||
phabricator_datetime($flag->getDateCreated(), $user),
|
||||
phabricator_render_form(
|
||||
$user,
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'action' => '/flag/edit/'.$flag->getObjectPHID().'/',
|
||||
'sigil' => 'workflow',
|
||||
),
|
||||
phutil_render_tag(
|
||||
'button',
|
||||
array(
|
||||
'class' => 'small grey',
|
||||
),
|
||||
'Edit Flag')),
|
||||
phabricator_render_form(
|
||||
$user,
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'action' => '/flag/delete/'.$flag->getID().'/',
|
||||
'sigil' => 'workflow',
|
||||
),
|
||||
phutil_render_tag(
|
||||
'button',
|
||||
array(
|
||||
'class' => 'small grey',
|
||||
),
|
||||
'Remove Flag')),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'',
|
||||
'Flagged Object',
|
||||
'Note',
|
||||
'Flagged On',
|
||||
'',
|
||||
'',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'pri',
|
||||
'wide',
|
||||
'',
|
||||
'action',
|
||||
'action',
|
||||
));
|
||||
$table->setNoDataString('No flags.');
|
||||
|
||||
return $table->render();
|
||||
}
|
||||
}
|
19
src/applications/flag/view/list/__init__.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/color');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorFlagListView.php');
|
|
@ -253,6 +253,27 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
|||
$action->setClass('action-edit');
|
||||
$actions[] = $action;
|
||||
|
||||
require_celerity_resource('phabricator-flag-css');
|
||||
$flag = PhabricatorFlagQuery::loadUserFlag($user, $task->getPHID());
|
||||
if ($flag) {
|
||||
$class = PhabricatorFlagColor::getCSSClass($flag->getColor());
|
||||
$color = PhabricatorFlagColor::getColorName($flag->getColor());
|
||||
|
||||
$action = new AphrontHeadsupActionView();
|
||||
$action->setClass('flag-clear '.$class);
|
||||
$action->setURI('/flag/delete/'.$flag->getID().'/');
|
||||
$action->setName('Remove '.$color.' Flag');
|
||||
$action->setWorkflow(true);
|
||||
$actions[] = $action;
|
||||
} else {
|
||||
$action = new AphrontHeadsupActionView();
|
||||
$action->setClass('phabricator-flag-ghost');
|
||||
$action->setURI('/flag/edit/'.$task->getPHID().'/');
|
||||
$action->setName('Flag Task');
|
||||
$action->setWorkflow(true);
|
||||
$actions[] = $action;
|
||||
}
|
||||
|
||||
require_celerity_resource('phabricator-object-selector-css');
|
||||
require_celerity_resource('javelin-behavior-phabricator-object-selector');
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'applications/draft/storage/draft');
|
||||
phutil_require_module('phabricator', 'applications/files/storage/file');
|
||||
phutil_require_module('phabricator', 'applications/flag/constants/color');
|
||||
phutil_require_module('phabricator', 'applications/flag/query/flag');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/priority');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
|
||||
|
|
|
@ -27,7 +27,7 @@ final class PhabricatorObjectHandleData {
|
|||
public function loadObjects() {
|
||||
$types = array();
|
||||
foreach ($this->phids as $phid) {
|
||||
$type = $this->lookupType($phid);
|
||||
$type = self::lookupType($phid);
|
||||
$types[$type][] = $phid;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ final class PhabricatorObjectHandleData {
|
|||
|
||||
$types = array();
|
||||
foreach ($this->phids as $phid) {
|
||||
$type = $this->lookupType($phid);
|
||||
$type = self::lookupType($phid);
|
||||
$types[$type][] = $phid;
|
||||
}
|
||||
|
||||
|
@ -493,7 +493,7 @@ final class PhabricatorObjectHandleData {
|
|||
return $handles;
|
||||
}
|
||||
|
||||
private function lookupType($phid) {
|
||||
public static function lookupType($phid) {
|
||||
$matches = null;
|
||||
if (preg_match('/^PHID-([^-]{4})-/', $phid, $matches)) {
|
||||
return $matches[1];
|
||||
|
|
44
webroot/rsrc/css/application/flag/flag.css
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @provides phabricator-flag-css
|
||||
*/
|
||||
|
||||
.phabricator-flag-icon {
|
||||
padding: 8px;
|
||||
background: transparent 0 0 no-repeat;
|
||||
}
|
||||
|
||||
.phabricator-flag-color-0 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_red.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-1 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_orange.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-2 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_yellow.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-3 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_green.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-4 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_blue.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-5 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_pink.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-6 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_purple.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-color-7 {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_finish.png);
|
||||
}
|
||||
|
||||
.phabricator-flag-ghost {
|
||||
background-image: url(/rsrc/image/icon/fatcow/flag_ghost.png);
|
||||
}
|
BIN
webroot/rsrc/image/icon/fatcow/flag_blue.png
Executable file
After Width: | Height: | Size: 726 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_finish.png
Executable file
After Width: | Height: | Size: 786 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_ghost.png
Normal file
After Width: | Height: | Size: 561 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_green.png
Executable file
After Width: | Height: | Size: 722 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_orange.png
Executable file
After Width: | Height: | Size: 709 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_pink.png
Executable file
After Width: | Height: | Size: 711 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_purple.png
Executable file
After Width: | Height: | Size: 744 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_red.png
Executable file
After Width: | Height: | Size: 737 B |
BIN
webroot/rsrc/image/icon/fatcow/flag_yellow.png
Executable file
After Width: | Height: | Size: 671 B |