diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 20f86ef121..f8a68e53c2 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -7,6 +7,55 @@ */ celerity_register_resource_map(array( + '/rsrc/image/app/app_audit.png' => + array( + 'hash' => '5f5b4a7c48fe921532bef4c986328bdc', + 'uri' => '/res/5f5b4a7c/rsrc/image/app/app_audit.png', + 'disk' => '/rsrc/image/app/app_audit.png', + 'type' => 'png', + ), + '/rsrc/image/app/app_differential.png' => + array( + 'hash' => 'b2e42893b64791f8382f7f5a0350b44d', + 'uri' => '/res/b2e42893/rsrc/image/app/app_differential.png', + 'disk' => '/rsrc/image/app/app_differential.png', + 'type' => 'png', + ), + '/rsrc/image/app/app_diffusion.png' => + array( + 'hash' => 'e9e4b1c380e19a2908730ad397ae5eca', + 'uri' => '/res/e9e4b1c3/rsrc/image/app/app_diffusion.png', + 'disk' => '/rsrc/image/app/app_diffusion.png', + 'type' => 'png', + ), + '/rsrc/image/app/app_fact.png' => + array( + 'hash' => '8b4da94b07e2aad9f741beca9519df98', + 'uri' => '/res/8b4da94b/rsrc/image/app/app_fact.png', + 'disk' => '/rsrc/image/app/app_fact.png', + 'type' => 'png', + ), + '/rsrc/image/app/app_flags.png' => + array( + 'hash' => 'e75e1047a6bc2ff428161d2130526367', + 'uri' => '/res/e75e1047/rsrc/image/app/app_flags.png', + 'disk' => '/rsrc/image/app/app_flags.png', + 'type' => 'png', + ), + '/rsrc/image/app/app_maniphest.png' => + array( + 'hash' => '88b6a06029b1ce38d5e7a70c1d2ebd97', + 'uri' => '/res/88b6a060/rsrc/image/app/app_maniphest.png', + 'disk' => '/rsrc/image/app/app_maniphest.png', + 'type' => 'png', + ), + '/rsrc/image/app/app_phriction.png' => + array( + 'hash' => '68f2387363a26c15653a39bd847157f3', + 'uri' => '/res/68f23873/rsrc/image/app/app_phriction.png', + 'disk' => '/rsrc/image/app/app_phriction.png', + 'type' => 'png', + ), '/rsrc/image/apps.png' => array( 'hash' => 'f7cb4abeb73245fea4098a02fd784653', @@ -14,6 +63,34 @@ celerity_register_resource_map(array( 'disk' => '/rsrc/image/apps.png', 'type' => 'png', ), + '/rsrc/image/appstatus_empty.png' => + array( + 'hash' => '2f8102e0a0f5a0980d87d4ab4ba8c8fd', + 'uri' => '/res/2f8102e0/rsrc/image/appstatus_empty.png', + 'disk' => '/rsrc/image/appstatus_empty.png', + 'type' => 'png', + ), + '/rsrc/image/appstatus_info.png' => + array( + 'hash' => '407de6daf2edc4a8b68e2e369f4fc8cb', + 'uri' => '/res/407de6da/rsrc/image/appstatus_info.png', + 'disk' => '/rsrc/image/appstatus_info.png', + 'type' => 'png', + ), + '/rsrc/image/appstatus_needs.png' => + array( + 'hash' => '2c1e193bc786ca4fca0b851ed9cd3d92', + 'uri' => '/res/2c1e193b/rsrc/image/appstatus_needs.png', + 'disk' => '/rsrc/image/appstatus_needs.png', + 'type' => 'png', + ), + '/rsrc/image/appstatus_okay.png' => + array( + 'hash' => 'd00e683ee1c61d0ccced1200775cdbb5', + 'uri' => '/res/d00e683e/rsrc/image/appstatus_okay.png', + 'disk' => '/rsrc/image/appstatus_okay.png', + 'type' => 'png', + ), '/rsrc/image/avatar.png' => array( 'hash' => '1c5f255071537f05406adee86717ff27', @@ -2142,6 +2219,15 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/application/directory/phabricator-app-buttons.css', ), + 'phabricator-application-launch-view-css' => + array( + 'uri' => '/res/e157830a/rsrc/css/application/base/phabricator-application-launch-view.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/base/phabricator-application-launch-view.css', + ), 'phabricator-chatlog-css' => array( 'uri' => '/res/f6631adc/rsrc/css/application/chatlog/chatlog.css', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index adc3122af6..4b8013417d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -536,9 +536,18 @@ phutil_register_library_map(array( 'Phabricator404Controller' => 'applications/base/controller/Phabricator404Controller.php', 'PhabricatorAccessLog' => 'infrastructure/PhabricatorAccessLog.php', 'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php', + 'PhabricatorApplicationApplications' => 'applications/meta/application/PhabricatorApplicationApplications.php', + 'PhabricatorApplicationAudit' => 'applications/audit/application/PhabricatorApplicationAudit.php', 'PhabricatorApplicationDifferential' => 'applications/differential/application/PhabricatorApplicationDifferential.php', + 'PhabricatorApplicationDiffusion' => 'applications/diffusion/application/PhabricatorApplicationDiffusion.php', 'PhabricatorApplicationFact' => 'applications/fact/application/PhabricatorApplicationFact.php', + 'PhabricatorApplicationFlags' => 'applications/flag/application/PhabricatorApplicationFlags.php', + 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', 'PhabricatorApplicationManiphest' => 'applications/maniphest/application/PhabricatorApplicationManiphest.php', + 'PhabricatorApplicationPhriction' => 'applications/phriction/application/PhabricatorApplicationPhriction.php', + 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', + 'PhabricatorApplicationsController' => 'applications/meta/controller/PhabricatorApplicationsController.php', + 'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php', 'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php', 'PhabricatorAuditAddCommentController' => 'applications/audit/controller/PhabricatorAuditAddCommentController.php', 'PhabricatorAuditComment' => 'applications/audit/storage/PhabricatorAuditComment.php', @@ -1602,9 +1611,18 @@ phutil_register_library_map(array( 'PackageDeleteMail' => 'PackageMail', 'PackageModifyMail' => 'PackageMail', 'Phabricator404Controller' => 'PhabricatorController', + 'PhabricatorApplicationApplications' => 'PhabricatorApplication', + 'PhabricatorApplicationAudit' => 'PhabricatorApplication', 'PhabricatorApplicationDifferential' => 'PhabricatorApplication', + 'PhabricatorApplicationDiffusion' => 'PhabricatorApplication', 'PhabricatorApplicationFact' => 'PhabricatorApplication', + 'PhabricatorApplicationFlags' => 'PhabricatorApplication', + 'PhabricatorApplicationLaunchView' => 'AphrontView', 'PhabricatorApplicationManiphest' => 'PhabricatorApplication', + 'PhabricatorApplicationPhriction' => 'PhabricatorApplication', + 'PhabricatorApplicationStatusView' => 'AphrontView', + 'PhabricatorApplicationsController' => 'PhabricatorController', + 'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController', 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', 'PhabricatorAuditComment' => 'PhabricatorAuditDAO', 'PhabricatorAuditCommitListView' => 'AphrontView', diff --git a/src/applications/audit/application/PhabricatorApplicationAudit.php b/src/applications/audit/application/PhabricatorApplicationAudit.php new file mode 100644 index 0000000000..6bfd190515 --- /dev/null +++ b/src/applications/audit/application/PhabricatorApplicationAudit.php @@ -0,0 +1,73 @@ +withAuditorPHIDs($phids) + ->withStatus(PhabricatorAuditQuery::STATUS_OPEN) + ->withAwaitingUser($user) + ->execute(); + + $count = count($audits); + $type = $count + ? PhabricatorApplicationStatusView::TYPE_INFO + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Commit(s) Awaiting Audit', $count)) + ->setCount($count); + + + $commits = id(new PhabricatorAuditCommitQuery()) + ->withAuthorPHIDs($phids) + ->withStatus(PhabricatorAuditQuery::STATUS_OPEN) + ->execute(); + + $count = count($commits); + $type = $count + ? PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Problem Commit(s)', $count)) + ->setCount($count); + + return $status; + } + +} + diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 65f86362c0..93ce67fa21 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -57,6 +57,10 @@ abstract class PhabricatorApplication { return PhabricatorUser::getDefaultProfileImageURI(); } + public function shouldAppearInLaunchView() { + return true; + } + /* -( URI Routing )-------------------------------------------------------- */ @@ -74,6 +78,14 @@ abstract class PhabricatorApplication { } +/* -( Launch Integration )------------------------------------------------- */ + + + public function loadStatus(PhabricatorUser $user) { + return array(); + } + + /* -( Application Management )--------------------------------------------- */ diff --git a/src/applications/differential/application/PhabricatorApplicationDifferential.php b/src/applications/differential/application/PhabricatorApplicationDifferential.php index 1df206c4ad..7f22c36a7b 100644 --- a/src/applications/differential/application/PhabricatorApplicationDifferential.php +++ b/src/applications/differential/application/PhabricatorApplicationDifferential.php @@ -18,18 +18,54 @@ final class PhabricatorApplicationDifferential extends PhabricatorApplication { + public function getBaseURI() { + return '/differential/'; + } + + public function getShortDescription() { + return 'Review Code'; + } + + public function getIconURI() { + return celerity_get_resource_uri('/rsrc/image/app/app_differential.png'); + } + public function getFactObjectsForAnalysis() { return array( new DifferentialRevision(), ); } - public function getBaseURI() { - return '/differential/'; - } + public function loadStatus(PhabricatorUser $user) { + $revisions = id(new DifferentialRevisionQuery()) + ->withResponsibleUsers(array($user->getPHID())) + ->withStatus(DifferentialRevisionQuery::STATUS_OPEN) + ->execute(); - public function getShortDescription() { - return 'Code Review Application'; + list($active, $waiting) = DifferentialRevisionQuery::splitResponsible( + $revisions, + $user->getPHID()); + + $status = array(); + + $active = count($active); + $type = $active + ? PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Review(s) Need Attention', $active)) + ->setCount($active); + + $waiting = count($waiting); + $type = $waiting + ? PhabricatorApplicationStatusView::TYPE_INFO + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Review(s) Waiting on Others', $waiting)); + + return $status; } } diff --git a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php new file mode 100644 index 0000000000..da1924d46c --- /dev/null +++ b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php @@ -0,0 +1,34 @@ + array( diff --git a/src/applications/flag/application/PhabricatorApplicationFlags.php b/src/applications/flag/application/PhabricatorApplicationFlags.php new file mode 100644 index 0000000000..b60f441c8e --- /dev/null +++ b/src/applications/flag/application/PhabricatorApplicationFlags.php @@ -0,0 +1,53 @@ +withOwnerPHIDs(array($user->getPHID())) + ->execute(); + + $count = count($flags); + $type = $count + ? PhabricatorApplicationStatusView::TYPE_INFO + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Flagged Object(s)', $count)) + ->setCount($count); + + return $status; + } + +} + diff --git a/src/applications/maniphest/application/PhabricatorApplicationManiphest.php b/src/applications/maniphest/application/PhabricatorApplicationManiphest.php index b459d4f157..98c0035d32 100644 --- a/src/applications/maniphest/application/PhabricatorApplicationManiphest.php +++ b/src/applications/maniphest/application/PhabricatorApplicationManiphest.php @@ -18,15 +18,64 @@ final class PhabricatorApplicationManiphest extends PhabricatorApplication { + public function getShortDescription() { + return 'Tasks and Bugs'; + } + + public function getBaseURI() { + return '/maniphest/'; + } + public function isEnabled() { return PhabricatorEnv::getEnvConfig('maniphest.enabled'); } + public function getIconURI() { + return celerity_get_resource_uri('/rsrc/image/app/app_maniphest.png'); + } + public function getFactObjectsForAnalysis() { return array( new ManiphestTask(), ); } + public function loadStatus(PhabricatorUser $user) { + $status = array(); + + $query = id(new ManiphestTaskQuery()) + ->withStatus(ManiphestTaskQuery::STATUS_OPEN) + ->withPriority(ManiphestTaskPriority::PRIORITY_UNBREAK_NOW) + ->setLimit(1) + ->setCalculateRows(true); + $query->execute(); + + $count = $query->getRowCount(); + $type = $count + ? PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Unbreak Now Task(s)!', $count)) + ->setCount($count); + + $query = id(new ManiphestTaskQuery()) + ->withStatus(ManiphestTaskQuery::STATUS_OPEN) + ->withOwners(array($user->getPHID())) + ->setLimit(1) + ->setCalculateRows(true); + $query->execute(); + + $count = $query->getRowCount(); + $type = $count + ? PhabricatorApplicationStatusView::TYPE_INFO + : PhabricatorApplicationStatusView::TYPE_EMPTY; + $status[] = id(new PhabricatorApplicationStatusView()) + ->setType($type) + ->setText(pht('%d Assigned Task(s)', $count)); + + return $status; + } + } diff --git a/src/applications/meta/application/PhabricatorApplicationApplications.php b/src/applications/meta/application/PhabricatorApplicationApplications.php new file mode 100644 index 0000000000..f9360be2cf --- /dev/null +++ b/src/applications/meta/application/PhabricatorApplicationApplications.php @@ -0,0 +1,42 @@ + array( + '' => 'PhabricatorApplicationsListController' + ), + ); + } + + public function shouldAppearInLaunchView() { + return false; + } + +} + diff --git a/src/applications/meta/controller/PhabricatorApplicationsController.php b/src/applications/meta/controller/PhabricatorApplicationsController.php new file mode 100644 index 0000000000..b0805c8f1a --- /dev/null +++ b/src/applications/meta/controller/PhabricatorApplicationsController.php @@ -0,0 +1,35 @@ +buildStandardPageView(); + + $page->setApplicationName('Applications'); + $page->setBaseURI('/applications/'); + $page->setTitle(idx($data, 'title')); + $page->setGlyph("\xE0\xBC\x84"); + $page->appendChild($view); + + $response = new AphrontWebpageResponse(); + return $response->setContent($page->render()); + + } +} diff --git a/src/applications/meta/controller/PhabricatorApplicationsListController.php b/src/applications/meta/controller/PhabricatorApplicationsListController.php new file mode 100644 index 0000000000..59ad41fec5 --- /dev/null +++ b/src/applications/meta/controller/PhabricatorApplicationsListController.php @@ -0,0 +1,63 @@ +getRequest(); + $user = $request->getUser(); + + $applications = PhabricatorApplication::getAllInstalledApplications(); + $applications = msort($applications, 'getName'); + + foreach ($applications as $key => $application) { + if (!$application->shouldAppearInLaunchView()) { + unset($applications[$key]); + } + } + + $status = array(); + foreach ($applications as $key => $application) { + $status[$key] = $application->loadStatus($user); + } + + $views = array(); + foreach ($applications as $key => $application) { + $views[] = id(new PhabricatorApplicationLaunchView()) + ->setApplication($application) + ->setApplicationStatus(idx($status, $key, array())) + ->setUser($user); + } + + $view = phutil_render_tag( + 'div', + array( + 'class' => 'phabricator-application-list', + ), + id(new AphrontNullView())->appendChild($views)->render()); + + return $this->buildStandardPageResponse( + $view, + array( + 'title' => 'Applications', + )); + } + +} + diff --git a/src/applications/meta/view/PhabricatorApplicationLaunchView.php b/src/applications/meta/view/PhabricatorApplicationLaunchView.php new file mode 100644 index 0000000000..4b0c852f35 --- /dev/null +++ b/src/applications/meta/view/PhabricatorApplicationLaunchView.php @@ -0,0 +1,88 @@ +application = $application; + return $this; + } + + public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + + public function setApplicationStatus(array $status) { + $this->status = $status; + return $this; + } + + public function render() { + $application = $this->application; + + require_celerity_resource('phabricator-application-launch-view-css'); + + $content = array(); + $content[] = phutil_render_tag( + 'span', + array( + 'class' => 'phabricator-application-launch-name', + ), + phutil_escape_html($application->getName())); + $content[] = phutil_render_tag( + 'span', + array( + 'class' => 'phabricator-application-launch-description', + ), + phutil_escape_html($application->getShortDescription())); + + + $count = 0; + if ($this->status) { + $content[] = ''; + foreach ($this->status as $status) { + $count += $status->getCount(); + $content[] = $status; + } + $content[] = ''; + } + + if ($count) { + $content[] = phutil_render_tag( + 'span', + array( + 'class' => 'phabricator-application-launch-attention', + ), + phutil_escape_html($count)); + } + + return phutil_render_tag( + 'a', + array( + 'class' => 'phabricator-application-launch-container', + 'style' => 'background-image: url('.$application->getIconURI().')', + 'href' => $application->getBaseURI(), + ), + $this->renderSingleView($content)); + } +} diff --git a/src/applications/meta/view/PhabricatorApplicationStatusView.php b/src/applications/meta/view/PhabricatorApplicationStatusView.php new file mode 100644 index 0000000000..bb2d4f24f2 --- /dev/null +++ b/src/applications/meta/view/PhabricatorApplicationStatusView.php @@ -0,0 +1,64 @@ +type = $type; + return $this; + } + + public function setText($text) { + $this->text = $text; + return $this; + } + + public function setCount($count) { + $this->count = $count; + return $this; + } + + public function getCount() { + return $this->count; + } + + public function render() { + $classes = array( + 'phabricator-application-status', + 'phabricator-application-status-type-'.$this->type, + ); + + return phutil_render_tag( + 'span', + array( + 'class' => implode(' ', $classes), + ), + phutil_escape_html($this->text)); + } + +} diff --git a/src/applications/phriction/application/PhabricatorApplicationPhriction.php b/src/applications/phriction/application/PhabricatorApplicationPhriction.php new file mode 100644 index 0000000000..80e94b29db --- /dev/null +++ b/src/applications/phriction/application/PhabricatorApplicationPhriction.php @@ -0,0 +1,35 @@ + array( + '%d Commit Awaiting Audit', + '%d Commits Awaiting Audit', + ), + + '%d Problem Commit(s)' => array( + '%d Problem Commit', + '%d Problem Commits', + ), + + '%d Review(s) Need Attention' => array( + '%d Review Needs Attention', + '%d Reviews Need Attention', + ), + + '%d Review(s) Waiting on Others' => array( + '%d Review Waiting on Others', + '%d Reviews Waiting on Others', + ), + + '%d Flagged Object(s)' => array( + '%d Flagged Object', + '%d Flagged Objects', + ), + + '%d Unbreak Now Task(s)!' => array( + '%d Unbreak Now Task!', + '%d Unbreak Now Tasks!', + ), + + '%d Assigned Task(s)' => array( + '%d Assigned Task', + '%d Assigned Tasks', + ), + ); } diff --git a/webroot/rsrc/css/application/base/phabricator-application-launch-view.css b/webroot/rsrc/css/application/base/phabricator-application-launch-view.css new file mode 100644 index 0000000000..499cc45466 --- /dev/null +++ b/webroot/rsrc/css/application/base/phabricator-application-launch-view.css @@ -0,0 +1,131 @@ +/** + * @provides phabricator-application-launch-view-css + */ + + +/* - Application List ---------------------------------------------------------- + + Spacing container for the list of large application buttons. + +*/ + +/* On desktops, put some space around the whole grid. */ +.device-desktop .phabricator-application-list { + padding: .5em; +} + +/* On tablets, show two columns in the center. */ +.device-tablet .phabricator-application-list { + width: 660px; + margin: auto; + padding: .5em 0; +} + + +/* - Application Launch Button ------------------------------------------------- + + Spacing container for the list of large application buttons. + +*/ + +a.phabricator-application-launch-container { + display: inline-block; + width: 210px; + min-height: 90px; + background-repeat: no-repeat; + padding: 5px 15px 5px 80px; + background-position: 15px 10px; + margin: 3px 6px; + overflow: hidden; + position: relative; + + text-decoration: none; + border: 1px solid #737373; + background-color: #f3f3f3; + + border-radius: 4px; + box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.10), + inset -1px -1px 2px rgba(0, 0, 0, 0.15); +} + +a.phabricator-application-launch-container:hover { + text-decoration: none; +} + +/* The hover effect looks awful on phones/tablets when scrolling. */ +.device-desktop a.phabricator-application-launch-container:hover { + background-color: #3875d7; + border-color: #223366; + color: #eeeeee; +} + +.phabricator-application-launch-name, +.phabricator-application-launch-description, +.phabricator-application-launch-status { + display: block; +} + +.phabricator-application-launch-name { + font-weight: bold; +} + +.phabricator-application-launch-description { + color: #666666; +} + +.device-desktop a.phabricator-application-launch-container:hover + .phabricator-application-launch-description { + color: #dddddd; +} + +.phabricator-application-launch-attention { + position: absolute; + left: 45px; + top: 10px; + background: red; + border-radius: 10px; + color: white; + font-weight: normal; + padding: 2px 6px; + border: 1px solid #aa0000; + box-shadow: 0px 0px 3px rgba(255, 255, 255, 0.5), + inset 0 0 3px #aa0000; +} + +.phabricator-application-status-block { + margin-top: 0.5em; + padding-top: 0.5em; + border-top: 1px solid #dfdfdf; + display: block; +} + +.phabricator-application-status { + float: left; + display: block; + position: relative; + font-size: 11px; + height: 20px; + padding-left: 22px; + color: #666666; + + background-repeat: no-repeat; + background-size: 16px auto; + padding-top: 1px; +} + +.device-desktop a.phabricator-application-launch-container:hover + .phabricator-application-status { + color: #eeeeee; +} + +.phabricator-application-status-type-needs { + background-image: url(/rsrc/image/appstatus_needs.png); +} + +.phabricator-application-status-type-empty { + background-image: url(/rsrc/image/appstatus_empty.png); +} + +.phabricator-application-status-type-info { + background-image: url(/rsrc/image/appstatus_info.png); +} diff --git a/webroot/rsrc/image/app/app_audit.png b/webroot/rsrc/image/app/app_audit.png new file mode 100755 index 0000000000..4bd098c024 Binary files /dev/null and b/webroot/rsrc/image/app/app_audit.png differ diff --git a/webroot/rsrc/image/app/app_differential.png b/webroot/rsrc/image/app/app_differential.png new file mode 100755 index 0000000000..6afefd7aa2 Binary files /dev/null and b/webroot/rsrc/image/app/app_differential.png differ diff --git a/webroot/rsrc/image/app/app_diffusion.png b/webroot/rsrc/image/app/app_diffusion.png new file mode 100755 index 0000000000..b6961ef48a Binary files /dev/null and b/webroot/rsrc/image/app/app_diffusion.png differ diff --git a/webroot/rsrc/image/app/app_fact.png b/webroot/rsrc/image/app/app_fact.png new file mode 100755 index 0000000000..7d95d490a7 Binary files /dev/null and b/webroot/rsrc/image/app/app_fact.png differ diff --git a/webroot/rsrc/image/app/app_flags.png b/webroot/rsrc/image/app/app_flags.png new file mode 100755 index 0000000000..1a6a01a8ca Binary files /dev/null and b/webroot/rsrc/image/app/app_flags.png differ diff --git a/webroot/rsrc/image/app/app_maniphest.png b/webroot/rsrc/image/app/app_maniphest.png new file mode 100755 index 0000000000..596e3e86dd Binary files /dev/null and b/webroot/rsrc/image/app/app_maniphest.png differ diff --git a/webroot/rsrc/image/app/app_phriction.png b/webroot/rsrc/image/app/app_phriction.png new file mode 100755 index 0000000000..3b8ccbd245 Binary files /dev/null and b/webroot/rsrc/image/app/app_phriction.png differ diff --git a/webroot/rsrc/image/appstatus_empty.png b/webroot/rsrc/image/appstatus_empty.png new file mode 100644 index 0000000000..e1a48b5841 Binary files /dev/null and b/webroot/rsrc/image/appstatus_empty.png differ diff --git a/webroot/rsrc/image/appstatus_info.png b/webroot/rsrc/image/appstatus_info.png new file mode 100644 index 0000000000..14d9a1af8b Binary files /dev/null and b/webroot/rsrc/image/appstatus_info.png differ diff --git a/webroot/rsrc/image/appstatus_needs.png b/webroot/rsrc/image/appstatus_needs.png new file mode 100644 index 0000000000..cdd5542f91 Binary files /dev/null and b/webroot/rsrc/image/appstatus_needs.png differ diff --git a/webroot/rsrc/image/appstatus_okay.png b/webroot/rsrc/image/appstatus_okay.png new file mode 100755 index 0000000000..3b99631d7b Binary files /dev/null and b/webroot/rsrc/image/appstatus_okay.png differ