Path: blob/master/src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php
13395 views
<?php12final class DiffusionRepositoryBasicsManagementPanel3extends DiffusionRepositoryManagementPanel {45const PANELKEY = 'basics';67public function getManagementPanelLabel() {8return pht('Basics');9}1011public function getManagementPanelOrder() {12return 100;13}1415public function getManagementPanelIcon() {16return 'fa-code';17}1819protected function getEditEngineFieldKeys() {20return array(21'name',22'callsign',23'shortName',24'description',25'projectPHIDs',26);27}2829public function buildManagementPanelCurtain() {30$repository = $this->getRepository();31$viewer = $this->getViewer();3233$action_list = id(new PhabricatorActionListView())34->setViewer($viewer);3536$can_edit = PhabricatorPolicyFilter::hasCapability(37$viewer,38$repository,39PhabricatorPolicyCapability::CAN_EDIT);4041$edit_uri = $this->getEditPageURI();42$activate_uri = $repository->getPathURI('edit/activate/');43$delete_uri = $repository->getPathURI('edit/delete/');44$encoding_uri = $this->getEditPageURI('encoding');45$dangerous_uri = $repository->getPathURI('edit/dangerous/');46$enormous_uri = $repository->getPathURI('edit/enormous/');47$update_uri = $repository->getPathURI('edit/update/');48$publish_uri = $repository->getPathURI('edit/publish/');4950if ($repository->isTracked()) {51$activate_icon = 'fa-ban';52$activate_label = pht('Deactivate Repository');53} else {54$activate_icon = 'fa-check';55$activate_label = pht('Activate Repository');56}5758if (!$repository->isPublishingDisabled()) {59$publish_icon = 'fa-ban';60$publish_label = pht('Disable Publishing');61} else {62$publish_icon = 'fa-check';63$publish_label = pht('Enable Publishing');64}6566$should_dangerous = $repository->shouldAllowDangerousChanges();67if ($should_dangerous) {68$dangerous_icon = 'fa-shield';69$dangerous_name = pht('Prevent Dangerous Changes');70$can_dangerous = $can_edit;71} else {72$dangerous_icon = 'fa-exclamation-triangle';73$dangerous_name = pht('Allow Dangerous Changes');74$can_dangerous = ($can_edit && $repository->canAllowDangerousChanges());75}7677$should_enormous = $repository->shouldAllowEnormousChanges();78if ($should_enormous) {79$enormous_icon = 'fa-shield';80$enormous_name = pht('Prevent Enormous Changes');81$can_enormous = $can_edit;82} else {83$enormous_icon = 'fa-exclamation-triangle';84$enormous_name = pht('Allow Enormous Changes');85$can_enormous = ($can_edit && $repository->canAllowEnormousChanges());86}8788$action_list->addAction(89id(new PhabricatorActionView())90->setName(pht('Edit Basic Information'))91->setHref($edit_uri)92->setIcon('fa-pencil')93->setDisabled(!$can_edit)94->setWorkflow(!$can_edit));9596$action_list->addAction(97id(new PhabricatorActionView())98->setName(pht('Edit Text Encoding'))99->setIcon('fa-text-width')100->setHref($encoding_uri)101->setDisabled(!$can_edit)102->setWorkflow(!$can_edit));103104$action_list->addAction(105id(new PhabricatorActionView())106->setName($dangerous_name)107->setHref($dangerous_uri)108->setIcon($dangerous_icon)109->setDisabled(!$can_dangerous)110->setWorkflow(true));111112$action_list->addAction(113id(new PhabricatorActionView())114->setName($enormous_name)115->setHref($enormous_uri)116->setIcon($enormous_icon)117->setDisabled(!$can_enormous)118->setWorkflow(true));119120$action_list->addAction(121id(new PhabricatorActionView())122->setType(PhabricatorActionView::TYPE_DIVIDER));123124$action_list->addAction(125id(new PhabricatorActionView())126->setName($activate_label)127->setHref($activate_uri)128->setIcon($activate_icon)129->setDisabled(!$can_edit)130->setWorkflow(true));131132$action_list->addAction(133id(new PhabricatorActionView())134->setName($publish_label)135->setHref($publish_uri)136->setIcon($publish_icon)137->setDisabled(!$can_edit)138->setWorkflow(true));139140$action_list->addAction(141id(new PhabricatorActionView())142->setName(pht('Update Now'))143->setHref($update_uri)144->setIcon('fa-refresh')145->setWorkflow(true)146->setDisabled(!$can_edit));147148$action_list->addAction(149id(new PhabricatorActionView())150->setType(PhabricatorActionView::TYPE_DIVIDER));151152$action_list->addAction(153id(new PhabricatorActionView())154->setName(pht('Delete Repository'))155->setHref($delete_uri)156->setIcon('fa-times')157->setWorkflow(true));158159return $this->newCurtainView()160->setActionList($action_list);161}162163public function buildManagementPanelContent() {164$basics = $this->buildBasics();165$basics = $this->newBox(pht('Properties'), $basics);166167$repository = $this->getRepository();168169$state = $this->buildStateView($repository);170171$is_new = $repository->isNewlyInitialized();172$info_view = null;173if ($is_new) {174$messages = array();175176$messages[] = pht(177'This newly created repository is not active yet. Configure policies, '.178'options, and URIs. When ready, %s the repository.',179phutil_tag('strong', array(), pht('Activate')));180181if ($repository->isHosted()) {182$messages[] = pht(183'If activated now, this repository will become a new hosted '.184'repository. To observe an existing repository instead, configure '.185'it in the %s panel.',186phutil_tag('strong', array(), pht('URIs')));187} else {188$messages[] = pht(189'If activated now, this repository will observe an existing remote '.190'repository and begin importing changes.');191}192193$info_view = id(new PHUIInfoView())194->setSeverity(PHUIInfoView::SEVERITY_NOTICE)195->setErrors($messages);196}197198$description = $this->buildDescription();199if ($description) {200$description = $this->newBox(pht('Description'), $description);201}202$status = $this->buildStatus();203204return array($info_view, $state, $basics, $description, $status);205}206207private function buildBasics() {208$repository = $this->getRepository();209$viewer = $this->getViewer();210211$view = id(new PHUIPropertyListView())212->setViewer($viewer);213214$name = $repository->getName();215$view->addProperty(pht('Name'), $name);216217$type = PhabricatorRepositoryType::getNameForRepositoryType(218$repository->getVersionControlSystem());219$view->addProperty(pht('Type'), $type);220221$callsign = $repository->getCallsign();222if (!strlen($callsign)) {223$callsign = phutil_tag('em', array(), pht('No Callsign'));224}225$view->addProperty(pht('Callsign'), $callsign);226227$short_name = $repository->getRepositorySlug();228if ($short_name === null) {229$short_name = phutil_tag('em', array(), pht('No Short Name'));230}231$view->addProperty(pht('Short Name'), $short_name);232233$encoding = $repository->getDetail('encoding');234if (!$encoding) {235$encoding = phutil_tag('em', array(), pht('Use Default (UTF-8)'));236}237$view->addProperty(pht('Encoding'), $encoding);238239$can_dangerous = $repository->canAllowDangerousChanges();240if (!$can_dangerous) {241$dangerous = phutil_tag('em', array(), pht('Not Preventable'));242} else {243$should_dangerous = $repository->shouldAllowDangerousChanges();244if ($should_dangerous) {245$dangerous = pht('Allowed');246} else {247$dangerous = pht('Not Allowed');248}249}250251$view->addProperty(pht('Dangerous Changes'), $dangerous);252253$can_enormous = $repository->canAllowEnormousChanges();254if (!$can_enormous) {255$enormous = phutil_tag('em', array(), pht('Not Preventable'));256} else {257$should_enormous = $repository->shouldAllowEnormousChanges();258if ($should_enormous) {259$enormous = pht('Allowed');260} else {261$enormous = pht('Not Allowed');262}263}264265$view->addProperty(pht('Enormous Changes'), $enormous);266267return $view;268}269270271private function buildDescription() {272$repository = $this->getRepository();273$viewer = $this->getViewer();274275$description = $repository->getDetail('description');276277$view = id(new PHUIPropertyListView())278->setViewer($viewer);279if (!strlen($description)) {280return null;281} else {282$description = new PHUIRemarkupView($viewer, $description);283}284$view->addTextContent($description);285286return $view;287}288289private function buildStatus() {290$repository = $this->getRepository();291$viewer = $this->getViewer();292293$view = id(new PHUIPropertyListView())294->setViewer($viewer);295296$view->addProperty(297pht('Update Frequency'),298$this->buildRepositoryUpdateInterval($repository));299300$messages = $this->loadStatusMessages($repository);301302$status = $this->buildRepositoryStatus($repository, $messages);303$raw_error = $this->buildRepositoryRawError($repository, $messages);304305$view->addProperty(pht('Status'), $status);306if ($raw_error) {307$view->addSectionHeader(pht('Raw Error'));308$view->addTextContent($raw_error);309}310311return $this->newBox(pht('Working Copy Status'), $view);312}313314private function buildRepositoryUpdateInterval(315PhabricatorRepository $repository) {316317$smart_wait = $repository->loadUpdateInterval();318319$doc_href = PhabricatorEnv::getDoclink(320'Diffusion User Guide: Repository Updates');321322return array(323phutil_format_relative_time_detailed($smart_wait),324" \xC2\xB7 ",325phutil_tag(326'a',327array(328'href' => $doc_href,329'target' => '_blank',330),331pht('Learn More')),332);333}334335private function buildRepositoryStatus(336PhabricatorRepository $repository,337array $messages) {338339$viewer = $this->getViewer();340$is_cluster = $repository->getAlmanacServicePHID();341342$view = new PHUIStatusListView();343344if ($repository->isTracked()) {345$view->addItem(346id(new PHUIStatusItemView())347->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')348->setTarget(pht('Repository Active')));349} else {350$view->addItem(351id(new PHUIStatusItemView())352->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')353->setTarget(pht('Repository Inactive'))354->setNote(355pht('Activate this repository to begin or resume import.')));356return $view;357}358359$binaries = array();360$svnlook_check = false;361switch ($repository->getVersionControlSystem()) {362case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:363$binaries[] = 'git';364break;365case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:366$binaries[] = 'svn';367break;368case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:369$binaries[] = 'hg';370break;371}372373if ($repository->isHosted()) {374$proto_https = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTPS;375$proto_http = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_HTTP;376$can_http = $repository->canServeProtocol($proto_http, false) ||377$repository->canServeProtocol($proto_https, false);378379if ($can_http) {380switch ($repository->getVersionControlSystem()) {381case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:382$binaries[] = 'git-http-backend';383break;384case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:385$binaries[] = 'svnserve';386$binaries[] = 'svnadmin';387$binaries[] = 'svnlook';388$svnlook_check = true;389break;390case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:391$binaries[] = 'hg';392break;393}394}395396397$proto_ssh = PhabricatorRepositoryURI::BUILTIN_PROTOCOL_SSH;398$can_ssh = $repository->canServeProtocol($proto_ssh, false);399400if ($can_ssh) {401switch ($repository->getVersionControlSystem()) {402case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:403$binaries[] = 'git-receive-pack';404$binaries[] = 'git-upload-pack';405break;406case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:407$binaries[] = 'svnserve';408$binaries[] = 'svnadmin';409$binaries[] = 'svnlook';410$svnlook_check = true;411break;412case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:413$binaries[] = 'hg';414break;415}416}417}418419$binaries = array_unique($binaries);420if (!$is_cluster) {421// We're only checking for binaries if we aren't running with a cluster422// configuration. In theory, we could check for binaries on the423// repository host machine, but we'd need to make this more complicated424// to do that.425426foreach ($binaries as $binary) {427$where = Filesystem::resolveBinary($binary);428if (!$where) {429$view->addItem(430id(new PHUIStatusItemView())431->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')432->setTarget(433pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))434->setNote(pht(435"Unable to find this binary in the webserver's PATH. You may ".436"need to configure %s.",437$this->getEnvConfigLink())));438} else {439$view->addItem(440id(new PHUIStatusItemView())441->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')442->setTarget(443pht('Found Binary %s', phutil_tag('tt', array(), $binary)))444->setNote(phutil_tag('tt', array(), $where)));445}446}447448// This gets checked generically above. However, for svn commit hooks, we449// need this to be in environment.append-paths because subversion strips450// PATH.451if ($svnlook_check) {452$where = Filesystem::resolveBinary('svnlook');453if ($where) {454$path = substr($where, 0, strlen($where) - strlen('svnlook'));455$dirs = PhabricatorEnv::getEnvConfig('environment.append-paths');456$in_path = false;457foreach ($dirs as $dir) {458if (Filesystem::isDescendant($path, $dir)) {459$in_path = true;460break;461}462}463if (!$in_path) {464$view->addItem(465id(new PHUIStatusItemView())466->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')467->setTarget(468pht('Commit Hooks: %s', phutil_tag('tt', array(), $binary)))469->setNote(470pht(471'The directory containing the "svnlook" binary is not '.472'listed in "environment.append-paths", so commit hooks '.473'(which execute with an empty "PATH") will not be able to '.474'find "svnlook". Add `%s` to %s.',475$path,476$this->getEnvConfigLink())));477}478}479}480}481482$doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd');483484$daemon_instructions = pht(485'Use %s to start daemons. See %s.',486phutil_tag('tt', array(), 'bin/phd start'),487phutil_tag(488'a',489array(490'href' => $doc_href,491),492pht('Managing Daemons with phd')));493494495$pull_daemon = id(new PhabricatorDaemonLogQuery())496->setViewer(PhabricatorUser::getOmnipotentUser())497->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)498->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))499->setLimit(1)500->execute();501502if ($pull_daemon) {503504// TODO: In a cluster environment, we need a daemon on this repository's505// host, specifically, and we aren't checking for that right now. This506// is a reasonable proxy for things being more-or-less correctly set up,507// though.508509$view->addItem(510id(new PHUIStatusItemView())511->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')512->setTarget(pht('Pull Daemon Running')));513} else {514$view->addItem(515id(new PHUIStatusItemView())516->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')517->setTarget(pht('Pull Daemon Not Running'))518->setNote($daemon_instructions));519}520521522$task_daemon = id(new PhabricatorDaemonLogQuery())523->setViewer(PhabricatorUser::getOmnipotentUser())524->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)525->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))526->setLimit(1)527->execute();528if ($task_daemon) {529$view->addItem(530id(new PHUIStatusItemView())531->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')532->setTarget(pht('Task Daemon Running')));533} else {534$view->addItem(535id(new PHUIStatusItemView())536->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')537->setTarget(pht('Task Daemon Not Running'))538->setNote($daemon_instructions));539}540541542if ($is_cluster) {543// Just omit this status check for now in cluster environments. We544// could make a service call and pull it from the repository host545// eventually.546} else if ($repository->usesLocalWorkingCopy()) {547$local_parent = dirname($repository->getLocalPath());548if (Filesystem::pathExists($local_parent)) {549$view->addItem(550id(new PHUIStatusItemView())551->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')552->setTarget(pht('Storage Directory OK'))553->setNote(phutil_tag('tt', array(), $local_parent)));554} else {555$view->addItem(556id(new PHUIStatusItemView())557->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')558->setTarget(pht('No Storage Directory'))559->setNote(560pht(561'Storage directory %s does not exist, or is not readable by '.562'the webserver. Create this directory or make it readable.',563phutil_tag('tt', array(), $local_parent))));564return $view;565}566567$local_path = $repository->getLocalPath();568$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);569if ($message) {570switch ($message->getStatusCode()) {571case PhabricatorRepositoryStatusMessage::CODE_ERROR:572$view->addItem(573id(new PHUIStatusItemView())574->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')575->setTarget(pht('Initialization Error'))576->setNote($message->getParameter('message')));577return $view;578case PhabricatorRepositoryStatusMessage::CODE_OKAY:579if (Filesystem::pathExists($local_path)) {580$view->addItem(581id(new PHUIStatusItemView())582->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')583->setTarget(pht('Working Copy OK'))584->setNote(phutil_tag('tt', array(), $local_path)));585} else {586$view->addItem(587id(new PHUIStatusItemView())588->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')589->setTarget(pht('Working Copy Error'))590->setNote(591pht(592'Working copy %s has been deleted, or is not '.593'readable by the webserver. Make this directory '.594'readable. If it has been deleted, the daemons should '.595'restore it automatically.',596phutil_tag('tt', array(), $local_path))));597return $view;598}599break;600default:601$view->addItem(602id(new PHUIStatusItemView())603->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')604->setTarget(pht('Initializing Working Copy'))605->setNote(pht('Daemons are initializing the working copy.')));606return $view;607}608} else {609$view->addItem(610id(new PHUIStatusItemView())611->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')612->setTarget(pht('No Working Copy Yet'))613->setNote(614pht('Waiting for daemons to build a working copy.')));615return $view;616}617}618619$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);620if ($message) {621switch ($message->getStatusCode()) {622case PhabricatorRepositoryStatusMessage::CODE_ERROR:623$message = $message->getParameter('message');624625$suggestion = null;626if (preg_match('/Permission denied \(publickey\)./', $message)) {627$suggestion = pht(628'Public Key Error: This error usually indicates that the '.629'keypair you have configured does not have permission to '.630'access the repository.');631}632633$view->addItem(634id(new PHUIStatusItemView())635->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')636->setTarget(pht('Update Error'))637->setNote($suggestion));638return $view;639case PhabricatorRepositoryStatusMessage::CODE_OKAY:640$ago = (PhabricatorTime::getNow() - $message->getEpoch());641$view->addItem(642id(new PHUIStatusItemView())643->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')644->setTarget(pht('Updates OK'))645->setNote(646pht(647'Last updated %s (%s ago).',648phabricator_datetime($message->getEpoch(), $viewer),649phutil_format_relative_time_detailed($ago))));650break;651}652} else {653$view->addItem(654id(new PHUIStatusItemView())655->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')656->setTarget(pht('Waiting For Update'))657->setNote(658pht('Waiting for daemons to read updates.')));659}660661if ($repository->isImporting()) {662$ratio = $repository->loadImportProgress();663$percentage = sprintf('%.2f%%', 100 * $ratio);664665$view->addItem(666id(new PHUIStatusItemView())667->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')668->setTarget(pht('Importing'))669->setNote(670pht('%s Complete', $percentage)));671} else {672$view->addItem(673id(new PHUIStatusItemView())674->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')675->setTarget(pht('Fully Imported')));676}677678if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {679$view->addItem(680id(new PHUIStatusItemView())681->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')682->setTarget(pht('Prioritized'))683->setNote(pht('This repository will be updated soon!')));684}685686return $view;687}688689private function buildRepositoryRawError(690PhabricatorRepository $repository,691array $messages) {692$viewer = $this->getViewer();693694$can_edit = PhabricatorPolicyFilter::hasCapability(695$viewer,696$repository,697PhabricatorPolicyCapability::CAN_EDIT);698699$raw_error = null;700701$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);702if ($message) {703switch ($message->getStatusCode()) {704case PhabricatorRepositoryStatusMessage::CODE_ERROR:705$raw_error = $message->getParameter('message');706break;707}708}709710if ($raw_error !== null) {711if (!$can_edit) {712$raw_message = pht(713'You must be able to edit a repository to see raw error messages '.714'because they sometimes disclose sensitive information.');715$raw_message = phutil_tag('em', array(), $raw_message);716} else {717$raw_message = phutil_escape_html_newlines($raw_error);718}719} else {720$raw_message = null;721}722723return $raw_message;724}725726private function loadStatusMessages(PhabricatorRepository $repository) {727$messages = id(new PhabricatorRepositoryStatusMessage())728->loadAllWhere('repositoryID = %d', $repository->getID());729$messages = mpull($messages, null, 'getStatusType');730731return $messages;732}733734private function getEnvConfigLink() {735$config_href = '/config/edit/environment.append-paths/';736return phutil_tag(737'a',738array(739'href' => $config_href,740),741'environment.append-paths');742}743744private function buildStateView(PhabricatorRepository $repository) {745$viewer = $this->getViewer();746$is_new = $repository->isNewlyInitialized();747748$view = id(new PHUIPropertyListView())749->setViewer($viewer);750751if (!$repository->isTracked()) {752if ($is_new) {753$active_icon = 'fa-ban';754$active_color = 'yellow';755$active_label = pht('Not Activated Yet');756$active_note = pht('Complete Setup and Activate Repository');757} else {758$active_icon = 'fa-times';759$active_color = 'red';760$active_label = pht('Not Active');761$active_note = pht('Repository Disabled');762}763} else if ($repository->isImporting()) {764$active_icon = 'fa-hourglass';765$active_color = 'yellow';766$active_label = pht('Importing...');767$active_note = null;768} else {769$active_icon = 'fa-check';770$active_color = 'green';771$active_label = pht('Repository Active');772$active_note = null;773}774775$active_view = id(new PHUIStatusListView())776->addItem(777id(new PHUIStatusItemView())778->setIcon($active_icon, $active_color)779->setTarget($active_label)780->setNote($active_note));781782if ($repository->isPublishingDisabled()) {783$publishing_icon = 'fa-times';784$publishing_color = 'red';785$publishing_label = pht('Not Publishing');786$publishing_note = pht('Publishing Disabled');787} else if (!$repository->isTracked()) {788$publishing_icon = 'fa-ban';789$publishing_color = 'yellow';790$publishing_label = pht('Not Publishing');791if ($is_new) {792$publishing_note = pht('Repository Not Active Yet');793} else {794$publishing_note = pht('Repository Inactive');795}796} else if ($repository->isImporting()) {797$publishing_icon = 'fa-ban';798$publishing_color = 'yellow';799$publishing_label = pht('Not Publishing');800$publishing_note = pht('Repository Importing');801} else {802$publishing_icon = 'fa-check';803$publishing_color = 'green';804$publishing_label = pht('Publishing Active');805$publishing_note = null;806}807808$publishing_view = id(new PHUIStatusListView())809->addItem(810id(new PHUIStatusItemView())811->setIcon($publishing_icon, $publishing_color)812->setTarget($publishing_label)813->setNote($publishing_note));814815$view->addProperty(pht('Active'), $active_view);816$view->addProperty(pht('Publishing'), $publishing_view);817818return $this->newBox(pht('State'), $view);819}820821}822823824