diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d050187ca1..af7dba56bd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,1018 +1,1025 @@ array( 'Aphront304Response' => 'aphront/response/304', 'Aphront400Response' => 'aphront/response/400', 'Aphront404Response' => 'aphront/response/404', 'AphrontAjaxResponse' => 'aphront/response/ajax', 'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration', 'AphrontAttachedFileView' => 'view/control/attachedfile', 'AphrontController' => 'aphront/controller', 'AphrontCrumbsView' => 'view/layout/crumbs', 'AphrontDatabaseConnection' => 'storage/connection/base', 'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration', 'AphrontDefaultApplicationController' => 'aphront/default/controller', 'AphrontDialogResponse' => 'aphront/response/dialog', 'AphrontDialogView' => 'view/dialog', 'AphrontErrorView' => 'view/form/error', 'AphrontException' => 'aphront/exception/base', 'AphrontFilePreviewView' => 'view/layout/filepreview', 'AphrontFileResponse' => 'aphront/response/file', 'AphrontFormCheckboxControl' => 'view/form/control/checkbox', 'AphrontFormControl' => 'view/form/control/base', 'AphrontFormDividerControl' => 'view/form/control/divider', 'AphrontFormDragAndDropUploadControl' => 'view/form/control/draganddropupload', 'AphrontFormFileControl' => 'view/form/control/file', 'AphrontFormLayoutView' => 'view/form/layout', 'AphrontFormMarkupControl' => 'view/form/control/markup', 'AphrontFormPasswordControl' => 'view/form/control/password', 'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha', 'AphrontFormSelectControl' => 'view/form/control/select', 'AphrontFormStaticControl' => 'view/form/control/static', 'AphrontFormSubmitControl' => 'view/form/control/submit', 'AphrontFormTextAreaControl' => 'view/form/control/textarea', 'AphrontFormTextControl' => 'view/form/control/text', 'AphrontFormToggleButtonsControl' => 'view/form/control/togglebuttons', 'AphrontFormTokenizerControl' => 'view/form/control/tokenizer', 'AphrontFormView' => 'view/form/base', 'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist', 'AphrontHeadsupActionView' => 'view/layout/headsup/action', 'AphrontIsolatedDatabaseConnection' => 'storage/connection/isolated', 'AphrontIsolatedDatabaseConnectionTestCase' => 'storage/connection/isolated/__tests__', 'AphrontKeyboardShortcutsAvailableView' => 'view/widget/keyboardshortcuts', 'AphrontListFilterView' => 'view/layout/listfilter', 'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql', 'AphrontNullView' => 'view/null', 'AphrontPageView' => 'view/page/base', 'AphrontPagerView' => 'view/control/pager', 'AphrontPanelView' => 'view/layout/panel', 'AphrontQueryAccessDeniedException' => 'storage/exception/accessdenied', 'AphrontQueryConnectionException' => 'storage/exception/connection', 'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost', 'AphrontQueryCountException' => 'storage/exception/count', 'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey', 'AphrontQueryException' => 'storage/exception/base', 'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing', 'AphrontQueryParameterException' => 'storage/exception/parameter', 'AphrontQueryRecoverableException' => 'storage/exception/recoverable', 'AphrontRedirectException' => 'aphront/exception/redirect', 'AphrontRedirectResponse' => 'aphront/response/redirect', 'AphrontReloadResponse' => 'aphront/response/reload', 'AphrontRequest' => 'aphront/request', 'AphrontRequestFailureView' => 'view/page/failure', 'AphrontResponse' => 'aphront/response/base', 'AphrontSideNavView' => 'view/layout/sidenav', 'AphrontTableView' => 'view/control/table', 'AphrontTokenizerTemplateView' => 'view/control/tokenizer', 'AphrontTypeaheadTemplateView' => 'view/control/typeahead', 'AphrontURIMapper' => 'aphront/mapper', 'AphrontView' => 'view/base', 'AphrontWebpageResponse' => 'aphront/response/webpage', 'CelerityAPI' => 'infrastructure/celerity/api', 'CelerityResourceController' => 'infrastructure/celerity/controller', 'CelerityResourceMap' => 'infrastructure/celerity/map', 'CelerityStaticResourceResponse' => 'infrastructure/celerity/response', 'ConduitAPIMethod' => 'applications/conduit/method/base', 'ConduitAPIRequest' => 'applications/conduit/protocol/request', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect', 'ConduitAPI_conduit_getcertificate_Method' => 'applications/conduit/method/conduit/getcertificate', 'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping', 'ConduitAPI_daemon_launched_Method' => 'applications/conduit/method/daemon/launched', 'ConduitAPI_daemon_log_Method' => 'applications/conduit/method/daemon/log', 'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff', 'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision', 'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find', 'ConduitAPI_differential_getalldiffs_Method' => 'applications/conduit/method/differential/getalldiffs', 'ConduitAPI_differential_getcommitmessage_Method' => 'applications/conduit/method/differential/getcommitmessage', 'ConduitAPI_differential_getcommitpaths_Method' => 'applications/conduit/method/differential/getcommitpaths', 'ConduitAPI_differential_getdiff_Method' => 'applications/conduit/method/differential/getdiff', 'ConduitAPI_differential_getrevision_Method' => 'applications/conduit/method/differential/getrevision', 'ConduitAPI_differential_getrevisionfeedback_Method' => 'applications/conduit/method/differential/getrevisionfeedback', 'ConduitAPI_differential_markcommitted_Method' => 'applications/conduit/method/differential/markcommitted', 'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty', 'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision', 'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'applications/conduit/method/differential/updatetaskrevisionassoc', 'ConduitAPI_differential_updateunitresults_Method' => 'applications/conduit/method/differential/updateunitresults', 'ConduitAPI_diffusion_getcommits_Method' => 'applications/conduit/method/diffusion/getcommits', 'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/conduit/method/diffusion/getrecentcommitsbypath', 'ConduitAPI_file_download_Method' => 'applications/conduit/method/file/download', 'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload', 'ConduitAPI_maniphest_info_Method' => 'applications/conduit/method/maniphest/info', 'ConduitAPI_paste_info_Method' => 'applications/conduit/method/paste/info', 'ConduitAPI_path_getowners_Method' => 'applications/conduit/method/path/getowners', 'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find', 'ConduitAPI_user_whoami_Method' => 'applications/conduit/method/user/whoami', 'ConduitException' => 'applications/conduit/protocol/exception', 'DarkConsole' => 'aphront/console/api', 'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config', 'DarkConsoleController' => 'aphront/console/controller', 'DarkConsoleCore' => 'aphront/console/core', 'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog', 'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api', 'DarkConsolePlugin' => 'aphront/console/plugin/base', 'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request', 'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services', 'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof', 'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api', 'DatabaseConfigurationProvider' => 'applications/base/storage/configuration', 'DifferentialAction' => 'applications/differential/constants/action', 'DifferentialAddCommentView' => 'applications/differential/view/addcomment', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome', 'DifferentialChangeType' => 'applications/differential/constants/changetype', 'DifferentialChangeset' => 'applications/differential/storage/changeset', 'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview', 'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview', 'DifferentialChangesetParser' => 'applications/differential/parser/changeset', 'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview', 'DifferentialComment' => 'applications/differential/storage/comment', 'DifferentialCommentEditor' => 'applications/differential/editor/comment', 'DifferentialCommentMail' => 'applications/differential/mail/comment', 'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview', 'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave', 'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage', 'DifferentialCommitMessageData' => 'applications/differential/data/commitmessage', 'DifferentialCommitMessageField' => 'applications/differential/data/commitmessage', 'DifferentialCommitMessageModifier' => 'applications/differential/data/commitmessage', 'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', 'DifferentialDiff' => 'applications/differential/storage/diff', 'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent', 'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate', 'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialExceptionMail' => 'applications/differential/mail/exception', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview', 'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialMail' => 'applications/differential/mail/base', 'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup', 'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff', 'DifferentialPrimaryPaneView' => 'applications/differential/view/primarypane', 'DifferentialReplyHandler' => 'applications/differential/replyhandler', 'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest', 'DifferentialRevision' => 'applications/differential/storage/revision', 'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist', 'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem', 'DifferentialRevisionDetailRenderer' => 'applications/differential/controller/customrenderer', 'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail', 'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit', 'DifferentialRevisionEditor' => 'applications/differential/editor/revision', 'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist', 'DifferentialRevisionListData' => 'applications/differential/data/revisionlist', 'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory', 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialSubscribeController' => 'applications/differential/controller/subscribe', 'DifferentialTasksAttacher' => 'applications/differential/tasks', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', 'DifferentialUnitTestResult' => 'applications/differential/constants/unittestresult', 'DifferentialViewTime' => 'applications/differential/storage/viewtime', 'DiffusionBranchInformation' => 'applications/diffusion/data/branch', 'DiffusionBranchQuery' => 'applications/diffusion/query/branch/base', 'DiffusionBranchTableView' => 'applications/diffusion/view/branchtable', 'DiffusionBrowseController' => 'applications/diffusion/controller/browse', 'DiffusionBrowseFileController' => 'applications/diffusion/controller/file', 'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base', 'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable', 'DiffusionChangeController' => 'applications/diffusion/controller/change', 'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable', 'DiffusionCommitController' => 'applications/diffusion/controller/commit', 'DiffusionController' => 'applications/diffusion/controller/base', 'DiffusionDiffController' => 'applications/diffusion/controller/diff', 'DiffusionDiffQuery' => 'applications/diffusion/query/diff/base', 'DiffusionFileContent' => 'applications/diffusion/data/filecontent', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base', 'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/git', 'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git', 'DiffusionGitDiffQuery' => 'applications/diffusion/query/diff/git', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git', 'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git', 'DiffusionGitLastModifiedQuery' => 'applications/diffusion/query/lastmodified/git', 'DiffusionGitPathIDQuery' => 'applications/diffusion/query/pathid/base', 'DiffusionGitRequest' => 'applications/diffusion/request/git', 'DiffusionHistoryController' => 'applications/diffusion/controller/history', 'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base', 'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable', 'DiffusionHomeController' => 'applications/diffusion/controller/home', 'DiffusionLastModifiedController' => 'applications/diffusion/controller/lastmodified', 'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/base', 'DiffusionPathChange' => 'applications/diffusion/data/pathchange', 'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base', 'DiffusionPathCompleteController' => 'applications/diffusion/controller/pathcomplete', 'DiffusionPathValidateController' => 'applications/diffusion/controller/pathvalidate', 'DiffusionRepositoryController' => 'applications/diffusion/controller/repository', 'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath', 'DiffusionRequest' => 'applications/diffusion/request/base', 'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn', 'DiffusionSvnDiffQuery' => 'applications/diffusion/query/diff/svn', 'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/svn', 'DiffusionSvnHistoryQuery' => 'applications/diffusion/query/history/svn', 'DiffusionSvnLastModifiedQuery' => 'applications/diffusion/query/lastmodified/svn', 'DiffusionSvnRequest' => 'applications/diffusion/request/svn', 'DiffusionView' => 'applications/diffusion/view/base', 'HeraldAction' => 'applications/herald/storage/action', 'HeraldActionConfig' => 'applications/herald/config/action', 'HeraldApplyTranscript' => 'applications/herald/storage/transcript/apply', 'HeraldCommitAdapter' => 'applications/herald/adapter/commit', 'HeraldCondition' => 'applications/herald/storage/condition', 'HeraldConditionConfig' => 'applications/herald/config/condition', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/condition', 'HeraldContentTypeConfig' => 'applications/herald/config/contenttype', 'HeraldController' => 'applications/herald/controller/base', 'HeraldDAO' => 'applications/herald/storage/base', 'HeraldDeleteController' => 'applications/herald/controller/delete', 'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/differential', 'HeraldDryRunAdapter' => 'applications/herald/adapter/dryrun', 'HeraldEffect' => 'applications/herald/engine/effect', 'HeraldEngine' => 'applications/herald/engine/engine', 'HeraldFieldConfig' => 'applications/herald/config/field', 'HeraldHomeController' => 'applications/herald/controller/home', 'HeraldInvalidConditionException' => 'applications/herald/engine/engine/exception', 'HeraldInvalidFieldException' => 'applications/herald/engine/engine/exception', 'HeraldNewController' => 'applications/herald/controller/new', 'HeraldObjectAdapter' => 'applications/herald/adapter/base', 'HeraldObjectTranscript' => 'applications/herald/storage/transcript/object', 'HeraldRecursiveConditionsException' => 'applications/herald/engine/engine/exception', 'HeraldRepetitionPolicyConfig' => 'applications/herald/config/repetitionpolicy', 'HeraldRule' => 'applications/herald/storage/rule', 'HeraldRuleController' => 'applications/herald/controller/rule', 'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule', 'HeraldTestConsoleController' => 'applications/herald/controller/test', 'HeraldTranscript' => 'applications/herald/storage/transcript/base', 'HeraldTranscriptController' => 'applications/herald/controller/transcript', 'HeraldTranscriptListController' => 'applications/herald/controller/transcriptlist', 'HeraldValueTypeConfig' => 'applications/herald/config/valuetype', 'Javelin' => 'infrastructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'LiskIsolationTestCase' => 'storage/lisk/dao/__tests__', 'LiskIsolationTestDAO' => 'storage/lisk/dao/__tests__', 'LiskIsolationTestDAOException' => 'storage/lisk/dao/__tests__', + 'ManiphestConstants' => 'applications/maniphest/constants/base', 'ManiphestController' => 'applications/maniphest/controller/base', 'ManiphestDAO' => 'applications/maniphest/storage/base', 'ManiphestReplyHandler' => 'applications/maniphest/replyhandler', 'ManiphestTask' => 'applications/maniphest/storage/task', 'ManiphestTaskDescriptionChangeController' => 'applications/maniphest/controller/descriptionchange', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail', 'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit', 'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist', 'ManiphestTaskListView' => 'applications/maniphest/view/tasklist', 'ManiphestTaskOwner' => 'applications/maniphest/constants/owner', 'ManiphestTaskPriority' => 'applications/maniphest/constants/priority', 'ManiphestTaskProject' => 'applications/maniphest/storage/taskproject', 'ManiphestTaskQuery' => 'applications/maniphest/query', 'ManiphestTaskStatus' => 'applications/maniphest/constants/status', 'ManiphestTaskSummaryView' => 'applications/maniphest/view/tasksummary', 'ManiphestTransaction' => 'applications/maniphest/storage/transaction', 'ManiphestTransactionDetailView' => 'applications/maniphest/view/transactiondetail', 'ManiphestTransactionEditor' => 'applications/maniphest/editor/transaction', 'ManiphestTransactionListView' => 'applications/maniphest/view/transactionlist', 'ManiphestTransactionPreviewController' => 'applications/maniphest/controller/transactionpreview', 'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave', 'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype', + 'ManiphestView' => 'applications/maniphest/view/base', 'Phabricator404Controller' => 'applications/base/controller/404', 'PhabricatorAuthController' => 'applications/auth/controller/base', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/api', 'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/token', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console', 'PhabricatorConduitController' => 'applications/conduit/controller/base', 'PhabricatorConduitDAO' => 'applications/conduit/storage/base', 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorConduitTokenController' => 'applications/conduit/controller/token', 'PhabricatorController' => 'applications/base/controller/base', 'PhabricatorCountdownController' => 'applications/countdown/controller/base', 'PhabricatorCountdownDAO' => 'applications/countdown/storage/base', 'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/delete', 'PhabricatorCountdownEditController' => 'applications/countdown/controller/edit', 'PhabricatorCountdownListController' => 'applications/countdown/controller/list', 'PhabricatorCountdownViewController' => 'applications/countdown/controller/view', 'PhabricatorDaemon' => 'infrastructure/daemon/base', 'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/combined', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/console', 'PhabricatorDaemonControl' => 'infrastructure/daemon/control', 'PhabricatorDaemonController' => 'applications/daemon/controller/base', 'PhabricatorDaemonDAO' => 'infrastructure/daemon/storage/base', 'PhabricatorDaemonLog' => 'infrastructure/daemon/storage/log', 'PhabricatorDaemonLogEvent' => 'infrastructure/daemon/storage/event', 'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/daemonlogevents', 'PhabricatorDaemonLogListController' => 'applications/daemon/controller/loglist', 'PhabricatorDaemonLogListView' => 'applications/daemon/view/daemonloglist', 'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/logview', 'PhabricatorDaemonReference' => 'infrastructure/daemon/control/reference', 'PhabricatorDaemonTimelineConsoleController' => 'applications/daemon/controller/timeline', 'PhabricatorDaemonTimelineEventController' => 'applications/daemon/controller/timelineevent', 'PhabricatorDirectoryCategory' => 'applications/directory/storage/category', 'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete', 'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit', 'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist', 'PhabricatorDirectoryController' => 'applications/directory/controller/base', 'PhabricatorDirectoryDAO' => 'applications/directory/storage/base', 'PhabricatorDirectoryItem' => 'applications/directory/storage/item', 'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete', 'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit', 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorDisabledUserController' => 'applications/auth/controller/disabled', 'PhabricatorDraft' => 'applications/draft/storage/draft', 'PhabricatorDraftDAO' => 'applications/draft/storage/base', 'PhabricatorEditPreferencesController' => 'applications/preferences/controller/edit', 'PhabricatorEmailLoginController' => 'applications/auth/controller/email', 'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken', 'PhabricatorEnv' => 'infrastructure/env', 'PhabricatorFile' => 'applications/files/storage/file', 'PhabricatorFileController' => 'applications/files/controller/base', 'PhabricatorFileDAO' => 'applications/files/storage/base', 'PhabricatorFileDropUploadController' => 'applications/files/controller/dropupload', 'PhabricatorFileImageMacro' => 'applications/files/storage/imagemacro', 'PhabricatorFileListController' => 'applications/files/controller/list', 'PhabricatorFileMacroDeleteController' => 'applications/files/controller/macrodelete', 'PhabricatorFileMacroEditController' => 'applications/files/controller/macroedit', 'PhabricatorFileMacroListController' => 'applications/files/controller/macrolist', 'PhabricatorFileProxyController' => 'applications/files/controller/proxy', 'PhabricatorFileProxyImage' => 'applications/files/storage/proxyimage', 'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob', 'PhabricatorFileTransformController' => 'applications/files/controller/transform', 'PhabricatorFileURI' => 'applications/files/uri', 'PhabricatorFileUploadController' => 'applications/files/controller/upload', 'PhabricatorFileViewController' => 'applications/files/controller/view', 'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing', 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector', 'PhabricatorHelpController' => 'applications/help/controller/base', 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/keyboardshortcut', 'PhabricatorIRCBot' => 'infrastructure/daemon/irc/bot', 'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base', 'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message', 'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname', 'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol', 'PhabricatorImageTransformer' => 'applications/files/transform', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/javelin', 'PhabricatorLintEngine' => 'infrastructure/lint/engine', 'PhabricatorLiskDAO' => 'applications/base/storage/lisk', 'PhabricatorLoginController' => 'applications/auth/controller/login', 'PhabricatorLogoutController' => 'applications/auth/controller/logout', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base', 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite', 'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/sendgrid', 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/base', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/base', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base', 'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta', 'PhabricatorMetaMTAEmailBodyParser' => 'applications/metamta/parser', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'applications/metamta/parser/__tests__', 'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail', 'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/mail/__tests__', 'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist', 'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit', 'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists', 'PhabricatorMetaMTAReceiveController' => 'applications/metamta/controller/receive', 'PhabricatorMetaMTAReceivedListController' => 'applications/metamta/controller/receivedlist', 'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/receivedmail', 'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send', 'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/sendgridreceive', 'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view', 'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default', 'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics', 'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure', 'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth', 'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base', 'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook', 'PhabricatorOAuthProviderGithub' => 'applications/auth/oauth/provider/github', 'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base', 'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink', 'PhabricatorObjectHandle' => 'applications/phid/handle', 'PhabricatorObjectHandleData' => 'applications/phid/handle/data', 'PhabricatorObjectSelectorDialog' => 'view/control/objectselector', 'PhabricatorOwnersController' => 'applications/owners/controller/base', 'PhabricatorOwnersDAO' => 'applications/owners/storage/base', 'PhabricatorOwnersDeleteController' => 'applications/owners/controller/delete', 'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail', 'PhabricatorOwnersEditController' => 'applications/owners/controller/edit', 'PhabricatorOwnersListController' => 'applications/owners/controller/list', 'PhabricatorOwnersOwner' => 'applications/owners/storage/owner', 'PhabricatorOwnersPackage' => 'applications/owners/storage/package', 'PhabricatorOwnersPath' => 'applications/owners/storage/path', 'PhabricatorPHID' => 'applications/phid/storage/phid', 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate', 'PhabricatorPHIDConstants' => 'applications/phid/constants', 'PhabricatorPHIDController' => 'applications/phid/controller/base', 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', 'PhabricatorPHIDListController' => 'applications/phid/controller/list', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup', 'PhabricatorPaste' => 'applications/paste/storage/paste', 'PhabricatorPasteController' => 'applications/paste/controller/base', 'PhabricatorPasteCreateController' => 'applications/paste/controller/create', 'PhabricatorPasteDAO' => 'applications/paste/storage/base', 'PhabricatorPasteListController' => 'applications/paste/controller/list', 'PhabricatorPasteViewController' => 'applications/paste/controller/view', 'PhabricatorPeopleController' => 'applications/people/controller/base', 'PhabricatorPeopleEditController' => 'applications/people/controller/edit', 'PhabricatorPeopleListController' => 'applications/people/controller/list', 'PhabricatorPeopleLogsController' => 'applications/people/controller/logs', 'PhabricatorPeopleProfileController' => 'applications/people/controller/profile', 'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit', 'PhabricatorPreferencesController' => 'applications/preferences/controller/base', 'PhabricatorProfileView' => 'view/layout/profile', 'PhabricatorProject' => 'applications/project/storage/project', 'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation', 'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation', 'PhabricatorProjectController' => 'applications/project/controller/base', 'PhabricatorProjectCreateController' => 'applications/project/controller/create', 'PhabricatorProjectDAO' => 'applications/project/storage/base', 'PhabricatorProjectListController' => 'applications/project/controller/list', 'PhabricatorProjectProfile' => 'applications/project/storage/profile', 'PhabricatorProjectProfileController' => 'applications/project/controller/profile', 'PhabricatorProjectProfileEditController' => 'applications/project/controller/profileedit', 'PhabricatorProjectStatus' => 'applications/project/constants/status', 'PhabricatorProjectTransactionSearch' => 'applications/project/transactions/search', 'PhabricatorRedirectController' => 'applications/base/controller/redirect', 'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential', 'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion', 'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro', 'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest', 'PhabricatorRemarkupRuleMention' => 'infrastructure/markup/remarkup/markuprule/mention', 'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/remarkup/markuprule/objectname', 'PhabricatorRemarkupRulePaste' => 'infrastructure/markup/remarkup/markuprule/paste', 'PhabricatorRemarkupRuleProxyImage' => 'infrastructure/markup/remarkup/markuprule/proxyimage', 'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/remarkup/markuprule/youtube', 'PhabricatorRepository' => 'applications/repository/storage/repository', 'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/arcanistproject', 'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/arcansistprojectedit', 'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit', 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/base', 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/commitdata', 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base', 'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/herald', 'PhabricatorRepositoryCommitMessageDetailParser' => 'applications/repository/parser/base', 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/base', 'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/base', 'PhabricatorRepositoryCommitTaskDaemon' => 'applications/repository/daemon/committask', 'PhabricatorRepositoryController' => 'applications/repository/controller/base', 'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create', 'PhabricatorRepositoryDAO' => 'applications/repository/storage/base', 'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base', 'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'applications/repository/parser/default', 'PhabricatorRepositoryDeleteController' => 'applications/repository/controller/delete', 'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/git', 'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/git', 'PhabricatorRepositoryGitFetchDaemon' => 'applications/repository/daemon/gitfetch', 'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification', 'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive', 'PhabricatorRepositoryListController' => 'applications/repository/controller/list', 'PhabricatorRepositoryShortcut' => 'applications/repository/storage/shortcut', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/svn', 'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn', 'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype', 'PhabricatorSQLPatchList' => 'infrastructure/setup/sql', 'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument', 'PhabricatorSearchAttachController' => 'applications/search/controller/attach', 'PhabricatorSearchBaseController' => 'applications/search/controller/base', 'PhabricatorSearchCommitIndexer' => 'applications/search/index/indexer/repository', 'PhabricatorSearchController' => 'applications/search/controller/search', 'PhabricatorSearchDAO' => 'applications/search/storage/base', 'PhabricatorSearchDifferentialIndexer' => 'applications/search/index/indexer/differential', 'PhabricatorSearchDocument' => 'applications/search/storage/document/document', 'PhabricatorSearchDocumentField' => 'applications/search/storage/document/field', 'PhabricatorSearchDocumentIndexer' => 'applications/search/index/indexer/base', 'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/relationship', 'PhabricatorSearchExecutor' => 'applications/search/execute/base', 'PhabricatorSearchField' => 'applications/search/constants/field', 'PhabricatorSearchIndexController' => 'applications/search/controller/index', 'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest', 'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql', 'PhabricatorSearchQuery' => 'applications/search/storage/query', 'PhabricatorSearchRelationship' => 'applications/search/constants/relationship', 'PhabricatorSearchResultView' => 'applications/search/view/searchresult', 'PhabricatorSearchSelectController' => 'applications/search/controller/select', 'PhabricatorSearchUserIndexer' => 'applications/search/index/indexer/user', 'PhabricatorSetup' => 'infrastructure/setup', 'PhabricatorStandardPageView' => 'view/page/standard', 'PhabricatorStatusController' => 'applications/status/base', 'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/taskmaster', 'PhabricatorTestCase' => 'infrastructure/testing/testcase', 'PhabricatorTimelineCursor' => 'infrastructure/daemon/timeline/storage/cursor', 'PhabricatorTimelineDAO' => 'infrastructure/daemon/timeline/storage/base', 'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/event', 'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata', 'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator', 'PhabricatorTimer' => 'applications/countdown/storage/timer', 'PhabricatorTransformedFile' => 'applications/files/storage/transformed', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base', 'PhabricatorUIExample' => 'applications/uiexample/examples/base', 'PhabricatorUIExampleController' => 'applications/uiexample/controller/base', 'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/render', 'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/listfilter', 'PhabricatorUIPagerExample' => 'applications/uiexample/examples/pager', 'PhabricatorUser' => 'applications/people/storage/user', 'PhabricatorUserDAO' => 'applications/people/storage/base', 'PhabricatorUserLog' => 'applications/people/storage/log', 'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo', 'PhabricatorUserPreferences' => 'applications/people/storage/preferences', 'PhabricatorUserProfile' => 'applications/people/storage/profile', 'PhabricatorUserSettingsController' => 'applications/people/controller/settings', 'PhabricatorWorker' => 'infrastructure/daemon/workers/worker', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/base', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/task', 'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/taskdata', 'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/workertaskdetail', 'PhabricatorXHPASTViewController' => 'applications/xhpastview/controller/base', 'PhabricatorXHPASTViewDAO' => 'applications/xhpastview/storage/base', 'PhabricatorXHPASTViewFrameController' => 'applications/xhpastview/controller/viewframe', 'PhabricatorXHPASTViewFramesetController' => 'applications/xhpastview/controller/viewframeset', 'PhabricatorXHPASTViewInputController' => 'applications/xhpastview/controller/viewinput', 'PhabricatorXHPASTViewPanelController' => 'applications/xhpastview/controller/viewpanel', 'PhabricatorXHPASTViewParseTree' => 'applications/xhpastview/storage/parsetree', 'PhabricatorXHPASTViewRunController' => 'applications/xhpastview/controller/run', 'PhabricatorXHPASTViewStreamController' => 'applications/xhpastview/controller/viewstream', 'PhabricatorXHPASTViewTreeController' => 'applications/xhpastview/controller/viewtree', 'PhabricatorXHProfController' => 'applications/xhprof/controller/base', 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile', 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol', 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel', ), 'function' => array( '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api', 'celerity_register_resource_map' => 'infrastructure/celerity/map', 'javelin_render_tag' => 'infrastructure/javelin/markup', 'phabricator_date' => 'view/utils', 'phabricator_datetime' => 'view/utils', 'phabricator_format_relative_time' => 'view/utils', 'phabricator_format_timestamp' => 'view/utils', 'phabricator_format_units_generic' => 'view/utils', 'phabricator_render_form' => 'infrastructure/javelin/markup', 'phabricator_time' => 'view/utils', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', 'queryfx_one' => 'storage/queryfx', 'require_celerity_resource' => 'infrastructure/celerity/api', 'vqsprintf' => 'storage/qsprintf', 'vqueryfx' => 'storage/queryfx', 'vqueryfx_all' => 'storage/queryfx', 'xsprintf_query' => 'storage/qsprintf', ), 'requires_class' => array( 'Aphront304Response' => 'AphrontResponse', 'Aphront400Response' => 'AphrontResponse', 'Aphront404Response' => 'AphrontResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontAttachedFileView' => 'AphrontView', 'AphrontCrumbsView' => 'AphrontView', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontFilePreviewView' => 'AphrontView', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormDividerControl' => 'AphrontFormControl', 'AphrontFormDragAndDropUploadControl' => 'AphrontFormControl', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormLayoutView' => 'AphrontView', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormToggleButtonsControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontHeadsupActionListView' => 'AphrontView', 'AphrontHeadsupActionView' => 'AphrontView', 'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontKeyboardShortcutsAvailableView' => 'AphrontView', 'AphrontListFilterView' => 'AphrontView', 'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontNullView' => 'AphrontView', 'AphrontPageView' => 'AphrontView', 'AphrontPagerView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontQueryAccessDeniedException' => 'AphrontQueryRecoverableException', 'AphrontQueryConnectionException' => 'AphrontQueryException', 'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException', 'AphrontQueryCountException' => 'AphrontQueryException', 'AphrontQueryDuplicateKeyException' => 'AphrontQueryException', 'AphrontQueryObjectMissingException' => 'AphrontQueryException', 'AphrontQueryParameterException' => 'AphrontQueryException', 'AphrontQueryRecoverableException' => 'AphrontQueryException', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontReloadResponse' => 'AphrontRedirectResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontSideNavView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontTokenizerTemplateView' => 'AphrontView', 'AphrontTypeaheadTemplateView' => 'AphrontView', 'AphrontWebpageResponse' => 'AphrontResponse', 'CelerityResourceController' => 'AphrontController', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_getcertificate_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod', 'ConduitAPI_daemon_launched_Method' => 'ConduitAPIMethod', 'ConduitAPI_daemon_log_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getrevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getrevisionfeedback_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_updatetaskrevisionassoc_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPIMethod', 'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPIMethod', 'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_download_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod', 'ConduitAPI_maniphest_info_Method' => 'ConduitAPIMethod', 'ConduitAPI_paste_info_Method' => 'ConduitAPIMethod', 'ConduitAPI_path_getowners_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_find_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_whoami_Method' => 'ConduitAPIMethod', 'DarkConsoleConfigPlugin' => 'DarkConsolePlugin', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => 'DifferentialDAO', 'DifferentialCommentMail' => 'DifferentialMail', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffCreateController' => 'DifferentialController', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialExceptionMail' => 'DifferentialMail', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialInlineComment' => 'DifferentialDAO', 'DifferentialInlineCommentEditController' => 'DifferentialController', 'DifferentialInlineCommentPreviewController' => 'DifferentialController', 'DifferentialInlineCommentView' => 'AphrontView', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', 'DifferentialPrimaryPaneView' => 'AphrontView', 'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler', 'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialRevision' => 'DifferentialDAO', 'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSubscribeController' => 'DifferentialController', 'DifferentialViewTime' => 'DifferentialDAO', 'DiffusionBranchTableView' => 'DiffusionView', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseFileController' => 'DiffusionController', 'DiffusionBrowseTableView' => 'DiffusionView', 'DiffusionChangeController' => 'DiffusionController', 'DiffusionCommitChangeTableView' => 'DiffusionView', 'DiffusionCommitController' => 'DiffusionController', 'DiffusionController' => 'PhabricatorController', 'DiffusionDiffController' => 'DiffusionController', 'DiffusionGitBranchQuery' => 'DiffusionBranchQuery', 'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionGitDiffQuery' => 'DiffusionDiffQuery', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionGitLastModifiedQuery' => 'DiffusionLastModifiedQuery', 'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionHistoryController' => 'DiffusionController', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHomeController' => 'DiffusionController', 'DiffusionLastModifiedController' => 'DiffusionController', 'DiffusionPathCompleteController' => 'DiffusionController', 'DiffusionPathValidateController' => 'DiffusionController', 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery', 'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionSvnLastModifiedQuery' => 'DiffusionLastModifiedQuery', 'DiffusionSvnRequest' => 'DiffusionRequest', 'DiffusionView' => 'AphrontView', 'HeraldAction' => 'HeraldDAO', 'HeraldApplyTranscript' => 'HeraldDAO', 'HeraldCommitAdapter' => 'HeraldObjectAdapter', 'HeraldCondition' => 'HeraldDAO', 'HeraldController' => 'PhabricatorController', 'HeraldDAO' => 'PhabricatorLiskDAO', 'HeraldDeleteController' => 'HeraldController', 'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter', 'HeraldDryRunAdapter' => 'HeraldObjectAdapter', 'HeraldHomeController' => 'HeraldController', 'HeraldNewController' => 'HeraldController', 'HeraldRule' => 'HeraldDAO', 'HeraldRuleController' => 'HeraldController', 'HeraldTestConsoleController' => 'HeraldController', 'HeraldTranscript' => 'HeraldDAO', 'HeraldTranscriptController' => 'HeraldController', 'HeraldTranscriptListController' => 'HeraldController', 'LiskIsolationTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestDAO' => 'LiskDAO', 'ManiphestController' => 'PhabricatorController', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler', 'ManiphestTask' => 'ManiphestDAO', 'ManiphestTaskDescriptionChangeController' => 'ManiphestController', 'ManiphestTaskDetailController' => 'ManiphestController', 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskListController' => 'ManiphestController', - 'ManiphestTaskListView' => 'AphrontView', + 'ManiphestTaskListView' => 'ManiphestView', + 'ManiphestTaskOwner' => 'ManiphestConstants', + 'ManiphestTaskPriority' => 'ManiphestConstants', 'ManiphestTaskProject' => 'ManiphestDAO', - 'ManiphestTaskSummaryView' => 'AphrontView', + 'ManiphestTaskStatus' => 'ManiphestConstants', + 'ManiphestTaskSummaryView' => 'ManiphestView', 'ManiphestTransaction' => 'ManiphestDAO', - 'ManiphestTransactionDetailView' => 'AphrontView', - 'ManiphestTransactionListView' => 'AphrontView', + 'ManiphestTransactionDetailView' => 'ManiphestView', + 'ManiphestTransactionListView' => 'ManiphestView', 'ManiphestTransactionPreviewController' => 'ManiphestController', 'ManiphestTransactionSaveController' => 'ManiphestController', + 'ManiphestTransactionType' => 'ManiphestConstants', + 'ManiphestView' => 'AphrontView', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitTokenController' => 'PhabricatorConduitController', 'PhabricatorController' => 'AphrontController', 'PhabricatorCountdownController' => 'PhabricatorController', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonCombinedLogController' => 'PhabricatorDaemonController', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonController' => 'PhabricatorController', 'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO', 'PhabricatorDaemonLog' => 'PhabricatorDaemonDAO', 'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO', 'PhabricatorDaemonLogEventsView' => 'AphrontView', 'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController', 'PhabricatorDaemonLogListView' => 'AphrontView', 'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController', 'PhabricatorDaemonTimelineConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonTimelineEventController' => 'PhabricatorDaemonController', 'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorDisabledUserController' => 'PhabricatorAuthController', 'PhabricatorDraft' => 'PhabricatorDraftDAO', 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 'PhabricatorEditPreferencesController' => 'PhabricatorPreferencesController', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailTokenController' => 'PhabricatorAuthController', 'PhabricatorFile' => 'PhabricatorFileDAO', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', 'PhabricatorFileImageMacro' => 'PhabricatorFileDAO', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileMacroDeleteController' => 'PhabricatorFileController', 'PhabricatorFileMacroEditController' => 'PhabricatorFileController', 'PhabricatorFileMacroListController' => 'PhabricatorFileController', 'PhabricatorFileProxyController' => 'PhabricatorFileController', 'PhabricatorFileProxyImage' => 'PhabricatorFileDAO', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileViewController' => 'PhabricatorFileController', 'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker', 'PhabricatorHelpController' => 'PhabricatorController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', 'PhabricatorIRCBot' => 'PhabricatorDaemon', 'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorLintEngine' => 'PhutilLintEngine', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLoginController' => 'PhabricatorAuthController', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTADaemon' => 'PhabricatorDaemon', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAReceivedListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController', 'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController', 'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController', 'PhabricatorOAuthFailureView' => 'AphrontView', 'PhabricatorOAuthLoginController' => 'PhabricatorAuthController', 'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthProviderGithub' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController', 'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorOwnersController' => 'PhabricatorController', 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController', 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 'PhabricatorOwnersEditController' => 'PhabricatorOwnersController', 'PhabricatorOwnersListController' => 'PhabricatorOwnersController', 'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO', 'PhabricatorPHID' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', 'PhabricatorPaste' => 'PhabricatorPasteDAO', 'PhabricatorPasteController' => 'PhabricatorController', 'PhabricatorPasteCreateController' => 'PhabricatorPasteController', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteListController' => 'PhabricatorPasteController', 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController', 'PhabricatorPreferencesController' => 'PhabricatorController', 'PhabricatorProfileView' => 'AphrontView', 'PhabricatorProject' => 'PhabricatorProjectDAO', 'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO', 'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController', 'PhabricatorProjectController' => 'PhabricatorController', 'PhabricatorProjectCreateController' => 'PhabricatorProjectController', 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectProfile' => 'PhabricatorProjectDAO', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController', 'PhabricatorRedirectController' => 'PhabricatorController', 'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName', 'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleManiphest' => 'PhabricatorRemarkupRuleObjectName', 'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRulePaste' => 'PhabricatorRemarkupRuleObjectName', 'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', 'PhabricatorRepository' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon', 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon', 'PhabricatorRepositoryController' => 'PhabricatorController', 'PhabricatorRepositoryCreateController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon', 'PhabricatorRepositoryDefaultCommitMessageDetailParser' => 'PhabricatorRepositoryCommitMessageDetailParser', 'PhabricatorRepositoryDeleteController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryEditController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryGitFetchDaemon' => 'PhabricatorRepositoryDaemon', 'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryShortcut' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorSearchAttachController' => 'PhabricatorSearchController', 'PhabricatorSearchBaseController' => 'PhabricatorController', 'PhabricatorSearchCommitIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchDAO' => 'PhabricatorLiskDAO', 'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorSearchDocument' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO', 'PhabricatorSearchIndexController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor', 'PhabricatorSearchQuery' => 'PhabricatorSearchDAO', 'PhabricatorSearchResultView' => 'AphrontView', 'PhabricatorSearchSelectController' => 'PhabricatorSearchController', 'PhabricatorSearchUserIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorStatusController' => 'PhabricatorController', 'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon', 'PhabricatorTestCase' => 'ArcanistPhutilTestCase', 'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO', 'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO', 'PhabricatorTimer' => 'PhabricatorCountdownDAO', 'PhabricatorTransformedFile' => 'PhabricatorFileDAO', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorUIExampleController' => 'PhabricatorController', 'PhabricatorUIExampleRenderController' => 'PhabricatorUIExampleController', 'PhabricatorUIListFilterExample' => 'PhabricatorUIExample', 'PhabricatorUIPagerExample' => 'PhabricatorUIExample', 'PhabricatorUser' => 'PhabricatorUserDAO', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 'PhabricatorUserLog' => 'PhabricatorUserDAO', 'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO', 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserSettingsController' => 'PhabricatorPeopleController', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController', 'PhabricatorXHPASTViewController' => 'PhabricatorController', 'PhabricatorXHPASTViewDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewParseTree' => 'PhabricatorXHPASTViewDAO', 'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHProfController' => 'PhabricatorController', 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', 'PhabricatorXHProfProfileSymbolView' => 'AphrontView', 'PhabricatorXHProfProfileTopLevelView' => 'AphrontView', ), 'requires_interface' => array( ), )); diff --git a/src/applications/maniphest/constants/owner/ManiphestTaskOwner.php b/src/applications/maniphest/constants/base/ManiphestConstants.php similarity index 87% copy from src/applications/maniphest/constants/owner/ManiphestTaskOwner.php copy to src/applications/maniphest/constants/base/ManiphestConstants.php index 6a6ff59b4c..7e12478621 100644 --- a/src/applications/maniphest/constants/owner/ManiphestTaskOwner.php +++ b/src/applications/maniphest/constants/base/ManiphestConstants.php @@ -1,23 +1,24 @@ 'Unbreak Now!', self::PRIORITY_TRIAGE => 'Needs Triage', self::PRIORITY_HIGH => 'High', self::PRIORITY_NORMAL => 'Normal', self::PRIORITY_LOW => 'Low', self::PRIORITY_WISH => 'Wishlist', ); } public static function getTaskPriorityName($priority) { return idx(self::getTaskPriorityMap(), $priority, '???'); } } diff --git a/src/applications/maniphest/constants/priority/__init__.php b/src/applications/maniphest/constants/priority/__init__.php index 791832bac4..9f3dcb8c8f 100644 --- a/src/applications/maniphest/constants/priority/__init__.php +++ b/src/applications/maniphest/constants/priority/__init__.php @@ -1,12 +1,14 @@ 'Open', self::STATUS_CLOSED_RESOLVED => 'Resolved', self::STATUS_CLOSED_WONTFIX => 'Wontfix', self::STATUS_CLOSED_INVALID => 'Invalid', self::STATUS_CLOSED_DUPLICATE => 'Duplicate', self::STATUS_CLOSED_SPITE => 'Spite', ); } public static function getTaskStatusFullName($status) { $map = array( self::STATUS_OPEN => 'Open', self::STATUS_CLOSED_RESOLVED => 'Closed, Resolved', self::STATUS_CLOSED_WONTFIX => 'Closed, Wontfix', self::STATUS_CLOSED_INVALID => 'Closed, Invalid', self::STATUS_CLOSED_DUPLICATE => 'Closed, Duplicate', self::STATUS_CLOSED_SPITE => 'Closed out of Spite', ); return idx($map, $status, '???'); } } diff --git a/src/applications/maniphest/constants/status/__init__.php b/src/applications/maniphest/constants/status/__init__.php index 0b7212d908..bd5a95071e 100644 --- a/src/applications/maniphest/constants/status/__init__.php +++ b/src/applications/maniphest/constants/status/__init__.php @@ -1,12 +1,14 @@ 'Comment', self::TYPE_STATUS => 'Close Task', self::TYPE_OWNER => 'Reassign / Claim', self::TYPE_CCS => 'Add CCs', self::TYPE_PRIORITY => 'Change Priority', self::TYPE_ATTACH => 'Upload File', self::TYPE_PROJECTS => 'Associate Projects', ); } } diff --git a/src/applications/maniphest/constants/transactiontype/__init__.php b/src/applications/maniphest/constants/transactiontype/__init__.php index 2d1616cc7d..7beed47c4c 100644 --- a/src/applications/maniphest/constants/transactiontype/__init__.php +++ b/src/applications/maniphest/constants/transactiontype/__init__.php @@ -1,10 +1,12 @@ buildStandardPageView(); $page->setApplicationName('Maniphest'); $page->setBaseURI('/maniphest/'); $page->setTitle(idx($data, 'title')); $page->setGlyph("\xE2\x9A\x93"); $page->appendChild($view); $response = new AphrontWebpageResponse(); return $response->setContent($page->render()); } } diff --git a/src/applications/maniphest/controller/descriptionchange/ManiphestTaskDescriptionChangeController.php b/src/applications/maniphest/controller/descriptionchange/ManiphestTaskDescriptionChangeController.php index 4c8f5004a1..d1b73fdba6 100644 --- a/src/applications/maniphest/controller/descriptionchange/ManiphestTaskDescriptionChangeController.php +++ b/src/applications/maniphest/controller/descriptionchange/ManiphestTaskDescriptionChangeController.php @@ -1,61 +1,64 @@ transactionID = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $transaction = id(new ManiphestTransaction())->load($this->transactionID); if (!$transaction) { return new Aphront404Response(); } $transactions = array($transaction); $phids = array(); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = $phid; } } $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $factory = new DifferentialMarkupEngineFactory(); $engine = $factory->newDifferentialCommentMarkupEngine(); $view = new ManiphestTransactionDetailView(); $view->setTransactionGroup($transactions); $view->setHandles($handles); $view->setUser($user); $view->setMarkupEngine($engine); $view->setRenderSummaryOnly(true); $view->setRenderFullSummary(true); return id(new AphrontAjaxResponse())->setContent($view->render()); } } diff --git a/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php index d1c432e82e..99eb7408f9 100644 --- a/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/taskdetail/ManiphestTaskDetailController.php @@ -1,392 +1,395 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $transactions = id(new ManiphestTransaction())->loadAllWhere( 'taskID = %d ORDER BY id ASC', $task->getID()); $phids = array(); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $phids = array_keys($phids); $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $factory = new DifferentialMarkupEngineFactory(); $engine = $factory->newDifferentialCommentMarkupEngine(); $dict = array(); $dict['Status'] = ''. ManiphestTaskStatus::getTaskStatusFullName($task->getStatus()). ''; $dict['Assigned To'] = $task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : 'None'; $dict['Priority'] = ManiphestTaskPriority::getTaskPriorityName( $task->getPriority()); $cc = $task->getCCPHIDs(); if ($cc) { $cc_links = array(); foreach ($cc as $phid) { $cc_links[] = $handles[$phid]->renderLink(); } $dict['CC'] = implode(', ', $cc_links); } else { $dict['CC'] = 'None'; } $dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink(); $projects = $task->getProjectPHIDs(); if ($projects) { $project_links = array(); foreach ($projects as $phid) { $project_links[] = $handles[$phid]->renderLink(); } $dict['Projects'] = implode(', ', $project_links); } else { $dict['Projects'] = 'None'; } if (idx($attached, PhabricatorPHIDConstants::PHID_TYPE_DREV)) { $revs = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_DREV); $rev_links = array(); foreach ($revs as $rev => $info) { $rev_links[] = $handles[$rev]->renderLink(); } $rev_links = implode('
', $rev_links); $dict['Revisions'] = $rev_links; } if (idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE)) { $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE); $file_phids = array_keys($file_infos); if ($file_phids) { $files = id(new PhabricatorFile())->loadAllWhere( 'phid IN (%Ls)', $file_phids); $views = array(); foreach ($files as $file) { $view = new AphrontFilePreviewView(); $view->setFile($file); $views[] = $view->render(); } $dict['Files'] = implode('', $views); } } $dict['Description'] = '
'. '
'. $engine->markupText($task->getDescription()). '
'. '
'; require_celerity_resource('mainphest-task-detail-css'); $table = array(); foreach ($dict as $key => $value) { $table[] = ''. ''.phutil_escape_html($key).':'. ''.$value.''. ''; } $table = ''. implode("\n", $table). '
'; $actions = array(); $action = new AphrontHeadsupActionView(); $action->setName('Edit Task'); $action->setURI('/maniphest/task/edit/'.$task->getID().'/'); $action->setClass('action-edit'); $actions[] = $action; require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('javelin-behavior-phabricator-object-selector'); $action = new AphrontHeadsupActionView(); $action->setName('Merge Duplicates'); $action->setURI('/search/attach/'.$task->getPHID().'/TASK/merge/'); $action->setWorkflow(true); $action->setClass('action-merge'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Differential Revisions'); $action->setURI('/search/attach/'.$task->getPHID().'/DREV/'); $action->setWorkflow(true); $action->setClass('action-attach'); $actions[] = $action; $action_list = new AphrontHeadsupActionListView(); $action_list->setActions($actions); $panel = '
'. $action_list->render(). '
'. '

'. ''. phutil_escape_html('T'.$task->getID()). ''. ' '. phutil_escape_html($task->getTitle()). '

'. $table. '
'. '
'; $transaction_types = ManiphestTransactionType::getTransactionTypeMap(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) { $resolution_types = array_select_keys( $resolution_types, array( ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, ManiphestTaskStatus::STATUS_CLOSED_INVALID, ManiphestTaskStatus::STATUS_CLOSED_SPITE, )); } else { $resolution_types = array( ManiphestTaskStatus::STATUS_OPEN => 'Reopened', ); $transaction_types[ManiphestTransactionType::TYPE_STATUS] = 'Reopen Task'; unset($transaction_types[ManiphestTransactionType::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransactionType::TYPE_OWNER]); } $default_claim = array( $user->getPHID() => $user->getUsername().' ('.$user->getRealName().')', ); $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $panel_id = celerity_generate_unique_node_id(); $comment_form = new AphrontFormView(); $comment_form ->setUser($user) ->setAction('/maniphest/transaction/save/') ->setEncType('multipart/form-data') ->addHiddenInput('taskID', $task->getID()) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Action') ->setName('action') ->setOptions($transaction_types) ->setID('transaction-action')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Resolution') ->setName('resolution') ->setControlID('resolution') ->setControlStyle('display: none') ->setOptions($resolution_types)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Assign To') ->setName('assign_to') ->setControlID('assign_to') ->setControlStyle('display: none') ->setID('assign-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('CCs') ->setName('ccs') ->setControlID('ccs') ->setControlStyle('display: none') ->setID('cc-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Priority') ->setName('priority') ->setOptions($priority_map) ->setControlID('priority') ->setControlStyle('display: none') ->setValue($task->getPriority())) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Projects') ->setName('projects') ->setControlID('projects') ->setControlStyle('display: none') ->setID('projects-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormFileControl()) ->setLabel('File') ->setName('file') ->setControlID('file') ->setControlStyle('display: none')) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Comments') ->setName('comments') ->setValue($draft_text) ->setID('transaction-comments')) ->appendChild( id(new AphrontFormDragAndDropUploadControl()) ->setLabel('Attached Files') ->setName('files') ->setDragAndDropTarget($panel_id) ->setActivatedClass('aphront-panel-view-drag-and-drop')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Avast!')); $control_map = array( ManiphestTransactionType::TYPE_STATUS => 'resolution', ManiphestTransactionType::TYPE_OWNER => 'assign_to', ManiphestTransactionType::TYPE_CCS => 'ccs', ManiphestTransactionType::TYPE_PRIORITY => 'priority', ManiphestTransactionType::TYPE_PROJECTS => 'projects', ManiphestTransactionType::TYPE_ATTACH => 'file', ); Javelin::initBehavior('maniphest-transaction-controls', array( 'select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => array( ManiphestTransactionType::TYPE_PROJECTS => array( 'id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', ), ManiphestTransactionType::TYPE_OWNER => array( 'id' => 'assign-tokenizer', 'src' => '/typeahead/common/users/', 'value' => $default_claim, 'limit' => 1, ), ManiphestTransactionType::TYPE_CCS => array( 'id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', ), ), )); Javelin::initBehavior('maniphest-transaction-preview', array( 'uri' => '/maniphest/transaction/preview/'.$task->getID().'/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, )); $comment_panel = new AphrontPanelView(); $comment_panel->appendChild($comment_form); $comment_panel->setID($panel_id); $comment_panel->addClass('aphront-panel-accent'); $comment_panel->setHeader('Weigh In'); $preview_panel = '
Loading preview...
'; $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setMarkupEngine($engine); return $this->buildStandardPageResponse( array( $panel, $transaction_view, $comment_panel, $preview_panel, ), array( 'title' => 'T'.$task->getID().' '.$task->getTitle(), )); } } diff --git a/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php b/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php index 47e474c453..9f5f278935 100644 --- a/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php @@ -1,310 +1,313 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $files = array(); if ($this->id) { $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } } else { $task = new ManiphestTask(); $task->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); $task->setAuthorPHID($user->getPHID()); // These allow task creation with defaults. if (!$request->isFormPost()) { $task->setTitle($request->getStr('title')); } $file_phids = $request->getArr('files', array()); if (!$file_phids) { // Allow a single 'file' key instead, mostly since Mac OS X urlencodes // square brackets in URLs when passed to 'open', so you can't 'open' // a URL like '?files[]=xyz' and have PHP interpret it correctly. $phid = $request->getStr('file'); if ($phid) { $file_phids = array($phid); } } if ($file_phids) { $files = id(new PhabricatorFile())->loadAllWhere( 'phid IN (%Ls)', $file_phids); } } $errors = array(); $e_title = true; if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); if ($task->getID()) { if ($new_title != $task->getTitle()) { $changes[ManiphestTransactionType::TYPE_TITLE] = $new_title; } if ($new_desc != $task->getDescription()) { $changes[ManiphestTransactionType::TYPE_DESCRIPTION] = $new_desc; } } else { $task->setTitle($new_title); $task->setDescription($new_desc); $changes[ManiphestTransactionType::TYPE_STATUS] = ManiphestTaskStatus::STATUS_OPEN; } $owner_tokenizer = $request->getArr('assigned_to'); $owner_phid = reset($owner_tokenizer); if (!strlen($new_title)) { $e_title = 'Required'; $errors[] = 'Title is required.'; } if (!$errors) { if ($request->getInt('priority') != $task->getPriority()) { $changes[ManiphestTransactionType::TYPE_PRIORITY] = $request->getInt('priority'); } if ($owner_phid != $task->getOwnerPHID()) { $changes[ManiphestTransactionType::TYPE_OWNER] = $owner_phid; } if ($request->getArr('cc') != $task->getCCPHIDs()) { $changes[ManiphestTransactionType::TYPE_CCS] = $request->getArr('cc'); } $new_proj_arr = $request->getArr('projects'); $new_proj_arr = array_values($new_proj_arr); sort($new_proj_arr); $cur_proj_arr = $task->getProjectPHIDs(); $cur_proj_arr = array_values($cur_proj_arr); sort($cur_proj_arr); if ($new_proj_arr != $cur_proj_arr) { $changes[ManiphestTransactionType::TYPE_PROJECTS] = $new_proj_arr; } if ($files) { $file_map = mpull($files, 'getPHID'); $file_map = array_fill_keys($file_map, true); $changes[ManiphestTransactionType::TYPE_ATTACH] = array( PhabricatorPHIDConstants::PHID_TYPE_FILE => $file_map, ); } $template = new ManiphestTransaction(); $template->setAuthorPHID($user->getPHID()); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); $transaction->setNewValue($value); $transactions[] = $transaction; } if ($transactions) { $editor = new ManiphestTransactionEditor(); $editor->applyTransactions($task, $transactions); } return id(new AphrontRedirectResponse()) ->setURI('/T'.$task->getID()); } } else { if (!$task->getID()) { $task->setCCPHIDs(array( $user->getPHID(), )); } } $phids = array_merge( array($task->getOwnerPHID()), $task->getCCPHIDs(), $task->getProjectPHIDs()); $phids = array_filter($phids); $phids = array_unique($phids); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles($phids); $tvalues = mpull($handles, 'getFullName', 'getPHID'); $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); $error_view->setTitle('Form Errors'); } $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($task->getOwnerPHID()) { $assigned_value = array( $task->getOwnerPHID() => $handles[$task->getOwnerPHID()]->getFullName(), ); } else { $assigned_value = array(); } if ($task->getCCPHIDs()) { $cc_value = array_select_keys($tvalues, $task->getCCPHIDs()); } else { $cc_value = array(); } if ($task->getProjectPHIDs()) { $projects_value = array_select_keys($tvalues, $task->getProjectPHIDs()); } else { $projects_value = array(); } if ($task->getID()) { $cancel_uri = '/T'.$task->getID(); $button_name = 'Save Task'; $header_name = 'Edit Task'; } else { $cancel_uri = '/maniphest/'; $button_name = 'Create Task'; $header_name = 'Create New Task'; } $project_tokenizer_id = celerity_generate_unique_node_id(); $form = new AphrontFormView(); $form ->setUser($user) ->setAction($request->getRequestURI()->getPath()) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Title') ->setName('title') ->setError($e_title) ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) ->setValue($task->getTitle())) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Assigned To') ->setName('assigned_to') ->setValue($assigned_value) ->setDatasource('/typeahead/common/users/') ->setLimit(1)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('CC') ->setName('cc') ->setValue($cc_value) ->setDatasource('/typeahead/common/mailable/')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Priority') ->setName('priority') ->setOptions($priority_map) ->setValue($task->getPriority())) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Projects') ->setName('projects') ->setValue($projects_value) ->setID($project_tokenizer_id) ->setCaption( javelin_render_tag( 'a', array( 'href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create', ), 'Create New Project')) ->setDatasource('/typeahead/common/projects/')); require_celerity_resource('aphront-error-view-css'); Javelin::initBehavior('maniphest-project-create', array( 'tokenizerID' => $project_tokenizer_id, )); if ($files) { $file_display = array(); foreach ($files as $file) { $file_display[] = phutil_escape_html($file->getName()); } $file_display = implode('
', $file_display); $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel('Files') ->setValue($file_display)); foreach ($files as $ii => $file) { $form->addHiddenInput('files['.$ii.']', $file->getPHID()); } } $form ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Description') ->setName('description') ->setValue($task->getDescription())) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($button_name)); $panel = new AphrontPanelView(); $panel->setWidth(AphrontPanelView::WIDTH_FULL); $panel->setHeader($header_name); $panel->appendChild($form); return $this->buildStandardPageResponse( array( $error_view, $panel, ), array( 'title' => 'Create Task', )); } } diff --git a/src/applications/maniphest/controller/tasklist/ManiphestTaskListController.php b/src/applications/maniphest/controller/tasklist/ManiphestTaskListController.php index 0c0dee7d1f..b57e8c55e2 100644 --- a/src/applications/maniphest/controller/tasklist/ManiphestTaskListController.php +++ b/src/applications/maniphest/controller/tasklist/ManiphestTaskListController.php @@ -1,474 +1,477 @@ view = idx($data, 'view'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $uri = $request->getRequestURI(); if ($request->isFormPost()) { // Redirect to GET so URIs can be copy/pasted. $user_phids = $request->getArr('set_users'); $proj_phids = $request->getArr('set_projects'); $user_phids = implode(',', $user_phids); $proj_phids = implode(',', $proj_phids); $user_phids = nonempty($user_phids, null); $proj_phids = nonempty($proj_phids, null); $uri = $request->getRequestURI() ->alter('users', $user_phids) ->alter('projects', $proj_phids); return id(new AphrontRedirectResponse())->setURI($uri); } $views = array( 'User Tasks', 'action' => 'Assigned', 'created' => 'Created', 'triage' => 'Need Triage', '
', 'All Tasks', 'alltriage' => 'Need Triage', 'all' => 'All Tasks', ); if (empty($views[$this->view])) { $this->view = 'action'; } $has_filter = array( 'action' => true, 'created' => true, 'triage' => true, ); $nav = new AphrontSideNavView(); foreach ($views as $view => $name) { if (is_integer($view)) { $nav->addNavItem( phutil_render_tag( 'span', array(), $name)); } else { $uri->setPath('/maniphest/view/'.$view.'/'); $nav->addNavItem( phutil_render_tag( 'a', array( 'href' => $uri->alter('page', null), 'class' => ($this->view == $view) ? 'aphront-side-nav-selected' : null, ), phutil_escape_html($name))); } } list($status_map, $status_links) = $this->renderStatusLinks(); list($grouping, $group_links) = $this->renderGroupLinks(); list($order, $order_links) = $this->renderOrderLinks(); $user_phids = $request->getStr('users'); if (strlen($user_phids)) { $user_phids = explode(',', $user_phids); } else { $user_phids = array($user->getPHID()); } $project_phids = $request->getStr('projects'); if (strlen($project_phids)) { $project_phids = explode(',', $project_phids); } else { $project_phids = array(); } $page = $request->getInt('page'); $page_size = self::DEFAULT_PAGE_SIZE; list($tasks, $handles, $total_count) = $this->loadTasks( $user_phids, $project_phids, array( 'status' => $status_map, 'group' => $grouping, 'order' => $order, 'offset' => $page, 'limit' => $page_size, )); $form = id(new AphrontFormView()) ->setUser($user) ->setAction($request->getRequestURI()); if (isset($has_filter[$this->view])) { $tokens = array(); foreach ($user_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } $form->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/searchowner/') ->setName('set_users') ->setLabel('Users') ->setValue($tokens)); } $tokens = array(); foreach ($project_phids as $phid) { $tokens[$phid] = $handles[$phid]->getFullName(); } $form->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/projects/') ->setName('set_projects') ->setLabel('Projects') ->setValue($tokens)); $form ->appendChild( id(new AphrontFormToggleButtonsControl()) ->setLabel('Status') ->setValue($status_links)) ->appendChild( id(new AphrontFormToggleButtonsControl()) ->setLabel('Group') ->setValue($group_links)) ->appendChild( id(new AphrontFormToggleButtonsControl()) ->setLabel('Order') ->setValue($order_links)); $form->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Filter Tasks')); $filter = new AphrontListFilterView(); $filter->addButton( phutil_render_tag( 'a', array( 'href' => '/maniphest/task/create/', 'class' => 'green button', ), 'Create New Task')); $filter->appendChild($form); $nav->appendChild($filter); $have_tasks = false; foreach ($tasks as $group => $list) { if (count($list)) { $have_tasks = true; break; } } require_celerity_resource('maniphest-task-summary-css'); if (!$have_tasks) { $nav->appendChild( '

'. 'No matching tasks.'. '

'); } else { $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'page'); $pager->setPageSize($page_size); $pager->setOffset($page); $pager->setCount($total_count); $cur = ($pager->getOffset() + 1); $max = min($pager->getOffset() + $page_size, $total_count); $tot = $total_count; $cur = number_format($cur); $max = number_format($max); $tot = number_format($tot); $nav->appendChild( '
'. "Displaying tasks {$cur} - {$max} of {$tot}.". '
'); foreach ($tasks as $group => $list) { $task_list = new ManiphestTaskListView(); $task_list->setUser($user); $task_list->setTasks($list); $task_list->setHandles($handles); $count = number_format(count($list)); $nav->appendChild( '

'. phutil_escape_html($group).' ('.$count.')'. '

'); $nav->appendChild($task_list); } $nav->appendChild($pager); } return $this->buildStandardPageResponse( $nav, array( 'title' => 'Task List', )); } private function loadTasks( array $user_phids, array $project_phids, array $dict) { $query = new ManiphestTaskQuery(); $query->withProjects($project_phids); $status = $dict['status']; if (!empty($status['open']) && !empty($status['closed'])) { $query->withStatus(ManiphestTaskQuery::STATUS_ANY); } else if (!empty($status['open'])) { $query->withStatus(ManiphestTaskQuery::STATUS_OPEN); } else { $query->withStatus(ManiphestTaskQuery::STATUS_CLOSED); } switch ($this->view) { case 'action': $query->withOwners($user_phids); break; case 'created': $query->withAuthors($user_phids); break; case 'triage': $query->withOwners($user_phids); $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); break; case 'alltriage': $query->withPriority(ManiphestTaskPriority::PRIORITY_TRIAGE); break; case 'all': break; } $order_map = array( 'priority' => ManiphestTaskQuery::ORDER_PRIORITY, 'created' => ManiphestTaskQuery::ORDER_CREATED, ); $query->setOrderBy( idx( $order_map, $dict['order'], ManiphestTaskQuery::ORDER_MODIFIED)); $group_map = array( 'priority' => ManiphestTaskQuery::GROUP_PRIORITY, 'owner' => ManiphestTaskQuery::GROUP_OWNER, 'status' => ManiphestTaskQuery::GROUP_STATUS, ); $query->setGroupBy( idx( $group_map, $dict['group'], ManiphestTaskQuery::GROUP_NONE)); $query->setCalculateRows(true); $query->setLimit($dict['limit']); $query->setOffset($dict['offset']); $data = $query->execute(); $total_row_count = $query->getRowCount(); $handle_phids = mpull($data, 'getOwnerPHID'); $handle_phids = array_merge($handle_phids, $project_phids, $user_phids); $handles = id(new PhabricatorObjectHandleData($handle_phids)) ->loadHandles(); switch ($dict['group']) { case 'priority': $data = mgroup($data, 'getPriority'); krsort($data); // If we have invalid priorities, they'll all map to "???". Merge // arrays to prevent them from overwriting each other. $out = array(); foreach ($data as $pri => $tasks) { $out[ManiphestTaskPriority::getTaskPriorityName($pri)][] = $tasks; } foreach ($out as $pri => $tasks) { $out[$pri] = array_mergev($tasks); } $data = $out; break; case 'status': $data = mgroup($data, 'getStatus'); ksort($data); $out = array(); foreach ($data as $status => $tasks) { $out[ManiphestTaskStatus::getTaskStatusFullName($status)] = $tasks; } $data = $out; break; case 'owner': $data = mgroup($data, 'getOwnerPHID'); $out = array(); foreach ($data as $phid => $tasks) { if ($phid) { $out[$handles[$phid]->getFullName()] = $tasks; } else { $out['Unassigned'] = $tasks; } } if (isset($out['Unassigned'])) { // If any tasks are unassigned, move them to the front of the list. $data = array('Unassigned' => $out['Unassigned']) + $out; } else { $data = $out; } ksort($data); break; default: $data = array( 'Tasks' => $data, ); break; } return array($data, $handles, $total_row_count); } public function renderStatusLinks() { $request = $this->getRequest(); $statuses = array( 'o' => array('open' => true), 'c' => array('closed' => true), 'oc' => array('open' => true, 'closed' => true), ); $status = $request->getStr('s'); if (empty($statuses[$status])) { $status = 'o'; } $button_names = array( 'Open' => 'o', 'Closed' => 'c', 'All' => 'oc', ); $status_links = $this->renderFilterLinks($button_names, $status, 's'); return array($statuses[$status], $status_links); } public function renderOrderLinks() { $request = $this->getRequest(); $order = $request->getStr('o'); $orders = array( 'u' => 'updated', 'c' => 'created', 'p' => 'priority', ); if (empty($orders[$order])) { $order = 'p'; } $order_by = $orders[$order]; $order_names = array( 'Priority' => 'p', 'Updated' => 'u', 'Created' => 'c', ); $order_links = $this->renderFilterLinks($order_names, $order, 'o'); return array($order_by, $order_links); } public function renderGroupLinks() { $request = $this->getRequest(); $group = $request->getStr('g'); $groups = array( 'n' => 'none', 'p' => 'priority', 's' => 'status', 'o' => 'owner', ); if (empty($groups[$group])) { $group = 'p'; } $group_by = $groups[$group]; $group_names = array( 'Priority' => 'p', 'Owner' => 'o', 'Status' => 's', 'None' => 'n', ); $group_links = $this->renderFilterLinks($group_names, $group, 'g'); return array($group_by, $group_links); } private function renderFilterLinks($filter_map, $selected, $uri_param) { $request = $this->getRequest(); $uri = $request->getRequestURI(); $links = array(); foreach ($filter_map as $name => $value) { if ($value == $selected) { $more = ' toggle-selected toggle-fixed'; $href = null; } else { $more = null; $href = $uri->alter($uri_param, $value); } $links[] = phutil_render_tag( 'a', array( 'class' => 'toggle'.$more, 'href' => $href, ), $name); } return implode("\n", $links); } } diff --git a/src/applications/maniphest/controller/transactionpreview/ManiphestTransactionPreviewController.php b/src/applications/maniphest/controller/transactionpreview/ManiphestTransactionPreviewController.php index 6d63ef761e..a830d5f0cc 100644 --- a/src/applications/maniphest/controller/transactionpreview/ManiphestTransactionPreviewController.php +++ b/src/applications/maniphest/controller/transactionpreview/ManiphestTransactionPreviewController.php @@ -1,94 +1,97 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $comments = $request->getStr('comments'); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if (!$draft) { $draft = new PhabricatorDraft(); $draft->setAuthorPHID($user->getPHID()); $draft->setDraftKey($task->getPHID()); } $draft->setDraft($comments); $draft->save(); $phids = array($user->getPHID()); $action = $request->getStr('action'); $transaction = new ManiphestTransaction(); $transaction->setAuthorPHID($user->getPHID()); $transaction->setComments($comments); $transaction->setTransactionType($action); $value = $request->getStr('value'); switch ($action) { case ManiphestTransactionType::TYPE_OWNER: if (!$value) { $value = $user->getPHID(); } $phids[] = $value; break; case ManiphestTransactionType::TYPE_PRIORITY: $transaction->setOldValue($task->getPriority()); break; } $transaction->setNewValue($value); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $transactions = array(); $transactions[] = $transaction; $factory = new DifferentialMarkupEngineFactory(); $engine = $factory->newDifferentialCommentMarkupEngine(); $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setMarkupEngine($engine); $transaction_view->setPreview(true); return id(new AphrontAjaxResponse()) ->setContent($transaction_view->render()); } } diff --git a/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php b/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php index 9284a8d027..99e95f6088 100644 --- a/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php +++ b/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php @@ -1,196 +1,199 @@ getRequest(); $user = $request->getUser(); $task = id(new ManiphestTask())->load($request->getStr('taskID')); if (!$task) { return new Aphront404Response(); } $transactions = array(); $action = $request->getStr('action'); // If we have drag-and-dropped files, attach them first in a separate // transaction. These can come in on any transaction type, which is why we // handle them separately. $files = array(); // Look for drag-and-drop uploads first. $file_phids = $request->getArr('files'); if ($file_phids) { $files = id(new PhabricatorFile())->loadAllWhere( 'phid in (%Ls)', $file_phids); } // This means "attach a file" even though we store other types of data // as 'attached'. if ($action == ManiphestTransactionType::TYPE_ATTACH) { if (!empty($_FILES['file'])) { $err = idx($_FILES['file'], 'error'); if ($err != UPLOAD_ERR_NO_FILE) { $file = PhabricatorFile::newFromPHPUpload($_FILES['file']); $files[] = $file; } } } // If we had explicit or drag-and-drop files, create a transaction // for those before we deal with whatever else might have happened. $file_transaction = null; if ($files) { $files = mpull($files, 'getPHID', 'getPHID'); $new = $task->getAttached(); foreach ($files as $phid) { if (empty($new[PhabricatorPHIDConstants::PHID_TYPE_FILE])) { $new[PhabricatorPHIDConstants::PHID_TYPE_FILE] = array(); } $new[PhabricatorPHIDConstants::PHID_TYPE_FILE][$phid] = array(); } $transaction = new ManiphestTransaction(); $transaction ->setAuthorPHID($user->getPHID()) ->setTransactionType(ManiphestTransactionType::TYPE_ATTACH); $transaction->setNewValue($new); $transactions[] = $transaction; $file_transaction = $transaction; } $transaction = new ManiphestTransaction(); $transaction ->setAuthorPHID($user->getPHID()) ->setComments($request->getStr('comments')) ->setTransactionType($action); switch ($action) { case ManiphestTransactionType::TYPE_STATUS: $transaction->setNewValue($request->getStr('resolution')); break; case ManiphestTransactionType::TYPE_OWNER: $assign_to = $request->getArr('assign_to'); $assign_to = reset($assign_to); $transaction->setNewValue($assign_to); break; case ManiphestTransactionType::TYPE_PROJECTS: $projects = $request->getArr('projects'); $projects = array_merge($projects, $task->getProjectPHIDs()); $projects = array_filter($projects); $projects = array_unique($projects); $transaction->setNewValue($projects); break; case ManiphestTransactionType::TYPE_CCS: $ccs = $request->getArr('ccs'); $ccs = array_merge($ccs, $task->getCCPHIDs()); $ccs = array_filter($ccs); $ccs = array_unique($ccs); $transaction->setNewValue($ccs); break; case ManiphestTransactionType::TYPE_PRIORITY: $transaction->setNewValue($request->getInt('priority')); break; case ManiphestTransactionType::TYPE_NONE: case ManiphestTransactionType::TYPE_ATTACH: // If we have a file transaction, just get rid of this secondary // transaction and put the comments on it instead. if ($file_transaction) { $file_transaction->setComments($transaction->getComments()); $transaction = null; } break; default: throw new Exception('unknown action'); } if ($transaction) { $transactions[] = $transaction; } switch ($action) { case ManiphestTransactionType::TYPE_OWNER: if ($task->getOwnerPHID() == $transaction->getNewValue()) { // If this is actually no-op, don't generate the side effect. break; } // When a task is reassigned, move the previous owner to CC. $old = $task->getCCPHIDs(); $new = array_merge( $old, array($task->getOwnerPHID())); $new = array_unique(array_filter($new)); if ($old != $new) { $cc = new ManiphestTransaction(); $cc->setAuthorPHID($user->getPHID()); $cc->setTransactionType(ManiphestTransactionType::TYPE_CCS); $cc->setNewValue($new); $transactions[] = $cc; } break; case ManiphestTransactionType::TYPE_STATUS: if (!$task->getOwnerPHID() && $request->getStr('resolution') != ManiphestTaskStatus::STATUS_OPEN) { // Closing an unassigned task. Assign the user for this task $assign = new ManiphestTransaction(); $assign->setAuthorPHID($user->getPHID()); $assign->setTransactionType(ManiphestTransactionType::TYPE_OWNER); $assign->setNewValue($user->getPHID()); $transactions[] = $assign; } break; case ManiphestTransactionType::TYPE_NONE: $ccs = $task->getCCPHIDs(); $owner = $task->getOwnerPHID(); if ($user->getPHID() !== $owner && !in_array($user->getPHID(), $ccs)) { // Current user, who is commenting, is not the owner or in ccs. // Add him to ccs $ccs[] = $user->getPHID(); $cc = new ManiphestTransaction(); $cc->setAuthorPHID($user->getPHID()); $cc->setTransactionType(ManiphestTransactionType::TYPE_CCS); $cc->setNewValue($ccs); $transactions[] = $cc; } default: break; } $editor = new ManiphestTransactionEditor(); $editor->applyTransactions($task, $transactions); $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft->delete(); } return id(new AphrontRedirectResponse()) ->setURI('/T'.$task->getID()); } } diff --git a/src/applications/maniphest/editor/transaction/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/transaction/ManiphestTransactionEditor.php index 37acc5d26d..825d4936d5 100644 --- a/src/applications/maniphest/editor/transaction/ManiphestTransactionEditor.php +++ b/src/applications/maniphest/editor/transaction/ManiphestTransactionEditor.php @@ -1,244 +1,247 @@ parentMessageID = $parent_message_id; return $this; } public function applyTransactions($task, array $transactions) { $email_cc = $task->getCCPHIDs(); $email_to = array(); $email_to[] = $task->getOwnerPHID(); foreach ($transactions as $key => $transaction) { $type = $transaction->getTransactionType(); $new = $transaction->getNewValue(); $email_to[] = $transaction->getAuthorPHID(); switch ($type) { case ManiphestTransactionType::TYPE_NONE: $old = null; break; case ManiphestTransactionType::TYPE_STATUS: $old = $task->getStatus(); break; case ManiphestTransactionType::TYPE_OWNER: $old = $task->getOwnerPHID(); break; case ManiphestTransactionType::TYPE_CCS: $old = $task->getCCPHIDs(); break; case ManiphestTransactionType::TYPE_PRIORITY: $old = $task->getPriority(); break; case ManiphestTransactionType::TYPE_ATTACH: $old = $task->getAttached(); break; case ManiphestTransactionType::TYPE_TITLE: $old = $task->getTitle(); break; case ManiphestTransactionType::TYPE_DESCRIPTION: $old = $task->getDescription(); break; case ManiphestTransactionType::TYPE_PROJECTS: $old = $task->getProjectPHIDs(); break; default: throw new Exception('Unknown action type.'); } if (($old !== null) && ($old == $new)) { if (count($transactions) > 1 && !$transaction->hasComments()) { // If we have at least one other transaction and this one isn't // doing anything and doesn't have any comments, just throw it // away. unset($transactions[$key]); continue; } else { $transaction->setOldValue(null); $transaction->setNewValue(null); $transaction->setTransactionType(ManiphestTransactionType::TYPE_NONE); } } else { switch ($type) { case ManiphestTransactionType::TYPE_NONE: break; case ManiphestTransactionType::TYPE_STATUS: $task->setStatus($new); break; case ManiphestTransactionType::TYPE_OWNER: if ($new) { $handles = id(new PhabricatorObjectHandleData(array($new))) ->loadHandles(); $task->setOwnerOrdering($handles[$new]->getName()); } else { $task->setOwnerOrdering(null); } $task->setOwnerPHID($new); break; case ManiphestTransactionType::TYPE_CCS: $task->setCCPHIDs($new); break; case ManiphestTransactionType::TYPE_PRIORITY: $task->setPriority($new); break; case ManiphestTransactionType::TYPE_ATTACH: $task->setAttached($new); break; case ManiphestTransactionType::TYPE_TITLE: $task->setTitle($new); break; case ManiphestTransactionType::TYPE_DESCRIPTION: $task->setDescription($new); break; case ManiphestTransactionType::TYPE_PROJECTS: $task->setProjectPHIDs($new); break; default: throw new Exception('Unknown action type.'); } $transaction->setOldValue($old); $transaction->setNewValue($new); } } $task->save(); foreach ($transactions as $transaction) { $transaction->setTaskID($task->getID()); $transaction->save(); } $email_to[] = $task->getOwnerPHID(); $email_cc = array_merge( $email_cc, $task->getCCPHIDs()); // TODO: Do this offline via timeline PhabricatorSearchManiphestIndexer::indexTask($task); $this->sendEmail($task, $transactions, $email_to, $email_cc); } protected function getSubjectPrefix() { return PhabricatorEnv::getEnvConfig('metamta.maniphest.subject-prefix'); } private function sendEmail($task, $transactions, $email_to, $email_cc) { $email_to = array_filter(array_unique($email_to)); $email_cc = array_filter(array_unique($email_cc)); $phids = array(); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($email_to as $phid) { $phids[$phid] = true; } foreach ($email_cc as $phid) { $phids[$phid] = true; } $phids = array_keys($phids); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $view = new ManiphestTransactionDetailView(); $view->setTransactionGroup($transactions); $view->setHandles($handles); list($action, $body) = $view->renderForEmail($with_date = false); $is_create = false; foreach ($transactions as $transaction) { $type = $transaction->getTransactionType(); if (($type == ManiphestTransactionType::TYPE_STATUS) && ($transaction->getOldValue() === null) && ($transaction->getNewValue() == ManiphestTaskStatus::STATUS_OPEN)) { $is_create = true; } } $task_uri = PhabricatorEnv::getURI('/T'.$task->getID()); $reply_handler = $this->buildReplyHandler($task); if ($is_create) { $body .= "\n\n". "TASK DESCRIPTION\n". " ".$task->getDescription(); } $body .= "\n\n". "TASK DETAIL\n". " ".$task_uri."\n"; $reply_instructions = $reply_handler->getReplyHandlerInstructions(); if ($reply_instructions) { $body .= "\n". "REPLY HANDLER ACTIONS\n". " ".$reply_instructions."\n"; } $thread_id = 'getPHID().'>'; $task_id = $task->getID(); $title = $task->getTitle(); $prefix = $this->getSubjectPrefix(); $subject = trim("{$prefix} [{$action}] T{$task_id}: {$title}"); $template = id(new PhabricatorMetaMTAMail()) ->setSubject($subject) ->setFrom($transaction->getAuthorPHID()) ->setParentMessageID($this->parentMessageID) ->addHeader('Thread-Topic', 'Maniphest Task '.$task->getID()) ->setThreadID($thread_id, $is_create) ->setRelatedPHID($task->getPHID()) ->setBody($body); $mails = $reply_handler->multiplexMail( $template, array_select_keys($handles, $email_to), array_select_keys($handles, $email_cc)); foreach ($mails as $mail) { $mail->saveAndSend(); } } public function buildReplyHandler(ManiphestTask $task) { $handler_class = PhabricatorEnv::getEnvConfig( 'metamta.maniphest.reply-handler'); $handler_object = newv($handler_class, array()); $handler_object->setMailReceiver($task); return $handler_object; } } diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index d7f874f1eb..1db3f02539 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -1,351 +1,353 @@ authorPHIDs = $authors; return $this; } public function withOwners(array $owners) { $this->includeUnowned = false; foreach ($owners as $k => $phid) { if ($phid == ManiphestTaskOwner::OWNER_UP_FOR_GRABS) { $this->includeUnowned = true; unset($owners[$k]); break; } } $this->ownerPHIDs = $owners; return $this; } public function withProjects(array $projects) { $this->projectPHIDs = $projects; return $this; } public function withStatus($status) { $this->status = $status; return $this; } public function withPriority($priority) { $this->priority = $priority; return $this; } public function setGroupBy($group) { $this->groupBy = $group; return $this; } public function setOrderBy($order) { $this->orderBy = $order; return $this; } public function setLimit($limit) { $this->limit = $limit; return $this; } public function setOffset($offset) { $this->offset = $offset; return $this; } public function setCalculateRows($calculate_rows) { $this->calculateRows = $calculate_rows; return $this; } public function getRowCount() { if ($this->rowCount === null) { throw new Exception( "You must execute a query with setCalculateRows() before you can ". "retrieve a row count."); } return $this->rowCount; } public function execute() { $task_dao = new ManiphestTask(); $conn = $task_dao->establishConnection('r'); if ($this->calculateRows) { $calc = 'SQL_CALC_FOUND_ROWS'; } else { $calc = ''; } $where = array(); $where[] = $this->buildStatusWhereClause($conn); $where[] = $this->buildPriorityWhereClause($conn); $where[] = $this->buildAuthorWhereClause($conn); $where[] = $this->buildOwnerWhereClause($conn); $where[] = $this->buildProjectWhereClause($conn); $where = array_filter($where); if ($where) { $where = 'WHERE ('.implode(') AND (', $where).')'; } else { $where = ''; } $join = array(); $join[] = $this->buildProjectJoinClause($conn); $join = array_filter($join); if ($join) { $join = implode(' ', $join); } else { $join = ''; } $having = ''; $count = ''; $group = ''; if (count($this->projectPHIDs) > 1) { // If we're searching for more than one project: // - We'll get multiple rows for tasks when they join the project table // multiple times. We use GROUP BY to make them distinct again. // - We want to treat the query as an intersection query, not a union // query. We sum the project count and require it be the same as the // number of projects we're searching for. $group = 'GROUP BY task.id'; $count = ', COUNT(1) projectCount'; $having = qsprintf( $conn, 'HAVING projectCount = %d', count($this->projectPHIDs)); } $order = $this->buildOrderClause($conn); $offset = (int)nonempty($this->offset, 0); $limit = (int)nonempty($this->limit, self::DEFAULT_PAGE_SIZE); $data = queryfx_all( $conn, 'SELECT %Q * %Q FROM %T task %Q %Q %Q %Q %Q LIMIT %d, %d', $calc, $count, $task_dao->getTableName(), $join, $where, $group, $having, $order, $offset, $limit); if ($this->calculateRows) { $count = queryfx_one( $conn, 'SELECT FOUND_ROWS() N'); $this->rowCount = $count['N']; } else { $this->rowCount = null; } return $task_dao->loadAllFromArray($data); } private function buildStatusWhereClause($conn) { switch ($this->status) { case self::STATUS_ANY: return null; case self::STATUS_OPEN: return 'status = 0'; case self::STATUS_CLOSED: return 'status > 0'; default: throw new Exception("Unknown status query '{$this->status}'!"); } } private function buildPriorityWhereClause($conn) { if ($this->priority === null) { return null; } return qsprintf( $conn, 'priority = %d', $this->priority); } private function buildAuthorWhereClause($conn) { if (!$this->authorPHIDs) { return null; } return qsprintf( $conn, 'authorPHID in (%Ls)', $this->authorPHIDs); } private function buildOwnerWhereClause($conn) { if (!$this->ownerPHIDs) { if ($this->includeUnowned === null) { return null; } else if ($this->includeUnowned) { return qsprintf( $conn, 'ownerPHID IS NULL'); } else { return qsprintf( $conn, 'ownerPHID IS NOT NULL'); } } if ($this->includeUnowned) { return qsprintf( $conn, 'ownerPHID IN (%Ls) OR ownerPHID IS NULL', $this->ownerPHIDs); } else { return qsprintf( $conn, 'ownerPHID IN (%Ls)', $this->ownerPHIDs); } } private function buildProjectWhereClause($conn) { if (!$this->projectPHIDs) { return null; } return qsprintf( $conn, 'project.projectPHID IN (%Ls)', $this->projectPHIDs); } private function buildProjectJoinClause($conn) { if (!$this->projectPHIDs) { return null; } $project_dao = new ManiphestTaskProject(); return qsprintf( $conn, 'JOIN %T project ON project.taskPHID = task.phid', $project_dao->getTableName()); } private function buildOrderClause($conn) { $order = array(); switch ($this->groupBy) { case self::GROUP_NONE: break; case self::GROUP_PRIORITY: $order[] = 'priority'; break; case self::GROUP_OWNER: $order[] = 'ownerOrdering'; break; case self::GROUP_STATUS: $order[] = 'status'; break; default: throw new Exception("Unknown group query '{$this->groupBy}'!"); } switch ($this->orderBy) { case self::ORDER_PRIORITY: $order[] = 'priority'; $order[] = 'dateModified'; break; case self::ORDER_CREATED: $order[] = 'id'; break; case self::ORDER_MODIFIED: $order[] = 'dateModified'; break; default: throw new Exception("Unknown order query '{$this->orderBy}'!"); } $order = array_unique($order); if (empty($order)) { return null; } foreach ($order as $k => $column) { switch ($column) { case 'ownerOrdering': $order[$k] = "task.{$column} ASC"; break; default: $order[$k] = "task.{$column} DESC"; break; } } return 'ORDER BY '.implode(', ', $order); } } diff --git a/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php b/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php index c3f8cfe1c9..0e0297c197 100644 --- a/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php +++ b/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php @@ -1,125 +1,128 @@ getDefaultPrivateReplyHandlerEmailAddress($handle, 'T'); } public function getPublicReplyHandlerEmailAddress() { return $this->getDefaultPublicReplyHandlerEmailAddress('T'); } public function getReplyHandlerDomain() { return PhabricatorEnv::getEnvConfig( 'metamta.maniphest.reply-handler-domain'); } public function getReplyHandlerInstructions() { if ($this->supportsReplies()) { return "Reply to comment or attach files, or !close, !claim, or ". "!unsubscribe."; } else { return null; } } public function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { $task = $this->getMailReceiver(); $user = $this->getActor(); $body = $mail->getCleanTextBody(); $body = trim($body); $lines = explode("\n", trim($body)); $first_line = head($lines); $command = null; $matches = null; if (preg_match('/^!(\w+)/', $first_line, $matches)) { $lines = array_slice($lines, 1); $body = implode("\n", $lines); $body = trim($body); $command = $matches[1]; } $xactions = array(); $files = $mail->getAttachments(); if ($files) { $file_xaction = new ManiphestTransaction(); $file_xaction->setAuthorPHID($user->getPHID()); $file_xaction->setTransactionType(ManiphestTransactionType::TYPE_ATTACH); $phid_type = PhabricatorPHIDConstants::PHID_TYPE_FILE; $new = $task->getAttached(); foreach ($files as $file_phid) { $new[$phid_type][$file_phid] = array(); } $file_xaction->setNewValue($new); $xactions[] = $file_xaction; } $ttype = ManiphestTransactionType::TYPE_NONE; $new_value = null; switch ($command) { case 'close': $ttype = ManiphestTransactionType::TYPE_STATUS; $new_value = ManiphestTaskStatus::STATUS_CLOSED_RESOLVED; break; case 'claim': $ttype = ManiphestTransactionType::TYPE_OWNER; $new_value = $user->getPHID(); break; case 'unsubscribe': $ttype = ManiphestTransactionType::TYPE_CCS; $ccs = $task->getCCPHIDs(); foreach ($ccs as $k => $phid) { if ($phid == $user->getPHID()) { unset($ccs[$k]); } } $new_value = array_values($ccs); break; } $xaction = new ManiphestTransaction(); $xaction->setAuthorPHID($user->getPHID()); $xaction->setTransactionType($ttype); $xaction->setNewValue($new_value); $xaction->setComments($body); $xactions[] = $xaction; $editor = new ManiphestTransactionEditor(); $editor->setParentMessageID($mail->getMessageID()); $editor->applyTransactions($task, $xactions); } } diff --git a/src/applications/maniphest/storage/base/ManiphestDAO.php b/src/applications/maniphest/storage/base/ManiphestDAO.php index 632fa9a0a7..c7df0c59b0 100644 --- a/src/applications/maniphest/storage/base/ManiphestDAO.php +++ b/src/applications/maniphest/storage/base/ManiphestDAO.php @@ -1,25 +1,28 @@ true, self::CONFIG_SERIALIZATION => array( 'ccPHIDs' => self::SERIALIZATION_JSON, 'attached' => self::SERIALIZATION_JSON, 'projectPHIDs' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function getAttachedPHIDs($type) { return array_keys(idx($this->attached, $type, array())); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_TASK); } public function getCCPHIDs() { return nonempty($this->ccPHIDs, array()); } public function setProjectPHIDs(array $phids) { $this->projectPHIDs = $phids; $this->projectsNeedUpdate = true; return $this; } public function save() { if (!$this->mailKey) { $this->mailKey = sha1(Filesystem::readRandomBytes(20)); } $result = parent::save(); if ($this->projectsNeedUpdate) { // If we've changed the project PHIDs for this task, update the link // table. ManiphestTaskProject::updateTaskProjects($this); $this->projectsNeedUpdate = false; } return $result; } } diff --git a/src/applications/maniphest/storage/transaction/ManiphestTransaction.php b/src/applications/maniphest/storage/transaction/ManiphestTransaction.php index ba7e5bf2ec..153e46f375 100644 --- a/src/applications/maniphest/storage/transaction/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/transaction/ManiphestTransaction.php @@ -1,105 +1,108 @@ array( 'oldValue' => self::SERIALIZATION_JSON, 'newValue' => self::SERIALIZATION_JSON, 'metadata' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function extractPHIDs() { $phids = array(); switch ($this->getTransactionType()) { case ManiphestTransactionType::TYPE_CCS: case ManiphestTransactionType::TYPE_PROJECTS: foreach ($this->getOldValue() as $phid) { $phids[] = $phid; } foreach ($this->getNewValue() as $phid) { $phids[] = $phid; } break; case ManiphestTransactionType::TYPE_OWNER: $phids[] = $this->getOldValue(); $phids[] = $this->getNewValue(); break; case ManiphestTransactionType::TYPE_ATTACH: $old = $this->getOldValue(); $new = $this->getNewValue(); if (!is_array($old)) { $old = array(); } if (!is_array($new)) { $new = array(); } $val = array_merge(array_values($old), array_values($new)); foreach ($val as $stuff) { foreach ($stuff as $phid => $ignored) { $phids[] = $phid; } } break; } $phids[] = $this->getAuthorPHID(); return $phids; } public function canGroupWith($target) { if ($target->getAuthorPHID() != $this->getAuthorPHID()) { return false; } if ($target->hasComments() && $this->hasComments()) { return false; } $ttime = $target->getDateCreated(); $stime = $this->getDateCreated(); if (abs($stime - $ttime) > 60) { return false; } if ($target->getTransactionType() == $this->getTransactionType()) { return false; } return true; } public function hasComments() { return (bool)strlen(trim($this->getComments())); } } diff --git a/src/applications/maniphest/constants/owner/ManiphestTaskOwner.php b/src/applications/maniphest/view/base/ManiphestView.php similarity index 87% copy from src/applications/maniphest/constants/owner/ManiphestTaskOwner.php copy to src/applications/maniphest/view/base/ManiphestView.php index 6a6ff59b4c..6a8144c9c0 100644 --- a/src/applications/maniphest/constants/owner/ManiphestTaskOwner.php +++ b/src/applications/maniphest/view/base/ManiphestView.php @@ -1,23 +1,24 @@ tasks = $tasks; return $this; } public function setHandles(array $handles) { $this->handles = $handles; return $this; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function render() { $views = array(); foreach ($this->tasks as $task) { $view = new ManiphestTaskSummaryView(); $view->setTask($task); $view->setUser($this->user); $view->setHandles($this->handles); $views[] = $view->render(); } return '
'. implode("\n", $views). '
'; } } diff --git a/src/applications/maniphest/view/tasklist/__init__.php b/src/applications/maniphest/view/tasklist/__init__.php index 5a35a49ef4..be0ea53278 100644 --- a/src/applications/maniphest/view/tasklist/__init__.php +++ b/src/applications/maniphest/view/tasklist/__init__.php @@ -1,13 +1,13 @@ task = $task; return $this; } public function setHandles(array $handles) { $this->handles = $handles; return $this; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function render() { if (!$this->user) { throw new Exception("Call setUser() before rendering!"); } $task = $this->task; $handles = $this->handles; require_celerity_resource('maniphest-task-summary-css'); $classes = array( ManiphestTaskPriority::PRIORITY_UNBREAK_NOW => 'pri-unbreak', ManiphestTaskPriority::PRIORITY_TRIAGE => 'pri-triage', ManiphestTaskPriority::PRIORITY_HIGH => 'pri-high', ManiphestTaskPriority::PRIORITY_NORMAL => 'pri-normal', ManiphestTaskPriority::PRIORITY_LOW => 'pri-low', ManiphestTaskPriority::PRIORITY_WISH => 'pri-wish', ); $pri_class = idx($classes, $task->getPriority()); return ''. ''. ''. ''. ''. ''. ''. ''. ''. '
'. 'T'.$task->getID(). ''. ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN ? 'Open' : 'Closed'). ''. ($task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : 'None'). ''. phutil_render_tag( 'a', array( 'href' => '/T'.$task->getID(), ), phutil_escape_html($task->getTitle())). ''. ManiphestTaskPriority::getTaskPriorityName($task->getPriority()). ''. phabricator_datetime($task->getDateModified(), $this->user). '
'; } } diff --git a/src/applications/maniphest/view/tasksummary/__init__.php b/src/applications/maniphest/view/tasksummary/__init__.php index 8ac09920ba..8e43605347 100644 --- a/src/applications/maniphest/view/tasksummary/__init__.php +++ b/src/applications/maniphest/view/tasksummary/__init__.php @@ -1,19 +1,19 @@ transactions = $transactions; return $this; } public function setHandles(array $handles) { $this->handles = $handles; return $this; } public function setMarkupEngine(PhutilMarkupEngine $engine) { $this->markupEngine = $engine; return $this; } public function setPreview($preview) { $this->preview = $preview; return $this; } public function setRenderSummaryOnly($render_summary_only) { $this->renderSummaryOnly = $render_summary_only; return $this; } public function getRenderSummaryOnly() { return $this->renderSummaryOnly; } public function setRenderFullSummary($render_full_summary) { $this->renderFullSummary = $render_full_summary; return $this; } public function getRenderFullSummary() { return $this->renderFullSummary; } public function setCommentNumber($comment_number) { $this->commentNumber = $comment_number; return $this; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function renderForEmail($with_date) { $this->forEmail = true; $transaction = reset($this->transactions); $author = $this->renderHandles(array($transaction->getAuthorPHID())); $action = null; $descs = array(); $comments = null; foreach ($this->transactions as $transaction) { list($verb, $desc, $classes) = $this->describeAction($transaction); if ($action === null) { $action = $verb; } $desc = $author.' '.$desc.'.'; if ($with_date) { // NOTE: This is going into a (potentially multi-recipient) email so // we can't use a single user's timezone preferences. Use the server's // instead, but make the timezone explicit. $datetime = date('M jS \a\t g:i A T', $transaction->getDateCreated()); $desc = "On {$datetime}, {$desc}"; } $descs[] = $desc; if ($transaction->hasComments()) { $comments = $transaction->getComments(); } } $descs = implode("\n", $descs); if ($comments) { $descs .= "\n".$comments; } foreach ($this->transactions as $transaction) { $supplemental = $this->renderSupplementalInfoForEmail($transaction); if ($supplemental) { $descs .= "\n\n".$supplemental; } } $this->forEmail = false; return array($action, $descs); } public function render() { if (!$this->user) { throw new Exception("Call setUser() before render()!"); } $handles = $this->handles; $transactions = $this->transactions; require_celerity_resource('maniphest-transaction-detail-css'); $comment_transaction = null; foreach ($this->transactions as $transaction) { if ($transaction->hasComments()) { $comment_transaction = $transaction; break; } } $any_transaction = reset($transactions); $author = $this->handles[$any_transaction->getAuthorPHID()]; $more_classes = array(); $descs = array(); foreach ($transactions as $transaction) { list($verb, $desc, $classes) = $this->describeAction($transaction); $more_classes = array_merge($more_classes, $classes); $full_summary = null; if ($this->getRenderFullSummary()) { $full_summary = $this->renderFullSummary($transaction); } $descs[] = javelin_render_tag( 'div', array( 'sigil' => 'maniphest-transaction-description', ), $author->renderLink().' '.$desc.'.'.$full_summary); } $descs = implode("\n", $descs); if ($this->getRenderSummaryOnly()) { return $descs; } $more_classes = implode(' ', $more_classes); if ($comment_transaction && $comment_transaction->hasComments()) { $comments = $comment_transaction->getCache(); if (!strlen($comments)) { $comments = $comment_transaction->getComments(); if (strlen($comments)) { $comments = $this->markupEngine->markupText($comments); $comment_transaction->setCache($comments); if ($comment_transaction->getID() && !$this->preview) { $comment_transaction->save(); } } } $comment_block = '
'. $comments. '
'; } else { $comment_block = null; } if ($this->preview) { $timestamp = 'COMMENT PREVIEW'; } else { $timestamp = phabricator_datetime( $transaction->getDateCreated(), $this->user); } $info = array(); $info[] = $timestamp; $comment_anchor = null; $num = $this->commentNumber; if ($num && !$this->preview) { Javelin::initBehavior('phabricator-watch-anchor'); $info[] = javelin_render_tag( 'a', array( 'name' => 'comment-'.$num, 'href' => '#comment-'.$num, ), 'Comment T'.$any_transaction->getTaskID().'#'.$num); $comment_anchor = 'anchor-comment-'.$num; } $info = implode(' · ', $info); return phutil_render_tag( 'div', array( 'class' => "maniphest-transaction-detail-container", 'style' => "background-image: url('".$author->getImageURI()."')", 'id' => $comment_anchor, ), '
'. '
'. '
'. $info. '
'. $descs. '
'. $comment_block. '
'); } private function renderSupplementalInfoForEmail($transaction) { $handles = $this->handles; $type = $transaction->getTransactionType(); $new = $transaction->getNewValue(); $old = $transaction->getOldValue(); switch ($type) { case ManiphestTransactionType::TYPE_DESCRIPTION: return "NEW DESCRIPTION\n ".trim($new)."\n\n". "PREVIOUS DESCRIPTION\n ".trim($old); case ManiphestTransactionType::TYPE_ATTACH: $old_raw = nonempty($old, array()); $new_raw = nonempty($new, array()); $attach_types = array( PhabricatorPHIDConstants::PHID_TYPE_DREV, PhabricatorPHIDConstants::PHID_TYPE_FILE, ); foreach ($attach_types as $type) { $old = array_keys(idx($old_raw, $type, array())); $new = array_keys(idx($new_raw, $type, array())); if ($old != $new) { break; } } $added = array_diff($new, $old); if (!$added) { break; } $links = array(); foreach (array_select_keys($handles, $added) as $handle) { $links[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI()); } $links = implode("\n", $links); switch ($type) { case PhabricatorPHIDConstants::PHID_TYPE_DREV: $title = 'ATTACHED REVISIONS'; break; case PhabricatorPHIDConstants::PHID_TYPE_FILE: $title = 'ATTACHED FILES'; break; } return $title."\n".$links; default: break; } return null; } private function describeAction($transaction) { $verb = null; $desc = null; $classes = array(); $handles = $this->handles; $type = $transaction->getTransactionType(); $author_phid = $transaction->getAuthorPHID(); $new = $transaction->getNewValue(); $old = $transaction->getOldValue(); switch ($type) { case ManiphestTransactionType::TYPE_TITLE: $verb = 'Retitled'; $desc = 'changed the title from '.$this->renderString($old). ' to '.$this->renderString($new); break; case ManiphestTransactionType::TYPE_DESCRIPTION: $verb = 'Edited'; if ($this->forEmail || $this->getRenderFullSummary()) { $desc = 'updated the task description'; } else { $desc = 'updated the task description; '. $this->renderExpandLink($transaction); } break; case ManiphestTransactionType::TYPE_NONE: $verb = 'Commented On'; $desc = 'added a comment'; break; case ManiphestTransactionType::TYPE_OWNER: if ($transaction->getAuthorPHID() == $new) { $verb = 'Claimed'; $desc = 'claimed this task'; $classes[] = 'claimed'; } else if (!$new) { $verb = 'Up For Grabs'; $desc = 'placed this task up for grabs'; $classes[] = 'upforgrab'; } else if (!$old) { $verb = 'Assigned'; $desc = 'assigned this task to '.$this->renderHandles(array($new)); $classes[] = 'assigned'; } else { $verb = 'Reassigned'; $desc = 'reassigned this task from '. $this->renderHandles(array($old)). ' to '. $this->renderHandles(array($new)); $classes[] = 'reassigned'; } break; case ManiphestTransactionType::TYPE_CCS: if ($this->preview) { $verb = 'Changed CC'; $desc = 'changed CCs..'; break; } $added = array_diff($new, $old); $removed = array_diff($old, $new); if ($added && !$removed) { $verb = 'Added CC'; if (count($added) == 1) { $desc = 'added '.$this->renderHandles($added).' to CC'; } else { $desc = 'added CCs: '.$this->renderHandles($added); } } else if ($removed && !$added) { $verb = 'Removed CC'; if (count($removed) == 1) { $desc = 'removed '.$this->renderHandles($removed).' from CC'; } else { $desc = 'removed CCs: '.$this->renderHandles($removed); } } else { $verb = 'Changed CC'; $desc = 'changed CCs, added: '.$this->renderHandles($added).'; '. 'removed: '.$this->renderHandles($removed); } break; case ManiphestTransactionType::TYPE_PROJECTS: if ($this->preview) { $verb = 'Changed Projects'; $desc = 'changed projects..'; break; } $added = array_diff($new, $old); $removed = array_diff($old, $new); if ($added && !$removed) { $verb = 'Added Project'; if (count($added) == 1) { $desc = 'added project '.$this->renderHandles($added); } else { $desc = 'added projects: '.$this->renderHandles($added); } } else if ($removed && !$added) { $verb = 'Removed Project'; if (count($removed) == 1) { $desc = 'removed project '.$this->renderHandles($removed); } else { $desc = 'removed projectss: '.$this->renderHandles($removed); } } else { $verb = 'Changed Projects'; $desc = 'changed projects, added: '.$this->renderHandles($added).'; '. 'removed: '.$this->renderHandles($removed); } break; case ManiphestTransactionType::TYPE_STATUS: if ($new == ManiphestTaskStatus::STATUS_OPEN) { if ($old) { $verb = 'Reopened'; $desc = 'reopened this task'; $classes[] = 'reopened'; } else { $verb = 'Created'; $desc = 'created this task'; $classes[] = 'created'; } } else if ($new == ManiphestTaskStatus::STATUS_CLOSED_SPITE) { $verb = 'Spited'; $desc = 'closed this task out of spite'; $classes[] = 'spited'; } else if ($new == ManiphestTaskStatus::STATUS_CLOSED_DUPLICATE) { $verb = 'Merged'; $desc = 'closed this task as a duplicate'; $classes[] = 'duplicate'; } else { $verb = 'Closed'; $full = idx(ManiphestTaskStatus::getTaskStatusMap(), $new, '???'); $desc = 'closed this task as "'.$full.'"'; $classes[] = 'closed'; } break; case ManiphestTransactionType::TYPE_PRIORITY: $old_name = ManiphestTaskPriority::getTaskPriorityName($old); $new_name = ManiphestTaskPriority::getTaskPriorityName($new); if ($old == ManiphestTaskPriority::PRIORITY_TRIAGE) { $verb = 'Triaged'; $desc = 'triaged this task as "'.$new_name.'" priority'; } else if ($old > $new) { $verb = 'Lowered Priority'; $desc = 'lowered the priority of this task from "'.$old_name.'" to '. '"'.$new_name.'"'; } else { $verb = 'Raised Priority'; $desc = 'raised the priority of this task from "'.$old_name.'" to '. '"'.$new_name.'"'; } if ($new == ManiphestTaskPriority::PRIORITY_UNBREAK_NOW) { $classes[] = 'unbreaknow'; } break; case ManiphestTransactionType::TYPE_ATTACH: if ($this->preview) { $verb = 'Changed Attached'; $desc = 'changed attachments..'; break; } $old_raw = nonempty($old, array()); $new_raw = nonempty($new, array()); foreach (array(PhabricatorPHIDConstants::PHID_TYPE_DREV, PhabricatorPHIDConstants::PHID_TYPE_FILE) as $type) { $old = array_keys(idx($old_raw, $type, array())); $new = array_keys(idx($new_raw, $type, array())); if ($old != $new) { break; } } $added = array_diff($new, $old); $removed = array_diff($old, $new); $add_desc = $this->renderHandles($added); $rem_desc = $this->renderHandles($removed); switch ($type) { case PhabricatorPHIDConstants::PHID_TYPE_DREV: $singular = 'Differential Revision'; $plural = 'Differential Revisions'; break; case PhabricatorPHIDConstants::PHID_TYPE_FILE: $singular = 'file'; $plural = 'files'; break; } if ($added && !$removed) { $verb = 'Attached'; if (count($added) == 1) { $desc = 'attached '.$singular.': '.$add_desc; } else { $desc = 'attached '.$plural.': '.$add_desc; } } else if ($removed && !$added) { $verb = 'Detached'; if (count($removed) == 1) { $desc = 'detached '.$singular.': '.$rem_desc; } else { $desc = 'detached '.$plural.': '.$rem_desc; } } else { $verb = 'Changed Attached'; $desc = 'changed attached '.$plural.', added: '.$add_desc. 'removed: '.$rem_desc; } break; default: return array($type, ' brazenly '.$type."'d", $classes); } return array($verb, $desc, $classes); } private function renderFullSummary($transaction) { switch ($transaction->getTransactionType()) { case ManiphestTransactionType::TYPE_DESCRIPTION: $engine = $this->markupEngine; $old = $transaction->getOldValue(); $new = $transaction->getNewValue(); $table = '
Previous Description New Description
'. $engine->markupText($old). '
'. $engine->markupText($new). '
'; return $table; } return null; } private function renderExpandLink($transaction) { $id = $transaction->getID(); Javelin::initBehavior('maniphest-transaction-expand'); return javelin_render_tag( 'a', array( 'href' => '/maniphest/task/descriptionchange/'.$id.'/', 'sigil' => 'maniphest-expand-transaction', 'mustcapture' => true, ), 'show details'); } private function renderHandles($phids) { $links = array(); foreach ($phids as $phid) { if ($this->forEmail) { $links[] = $this->handles[$phid]->getName(); } else { $links[] = $this->handles[$phid]->renderLink(); } } return implode(', ', $links); } private function renderString($string) { if ($this->forEmail) { return '"'.$string.'"'; } else { return '"'.phutil_escape_html($string).'"'; } } } diff --git a/src/applications/maniphest/view/transactiondetail/__init__.php b/src/applications/maniphest/view/transactiondetail/__init__.php index 600b258bce..bbb604b5bc 100644 --- a/src/applications/maniphest/view/transactiondetail/__init__.php +++ b/src/applications/maniphest/view/transactiondetail/__init__.php @@ -1,24 +1,24 @@ transactions = $transactions; return $this; } public function setHandles(array $handles) { $this->handles = $handles; return $this; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function setMarkupEngine(PhutilMarkupEngine $engine) { $this->markupEngine = $engine; return $this; } public function setPreview($preview) { $this->preview = $preview; return $this; } public function render() { $views = array(); $last = null; $group = array(); $groups = array(); foreach ($this->transactions as $transaction) { if ($last === null) { $last = $transaction; $group[] = $transaction; continue; } else if ($last->canGroupWith($transaction)) { $group[] = $transaction; if ($transaction->hasComments()) { $last = $transaction; } } else { $groups[] = $group; $last = $transaction; $group = array($transaction); } } if ($group) { $groups[] = $group; } $sequence = 1; foreach ($groups as $group) { $view = new ManiphestTransactionDetailView(); $view->setUser($this->user); $view->setTransactionGroup($group); $view->setHandles($this->handles); $view->setMarkupEngine($this->markupEngine); $view->setPreview($this->preview); $view->setCommentNumber($sequence++); $views[] = $view->render(); } return '
'. implode("\n", $views). '
'; } } diff --git a/src/applications/maniphest/view/transactionlist/__init__.php b/src/applications/maniphest/view/transactionlist/__init__.php index 8c06249c94..6611e4539a 100644 --- a/src/applications/maniphest/view/transactionlist/__init__.php +++ b/src/applications/maniphest/view/transactionlist/__init__.php @@ -1,13 +1,13 @@ ... This will highlight the block using a highlighter for that language, if one is available (in most cases, this means you need to configure Pygments): lang=html ... You can also use a "COUNTEREXAMPLE" header to show that a block of code is bad and shouldn't be copied: lang=demo COUNTEREXAMPLE function f() { global $$variable_variable; } This produces a block like this: COUNTEREXAMPLE function f() { global $$variable_variable; } = Linking URIs = URIs are automatically linked: http://phabricator.org/ If you have a URI with problematic characters in it, like "##http://comma.org/,##", you can surround it with angle brackets: This will force the parser to consume the whole URI: = Linking to Objects = You can link to Differential revisions, Diffusion commits and Maniphest tasks by mentioning the name of an object: D123 # Link to Differential revision D123 rX123 # Link to SVN commit 123 from the "X" repository rXaf3192cd5 # Link to Git commit "af3192cd5..." from the "X" repository. # You must specify at least 7 characters of the hash. T123 # Link to Maniphest task T123 You can also link directly to a comment in Maniphest and Differential: T123#4 # Link to comment #4 of T123 = Quoting Text = To quote text, preface it with an ">": > This is quoted text. This appears like this: > This is quoted text. = Embedding Media = If you set configuration flags, you can embed media directly in text: - **files.enable-proxy**: allows you to paste in image URLs and have them render inline. - **remarkup.enable-embedded-youtube**: allows you to paste in YouTube videos and have them render inline. These options are disabled by default because they have security and/or silliness implications, read their descriptions in ##default.conf.php## before enabling them. = Image Macros = You can upload image macros (Files -> Image Macros) which will replace text strings with the image you specify. For instance, you could upload an image of a dancing banana to create a macro named "peanutbutterjellytime", and then any time you type that string it will be replaced with the image of a dancing banana. = Mentioning Users = In Differential and Maniphest, you can mention another user by writing: @username When you submit your comment, this will add them as a CC on the revision or task if they aren't already CC'd. \ No newline at end of file