1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

Merge branch 'master' into redesign-2015

This commit is contained in:
epriestley 2015-06-19 08:33:18 -07:00
commit 7d7e13d79b
50 changed files with 727 additions and 313 deletions

View file

@ -8,7 +8,7 @@
return array(
'names' => array(
'core.pkg.css' => '9cbee819',
'core.pkg.js' => '41f5edc5',
'core.pkg.js' => 'f1e8abd7',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'fe951924',
'differential.pkg.js' => 'ebef29b1',
@ -459,7 +459,7 @@ return array(
'rsrc/js/core/behavior-object-selector.js' => '49b73b36',
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
'rsrc/js/core/behavior-phabricator-nav.js' => '56a1ca03',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '095ed313',
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'eeaa9e5a',
'rsrc/js/core/behavior-refresh-csrf.js' => '7814b593',
'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45',
'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e',
@ -609,7 +609,7 @@ return array(
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
'javelin-behavior-phabricator-object-selector' => '49b73b36',
'javelin-behavior-phabricator-oncopy' => '2926fff2',
'javelin-behavior-phabricator-remarkup-assist' => '095ed313',
'javelin-behavior-phabricator-remarkup-assist' => 'eeaa9e5a',
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
'javelin-behavior-phabricator-search-typeahead' => '048330fa',
'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6',
@ -896,15 +896,6 @@ return array(
'javelin-stratcom',
'javelin-vector',
),
'095ed313' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-phtize',
'phabricator-textareautils',
'javelin-workflow',
'javelin-vector',
),
'0a3f3021' => array(
'javelin-behavior',
'javelin-stratcom',
@ -1951,6 +1942,15 @@ return array(
'phabricator-phtize',
'javelin-dom',
),
'eeaa9e5a' => array(
'javelin-behavior',
'javelin-stratcom',
'javelin-dom',
'phabricator-phtize',
'phabricator-textareautils',
'javelin-workflow',
'javelin-vector',
),
'efe49472' => array(
'javelin-install',
'javelin-util',

View file

@ -0,0 +1,5 @@
ALTER TABLE {$NAMESPACE}_diviner.diviner_livebook
ADD COLUMN repositoryPHID VARBINARY(64) AFTER name;
ALTER TABLE {$NAMESPACE}_diviner.diviner_livesymbol
ADD COLUMN repositoryPHID VARBINARY(64) AFTER bookPHID;

View file

@ -3288,7 +3288,6 @@ phutil_register_library_map(array(
'phabricator_format_local_time' => 'view/viewutils.php',
'phabricator_relative_date' => 'view/viewutils.php',
'phabricator_time' => 'view/viewutils.php',
'phabricator_time_format' => 'view/viewutils.php',
'phid_get_subtype' => 'applications/phid/utils.php',
'phid_get_type' => 'applications/phid/utils.php',
'phid_group_by_type' => 'applications/phid/utils.php',

View file

@ -35,8 +35,10 @@ abstract class AphrontController extends Phobject {
throw new PhutilMethodNotImplementedException(
pht(
'Controllers must implement either handleRequest() (recommended) '.
'or processRequest() (deprecated).'));
'Controllers must implement either %s (recommended) '.
'or %s (deprecated).',
'handleRequest()',
'processRequest()'));
}
final public function setRequest(AphrontRequest $request) {
@ -46,7 +48,7 @@ abstract class AphrontController extends Phobject {
final public function getRequest() {
if (!$this->request) {
throw new Exception(pht('Call setRequest() before getRequest()!'));
throw new PhutilInvalidStateException('setRequest');
}
return $this->request;
}
@ -81,10 +83,12 @@ abstract class AphrontController extends Phobject {
}
public function getDefaultResourceSource() {
throw new Exception(
throw new PhutilMethodNotImplementedException(
pht(
'A Controller must implement getDefaultResourceSource() before you '.
'can invoke requireResource() or initBehavior().'));
'A Controller must implement %s before you can invoke %s or %s.',
'getDefaultResourceSource()',
'requireResource()',
'initBehavior()'));
}
public function requireResource($symbol) {

View file

@ -18,7 +18,7 @@ final class PhabricatorAuthInviteEngine extends Phobject {
public function getViewer() {
if (!$this->viewer) {
throw new Exception(pht('Call setViewer() before getViewer()!'));
throw new PhutilInvalidStateException('setViewer');
}
return $this->viewer;
}

View file

@ -437,10 +437,11 @@ final class PhabricatorCalendarEventEditController
->setValue($end_disabled);
}
$description = id(new AphrontFormTextAreaControl())
$description = id(new PhabricatorRemarkupControl())
->setLabel(pht('Description'))
->setName('description')
->setValue($description);
->setValue($description)
->setUser($viewer);
$view_policies = id(new AphrontFormPolicyControl())
->setUser($viewer)

View file

@ -362,10 +362,19 @@ final class PhabricatorCalendarEventViewController
pht('Icon'),
$icon_display);
$properties->addSectionHeader(
pht('Description'),
PHUIPropertyListView::ICON_SUMMARY);
$properties->addTextContent($event->getDescription());
if (strlen($event->getDescription())) {
$description = PhabricatorMarkupEngine::renderOneObject(
id(new PhabricatorMarkupOneOff())->setContent($event->getDescription()),
'default',
$viewer);
$properties->addSectionHeader(
pht('Description'),
PHUIPropertyListView::ICON_SUMMARY);
$properties->addTextContent($description);
}
return $properties;
}

View file

@ -126,15 +126,15 @@ final class PhabricatorCalendarEventSearchEngine
$query->withDateRange($min_range, $max_range);
}
$invited_phids = $saved->getParameter('invitedPHIDs');
$invited_phids = $saved->getParameter('invitedPHIDs', array());
$invited_phids = $user_datasource->evaluateTokens($invited_phids);
if ($invited_phids) {
$invited_phids = $user_datasource->evaluateTokens($invited_phids);
$query->withInvitedPHIDs($invited_phids);
}
$creator_phids = $saved->getParameter('creatorPHIDs');
$creator_phids = $saved->getParameter('creatorPHIDs', array());
$creator_phids = $user_datasource->evaluateTokens($creator_phids);
if ($creator_phids) {
$creator_phids = $user_datasource->evaluateTokens($creator_phids);
$query->withCreatorPHIDs($creator_phids);
}
@ -313,17 +313,31 @@ final class PhabricatorCalendarEventSearchEngine
$list = new PHUIObjectItemListView();
foreach ($events as $event) {
$from = phabricator_datetime($event->getDateFrom(), $viewer);
$to = phabricator_datetime($event->getDateTo(), $viewer);
$duration = '';
$creator_handle = $handles[$event->getUserPHID()];
$attendees = array();
foreach ($event->getInvitees() as $invitee) {
$attendees[] = $invitee->getInviteePHID();
}
$attendees = pht(
'Attending: %s',
$viewer->renderHandleList($attendees)
->setAsInline(1)
->render());
if (strlen($event->getDuration()) > 0) {
$duration = pht(
'Duration: %s',
$event->getDuration());
}
$item = id(new PHUIObjectItemView())
->setHeader($event->getName())
->setHref($event->getURI())
->addByline(pht('Creator: %s', $creator_handle->renderLink()))
->addAttribute(pht('From %s to %s', $from, $to))
->addAttribute(id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(64)
->truncateString($event->getDescription()));
->setHeader($viewer->renderHandle($event->getPHID())->render())
->addAttribute($attendees)
->addIcon('none', $from)
->addIcon('none', $duration);
$list->addItem($item);
}

View file

@ -373,6 +373,29 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
return false;
}
public function getDuration() {
$seconds = $this->dateTo - $this->dateFrom;
$minutes = round($seconds / 60, 1);
$hours = round($minutes / 60, 3);
$days = round($hours / 24, 2);
$duration = '';
if ($days >= 1) {
return pht(
'%s day(s)',
round($days, 1));
} else if ($hours >= 1) {
return pht(
'%s hour(s)',
round($hours, 1));
} else if ($minutes >= 1) {
return pht(
'%s minute(s)',
round($minutes, 0));
}
}
/* -( Markup Interface )--------------------------------------------------- */

View file

@ -30,7 +30,7 @@ abstract class ConduitAPIMethod
$query = $this->newQueryObject();
if ($query) {
$types['order'] = 'order';
$types['order'] = 'optional order';
$types += $this->getPagerParamTypes();
}

View file

@ -20,7 +20,6 @@ final class PhabricatorSyntaxHighlightingConfigOptions
}
public function getOptions() {
$caches_href = PhabricatorEnv::getDocLink('Managing Caches');
return array(
@ -74,31 +73,43 @@ final class PhabricatorSyntaxHighlightingConfigOptions
'c' => 'C',
'coffee-script' => 'CoffeeScript',
'cpp' => 'C++',
'csharp' => 'C#',
'css' => 'CSS',
'd' => 'D',
'diff' => 'Diff',
'django' => 'Django Templating',
'docker' => 'Docker',
'erb' => 'Embedded Ruby/ERB',
'erlang' => 'Erlang',
'go' => 'Golang',
'groovy' => 'Groovy',
'haskell' => 'Haskell',
'html' => 'HTML',
'http' => 'HTTP',
'invisible' => 'Invisible',
'java' => 'Java',
'js' => 'Javascript',
'json' => 'JSON',
'make' => 'Makefile',
'mysql' => 'MySQL',
'nginx' => 'Nginx Configuration',
'objc' => 'Objective-C',
'perl' => 'Perl',
'php' => 'PHP',
'postgresql' => 'PostgreSQL',
'pot' => 'Gettext Catalog',
'puppet' => 'Puppet',
'rest' => 'reStructuredText',
'text' => 'Plain Text',
'python' => 'Python',
'rainbow' => 'Rainbow',
'remarkup' => 'Remarkup',
'rest' => 'reStructuredText',
'robotframework' => 'RobotFramework',
'rst' => 'reStructuredText',
'ruby' => 'Ruby',
'sql' => 'SQL',
'tex' => 'LaTeX',
'text' => 'Plain Text',
'twig' => 'Twig',
'xml' => 'XML',
'yaml' => 'YAML',
))

View file

@ -64,7 +64,7 @@ final class ConpherenceTransactionView extends AphrontView {
public function render() {
$viewer = $this->getUser();
if (!$viewer) {
throw new Exception(pht('Call setUser() before render()!'));
throw new PhutilInvalidStateException('setUser');
}
require_celerity_resource('conpherence-transaction-css');

View file

@ -127,6 +127,13 @@ final class DarkConsoleCore extends Phobject {
}
return $data;
} else {
// Truncate huge strings. Since the data doesn't really matter much,
// just truncate bytes to avoid PhutilUTF8StringTruncator overhead.
$length = strlen($data);
$max = 4096;
if ($length > $max) {
$data = substr($data, 0, $max).'...<'.$length.' bytes>...';
}
return phutil_utf8ize($data);
}
}

View file

@ -283,9 +283,7 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
*/
private function detectRenderingCycle(PhabricatorDashboardPanel $panel) {
if ($this->parentPanelPHIDs === null) {
throw new Exception(
pht(
'You must call setParentPanelPHIDs() before rendering panels.'));
throw new PhutilInvalidStateException('setParentPanelPHIDs');
}
$max_depth = 4;

View file

@ -20,6 +20,8 @@ final class DiffusionFileContentQueryConduitAPIMethod
'path' => 'required string',
'commit' => 'required string',
'needsBlame' => 'optional bool',
'timeout' => 'optional int',
'byteLimit' => 'optional int',
);
}
@ -31,16 +33,30 @@ final class DiffusionFileContentQueryConduitAPIMethod
$file_query
->setViewer($request->getUser())
->setNeedsBlame($needs_blame);
$timeout = $request->getValue('timeout');
if ($timeout) {
$file_query->setTimeout($timeout);
}
$byte_limit = $request->getValue('byteLimit');
if ($byte_limit) {
$file_query->setByteLimit($byte_limit);
}
$file_content = $file_query->loadFileContent();
if ($needs_blame) {
list($text_list, $rev_list, $blame_dict) = $file_query->getBlameData();
} else {
$text_list = $rev_list = $blame_dict = array();
}
$file_content
->setBlameDict($blame_dict)
->setRevList($rev_list)
->setTextList($text_list);
return $file_content->toDictionary();
}

View file

@ -54,14 +54,27 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
$needs_blame = ($show_blame && !$show_color) ||
($show_blame && $request->isAjax());
$params = array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
'needsBlame' => $needs_blame,
);
$byte_limit = null;
if ($view !== 'raw') {
$byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
$time_limit = 10;
$params += array(
'timeout' => $time_limit,
'byteLimit' => $byte_limit,
);
}
$file_content = DiffusionFileContent::newFromConduit(
$this->callConduitWithDiffusionRequest(
'diffusion.filecontentquery',
array(
'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(),
'needsBlame' => $needs_blame,
)));
$params));
$data = $file_content->getCorpus();
if ($view === 'raw') {
@ -71,8 +84,13 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
$this->loadLintMessages();
$this->coverage = $drequest->loadCoverage();
$binary_uri = null;
if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
if ($byte_limit && (strlen($data) == $byte_limit)) {
$corpus = $this->buildErrorCorpus(
pht(
'This file is larger than %s byte(s), and too large to display '.
'in the web UI.',
$byte_limit));
} else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
$file = $this->loadFileForData($path, $data);
$file_uri = $file->getBestURI();
@ -80,7 +98,6 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
$corpus = $this->buildImageCorpus($file_uri);
} else {
$corpus = $this->buildBinaryCorpus($file_uri, $data);
$binary_uri = $file_uri;
}
} else {
// Build the content of the file.
@ -940,6 +957,21 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
return $box;
}
private function buildErrorCorpus($message) {
$text = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->appendChild($message);
$header = id(new PHUIHeaderView())
->setHeader(pht('Details'));
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($text);
return $box;
}
private function buildBeforeResponse($before) {
$request = $this->getRequest();
$drequest = $this->getDiffusionRequest();

View file

@ -11,6 +11,26 @@ abstract class DiffusionFileContentQuery extends DiffusionQuery {
private $needsBlame;
private $fileContent;
private $viewer;
private $timeout;
private $byteLimit;
public function setTimeout($timeout) {
$this->timeout = $timeout;
return $this;
}
public function getTimeout() {
return $this->timeout;
}
public function setByteLimit($byte_limit) {
$this->byteLimit = $byte_limit;
return $this;
}
public function getByteLimit() {
return $this->byteLimit;
}
final public static function newFromDiffusionRequest(
DiffusionRequest $request) {
@ -21,7 +41,31 @@ abstract class DiffusionFileContentQuery extends DiffusionQuery {
abstract protected function executeQueryFromFuture(Future $future);
final public function loadFileContentFromFuture(Future $future) {
$this->fileContent = $this->executeQueryFromFuture($future);
if ($this->timeout) {
$future->setTimeout($this->timeout);
}
if ($this->getByteLimit()) {
$future->setStdoutSizeLimit($this->getByteLimit());
}
try {
$file_content = $this->executeQueryFromFuture($future);
} catch (CommandException $ex) {
if (!$future->getWasKilledByTimeout()) {
throw $ex;
}
$message = pht(
'<Attempt to load this file was terminated after %s second(s).>',
$this->timeout);
$file_content = new DiffusionFileContent();
$file_content->setCorpus($message);
}
$this->fileContent = $file_content;
$repository = $this->getRequest()->getRepository();
$try_encoding = $repository->getDetail('encoding');

View file

@ -84,6 +84,7 @@ final class DivinerAtomController extends DivinerController {
if ($atom) {
$this->buildDefined($properties, $symbol);
$this->buildExtendsAndImplements($properties, $symbol);
$this->buildRepository($properties, $symbol);
$warnings = $atom->getWarnings();
if ($warnings) {
@ -294,6 +295,15 @@ final class DivinerAtomController extends DivinerController {
}
}
private function buildRepository(
PHUIPropertyListView $view,
DivinerLiveSymbol $symbol) {
$view->addProperty(
pht('Repository'),
$this->getViewer()->renderHandle($symbol->getRepositoryPHID()));
}
private function renderAtomTag(DivinerLiveSymbol $symbol) {
return id(new PHUITagView())
->setType(PHUITagView::TYPE_OBJECT)

View file

@ -14,6 +14,7 @@ final class DivinerBookController extends DivinerController {
$book = id(new DivinerBookQuery())
->setViewer($viewer)
->withNames(array($book_name))
->needRepositories(true)
->executeOne();
if (!$book) {
@ -43,6 +44,15 @@ final class DivinerBookController extends DivinerController {
->setEpoch($book->getDateModified())
->addActionLink($action_button);
// TODO: This could probably look better.
if ($book->getRepositoryPHID()) {
$header->addTag(
id(new PHUITagView())
->setType(PHUITagView::TYPE_STATE)
->setBackgroundColor(PHUITagView::COLOR_BLUE)
->setName($book->getRepository()->getMonogram()));
}
$document = new PHUIDocumentView();
$document->setHeader($header);
$document->addClass('diviner-view');

View file

@ -75,6 +75,16 @@ final class DivinerBookEditController extends DivinerController {
->setName('projectPHIDs')
->setLabel(pht('Projects'))
->setValue($book->getProjectPHIDs()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new DiffusionRepositoryDatasource())
->setName('repositoryPHIDs')
->setLabel(pht('Repository'))
->setDisableBehavior(true)
->setLimit(1)
->setValue($book->getRepositoryPHID()
? array($book->getRepositoryPHID())
: null))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('viewPolicy')

View file

@ -4,7 +4,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
private $book;
private function loadBook() {
protected function getBook() {
if (!$this->book) {
$book_name = $this->getConfig('name');
@ -20,7 +20,24 @@ final class DivinerLivePublisher extends DivinerPublisher {
->save();
}
$book->setConfigurationData($this->getConfigurationData())->save();
$conn_w = $book->establishConnection('w');
$conn_w->openTransaction();
$book
->setRepositoryPHID($this->getRepositoryPHID())
->setConfigurationData($this->getConfigurationData())
->save();
// TODO: This is gross. Without this, the repository won't be updated for
// atoms which have already been published.
queryfx(
$conn_w,
'UPDATE %T SET repositoryPHID = %s WHERE bookPHID = %s',
id(new DivinerLiveSymbol())->getTableName(),
$this->getRepositoryPHID(),
$book->getPHID());
$conn_w->saveTransaction();
$this->book = $book;
id(new PhabricatorSearchIndexer())
@ -33,7 +50,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
private function loadSymbolForAtom(DivinerAtom $atom) {
$symbol = id(new DivinerAtomQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withBookPHIDs(array($this->loadBook()->getPHID()))
->withBookPHIDs(array($atom->getBook()))
->withTypes(array($atom->getType()))
->withNames(array($atom->getName()))
->withContexts(array($atom->getContext()))
@ -45,7 +62,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
}
return id(new DivinerLiveSymbol())
->setBookPHID($this->loadBook()->getPHID())
->setBookPHID($this->getBook()->getPHID())
->setType($atom->getType())
->setName($atom->getName())
->setContext($atom->getContext())
@ -68,7 +85,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
protected function loadAllPublishedHashes() {
$symbols = id(new DivinerAtomQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withBookPHIDs(array($this->loadBook()->getPHID()))
->withBookPHIDs(array($this->getBook()->getPHID()))
->withGhosts(false)
->execute();
@ -113,6 +130,7 @@ final class DivinerLivePublisher extends DivinerPublisher {
$is_documentable = $this->shouldGenerateDocumentForAtom($atom);
$symbol
->setRepositoryPHID($this->getRepositoryPHID())
->setGraphHash($hash)
->setIsDocumentable((int)$is_documentable)
->setTitle($ref->getTitle())

View file

@ -9,6 +9,7 @@ abstract class DivinerPublisher extends Phobject {
private $config;
private $symbolReverseMap;
private $dropCaches;
private $repositoryPHID;
final public function setDropCaches($drop_caches) {
$this->dropCaches = $drop_caches;
@ -163,4 +164,13 @@ abstract class DivinerPublisher extends Phobject {
return true;
}
final public function getRepositoryPHID() {
return $this->repositoryPHID;
}
final public function setRepositoryPHID($repository_phid) {
$this->repositoryPHID = $repository_phid;
return $this;
}
}

View file

@ -14,10 +14,12 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
private $nodeHashes;
private $titles;
private $nameContains;
private $repositoryPHIDs;
private $needAtoms;
private $needExtends;
private $needChildren;
private $needRepositories;
public function withIDs(array $ids) {
$this->ids = $ids;
@ -109,6 +111,16 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this;
}
public function withRepositoryPHIDs(array $repository_phids) {
$this->repositoryPHIDs = $repository_phids;
return $this;
}
public function needRepositories($need_repositories) {
$this->needRepositories = $need_repositories;
return $this;
}
protected function loadPage() {
$table = new DivinerLiveSymbol();
$conn_r = $table->establishConnection('r');
@ -125,6 +137,8 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
}
protected function willFilterPage(array $atoms) {
assert_instances_of($atoms, 'DivinerLiveSymbol');
$books = array_unique(mpull($atoms, 'getBookPHID'));
$books = id(new DivinerBookQuery())
@ -257,6 +271,31 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$this->attachAllChildren($atoms, $children, $this->needExtends);
}
if ($this->needRepositories) {
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($this->getViewer())
->withPHIDs(mpull($atoms, 'getRepositoryPHID'))
->execute();
$repositories = mpull($repositories, null, 'getPHID');
foreach ($atoms as $key => $atom) {
if ($atom->getRepositoryPHID() === null) {
$atom->attachRepository(null);
continue;
}
$repository = idx($repositories, $atom->getRepositoryPHID());
if (!$repository) {
$this->didRejectResult($atom);
unset($atom[$key]);
continue;
}
$atom->attachRepository($repository);
}
}
return $atoms;
}
@ -381,6 +420,13 @@ final class DivinerAtomQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$this->nameContains);
}
if ($this->repositoryPHIDs) {
$where[] = qsprintf(
$conn_r,
'repositoryPHID IN (%Ls)',
$this->repositoryPHIDs);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);

View file

@ -13,21 +13,23 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'repositoryPHIDs',
$this->readPHIDsFromRequest($request, 'repositoryPHIDs'));
$saved->setParameter('name', $request->getStr('name'));
$saved->setParameter(
'types',
$this->readListFromRequest($request, 'types'));
$saved->setParameter('name', $request->getStr('name'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new DivinerAtomQuery());
$types = $saved->getParameter('types');
if ($types) {
$query->withTypes($types);
$repository_phids = $saved->getParameter('repositoryPHIDs');
if ($repository_phids) {
$query->withRepositoryPHIDs($repository_phids);
}
$name = $saved->getParameter('name');
@ -35,6 +37,11 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
$query->withNameContains($name);
}
$types = $saved->getParameter('types');
if ($types) {
$query->withTypes($types);
}
return $query;
}
@ -42,6 +49,12 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name Contains'))
->setName('name')
->setValue($saved->getParameter('name')));
$all_types = array();
foreach (DivinerAtom::getAllTypes() as $type) {
$all_types[$type] = DivinerAtom::getAtomTypeNameString($type);
@ -59,14 +72,14 @@ final class DivinerAtomSearchEngine extends PhabricatorApplicationSearchEngine {
$name,
isset($types[$type]));
}
$form->appendChild($type_control);
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name Contains'))
->setName('name')
->setValue($saved->getParameter('name')))
->appendChild($type_control);
$form->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Repositories'))
->setName('repositoryPHIDs')
->setDatasource(new DiffusionRepositoryDatasource())
->setValue($saved->getParameter('repositoryPHIDs')));
}
protected function getURI($path) {

View file

@ -5,8 +5,10 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $names;
private $repositoryPHIDs;
private $needProjectPHIDs;
private $needRepositories;
public function withIDs(array $ids) {
$this->ids = $ids;
@ -23,11 +25,21 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this;
}
public function withRepositoryPHIDs(array $repository_phids) {
$this->repositoryPHIDs = $repository_phids;
return $this;
}
public function needProjectPHIDs($need_phids) {
$this->needProjectPHIDs = $need_phids;
return $this;
}
public function needRepositories($need_repositories) {
$this->needRepositories = $need_repositories;
return $this;
}
protected function loadPage() {
$table = new DivinerLiveBook();
$conn_r = $table->establishConnection('r');
@ -46,6 +58,31 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
protected function didFilterPage(array $books) {
assert_instances_of($books, 'DivinerLiveBook');
if ($this->needRepositories) {
$repositories = id(new PhabricatorRepositoryQuery())
->setViewer($this->getViewer())
->withPHIDs(mpull($books, 'getRepositoryPHID'))
->execute();
$repositories = mpull($repositories, null, 'getPHID');
foreach ($books as $key => $book) {
if ($book->getRepositoryPHID() === null) {
$book->attachRepository(null);
continue;
}
$repository = idx($repositories, $book->getRepositoryPHID());
if (!$repository) {
$this->didRejectResult($book);
unset($books[$key]);
continue;
}
$book->attachRepository($repository);
}
}
if ($this->needProjectPHIDs) {
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($books, 'getPHID'))
@ -91,6 +128,13 @@ final class DivinerBookQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$this->names);
}
if ($this->repositoryPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'repositoryPHID IN (%Ls)',
$this->repositoryPHIDs);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);

View file

@ -29,6 +29,12 @@ final class DivinerAtomSearchIndexer extends PhabricatorSearchDocumentIndexer {
DivinerBookPHIDType::TYPECONST,
PhabricatorTime::getNow());
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
$atom->getRepositoryPHID(),
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
PhabricatorTime::getNow());
$doc->addRelationship(
$atom->getGraphHash()
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED

View file

@ -18,6 +18,12 @@ final class DivinerBookSearchIndexer extends PhabricatorSearchDocumentIndexer {
PhabricatorSearchDocumentFieldType::FIELD_BODY,
$book->getPreface());
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY,
$book->getRepositoryPHID(),
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
$book->getDateCreated());
$this->indexTransactions(
$doc,
new DivinerLiveBookTransactionQuery(),

View file

@ -8,11 +8,13 @@ final class DivinerLiveBook extends DivinerDAO
PhabricatorApplicationTransactionInterface {
protected $name;
protected $repositoryPHID;
protected $viewPolicy;
protected $editPolicy;
protected $configurationData = array();
private $projectPHIDs = self::ATTACHABLE;
private $repository = self::ATTACHABLE;
protected function getConfiguration() {
return array(
@ -22,6 +24,7 @@ final class DivinerLiveBook extends DivinerDAO
),
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'text64',
'repositoryPHID' => 'phid?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
@ -68,6 +71,15 @@ final class DivinerLiveBook extends DivinerDAO
return idx($spec, 'name', $group);
}
public function attachRepository(PhabricatorRepository $repository = null) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->assertAttached($this->repository);
}
public function attachProjectPHIDs(array $project_phids) {
$this->projectPHIDs = $project_phids;
return $this;
@ -98,7 +110,7 @@ final class DivinerLiveBook extends DivinerDAO
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
return false;
}
public function describeAutomaticCapability($capability) {

View file

@ -7,6 +7,7 @@ final class DivinerLiveSymbol extends DivinerDAO
PhabricatorDestructibleInterface {
protected $bookPHID;
protected $repositoryPHID;
protected $context;
protected $type;
protected $name;
@ -22,6 +23,7 @@ final class DivinerLiveSymbol extends DivinerDAO
protected $isDocumentable = 0;
private $book = self::ATTACHABLE;
private $repository = self::ATTACHABLE;
private $atom = self::ATTACHABLE;
private $extends = self::ATTACHABLE;
private $children = self::ATTACHABLE;
@ -43,6 +45,7 @@ final class DivinerLiveSymbol extends DivinerDAO
'summary' => 'text?',
'isDocumentable' => 'bool',
'nodeHash' => 'text64?',
'repositoryPHID' => 'phid?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
@ -94,6 +97,15 @@ final class DivinerLiveSymbol extends DivinerDAO
return $this;
}
public function getRepository() {
return $this->assertAttached($this->repository);
}
public function attachRepository(PhabricatorRepository $repository = null) {
$this->repository = $repository;
return $this;
}
public function getAtom() {
return $this->assertAttached($this->atom);
}

View file

@ -25,6 +25,11 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
'help' => pht('Specify a subclass of %s.', 'DivinerPublisher'),
'default' => 'DivinerLivePublisher',
),
array(
'name' => 'repository',
'param' => 'callsign',
'help' => pht('Repository that the documentation belongs to.'),
),
));
}
@ -187,6 +192,24 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
}
$publisher = newv($publisher_class, array());
$callsign = $args->getArg('repository');
$repository = null;
if ($callsign) {
$repository = id(new PhabricatorRepositoryQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withCallsigns(array($callsign))
->executeOne();
if (!$repository) {
throw new PhutilArgumentUsageException(
pht(
"Repository '%s' does not exist.",
$callsign));
}
$publisher->setRepositoryPHID($repository->getPHID());
}
$this->publishDocumentation($args->getArg('clean'), $publisher);
}

View file

@ -77,20 +77,7 @@ final class DrydockPreallocatedHostBlueprintImplementation
$cmd = $lease->getInterface('command');
if ($v_platform !== 'windows') {
$cmd->execx('mkdir %s', $full_path);
} else {
// Windows is terrible. The mkdir command doesn't even support putting
// the path in quotes. IN QUOTES. ARGUHRGHUGHHGG!! Do some terribly
// inaccurate sanity checking since we can't safely escape the path.
if (preg_match('/^[A-Z]\\:\\\\[a-zA-Z0-9\\\\\\ ]/', $full_path) === 0) {
throw new Exception(
pht(
'Unsafe path detected for Windows platform: "%s".',
$full_path));
}
$cmd->execx('mkdir %C', $full_path);
}
$cmd->execx('mkdir %s', $full_path);
$lease->setAttribute('path', $full_path);
}

View file

@ -42,46 +42,8 @@ final class DrydockSSHCommandInterface extends DrydockCommandInterface {
$this->openCredentialsIfNotOpen();
$argv = func_get_args();
if ($this->getConfig('platform') === 'windows') {
// Handle Windows by executing the command under PowerShell.
$command = id(new PhutilCommandString($argv))
->setEscapingMode(PhutilCommandString::MODE_POWERSHELL);
$change_directory = '';
if ($this->getWorkingDirectory() !== null) {
$change_directory .= 'cd '.$this->getWorkingDirectory();
}
$script = <<<EOF
$change_directory
$command
if (\$LastExitCode -ne 0) {
exit \$LastExitCode
}
EOF;
// When Microsoft says "Unicode" they don't mean UTF-8.
$script = mb_convert_encoding($script, 'UTF-16LE');
$script = base64_encode($script);
$powershell =
'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
$powershell .=
' -ExecutionPolicy Bypass'.
' -NonInteractive'.
' -InputFormat Text'.
' -OutputFormat Text'.
' -EncodedCommand '.$script;
$full_command = $powershell;
} else {
// Handle UNIX by executing under the native shell.
$argv = $this->applyWorkingDirectoryToArgv($argv);
$full_command = call_user_func_array('csprintf', $argv);
}
$argv = $this->applyWorkingDirectoryToArgv($argv);
$full_command = call_user_func_array('csprintf', $argv);
$command_timeout = '';
if ($this->connectTimeout !== null) {

View file

@ -7,6 +7,7 @@ final class PhabricatorOwnersPackageQuery
private $phids;
private $ownerPHIDs;
private $repositoryPHIDs;
private $namePrefix;
/**
* Owners are direct owners, and members of owning projects.
@ -31,62 +32,59 @@ final class PhabricatorOwnersPackageQuery
return $this;
}
protected function loadPage() {
$table = new PhabricatorOwnersPackage();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT p.* FROM %T p %Q %Q %Q %Q',
$table->getTableName(),
$this->buildJoinClause($conn_r),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
public function withNamePrefix($prefix) {
$this->namePrefix = $prefix;
return $this;
}
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
$joins = array();
public function newResultObject() {
return new PhabricatorOwnersPackage();
}
protected function loadPage() {
return $this->loadStandardPage(new PhabricatorOwnersPackage());
}
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = parent::buildJoinClauseParts($conn);
if ($this->ownerPHIDs !== null) {
$joins[] = qsprintf(
$conn_r,
$conn,
'JOIN %T o ON o.packageID = p.id',
id(new PhabricatorOwnersOwner())->getTableName());
}
if ($this->repositoryPHIDs !== null) {
$joins[] = qsprintf(
$conn_r,
$conn,
'JOIN %T rpath ON rpath.packageID = p.id',
id(new PhabricatorOwnersPath())->getTableName());
}
return implode(' ', $joins);
return $joins;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->phids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'p.phid IN (%Ls)',
$this->phids);
}
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'p.id IN (%Ld)',
$this->ids);
}
if ($this->repositoryPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'rpath.repositoryPHID IN (%Ls)',
$this->repositoryPHIDs);
}
@ -94,26 +92,79 @@ final class PhabricatorOwnersPackageQuery
if ($this->ownerPHIDs !== null) {
$base_phids = $this->ownerPHIDs;
$query = new PhabricatorProjectQuery();
$query->setViewer($this->getViewer());
$query->withMemberPHIDs($base_phids);
$projects = $query->execute();
$projects = id(new PhabricatorProjectQuery())
->setViewer($this->getViewer())
->withMemberPHIDs($base_phids)
->execute();
$project_phids = mpull($projects, 'getPHID');
$all_phids = array_merge($base_phids, $project_phids);
$where[] = qsprintf(
$conn_r,
$conn,
'o.userPHID IN (%Ls)',
$all_phids);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
if (strlen($this->namePrefix)) {
// NOTE: This is a hacky mess, but this column is currently case
// sensitive and unique.
$where[] = qsprintf(
$conn,
'LOWER(p.name) LIKE %>',
phutil_utf8_strtolower($this->namePrefix));
}
return $where;
}
protected function shouldGroupQueryResultRows() {
if ($this->repositoryPHIDs) {
return true;
}
if ($this->ownerPHIDs) {
return true;
}
return parent::shouldGroupQueryResultRows();
}
public function getBuiltinOrders() {
return array(
'name' => array(
'vector' => array('name'),
'name' => pht('Name'),
),
) + parent::getBuiltinOrders();
}
public function getOrderableColumns() {
return parent::getOrderableColumns() + array(
'name' => array(
'table' => $this->getPrimaryTableAlias(),
'column' => 'name',
'type' => 'string',
'unique' => true,
'reverse' => true,
),
);
}
protected function getPagingValueMap($cursor, array $keys) {
$package = $this->loadCursorObject($cursor);
return array(
'id' => $package->getID(),
'name' => $package->getName(),
);
}
public function getQueryApplicationClass() {
return 'PhabricatorOwnersApplication';
}
protected function getPrimaryTableAlias() {
return 'p';
}
}

View file

@ -11,68 +11,39 @@ final class PhabricatorOwnersPackageSearchEngine
return 'PhabricatorOwnersApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'ownerPHIDs',
$this->readUsersFromRequest(
$request,
'owners',
array(
PhabricatorProjectProjectPHIDType::TYPECONST,
)));
$saved->setParameter(
'repositoryPHIDs',
$this->readPHIDsFromRequest(
$request,
'repositories',
array(
PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
)));
return $saved;
public function newQuery() {
return new PhabricatorOwnersPackageQuery();
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhabricatorOwnersPackageQuery());
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Owners'))
->setKey('ownerPHIDs')
->setAliases(array('owner', 'owners'))
->setDatasource(new PhabricatorProjectOrUserDatasource()),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Repositories'))
->setKey('repositoryPHIDs')
->setAliases(array('repository', 'repositories'))
->setDatasource(new DiffusionRepositoryDatasource()),
);
}
$owner_phids = $saved->getParameter('ownerPHIDs', array());
if ($owner_phids) {
$query->withOwnerPHIDs($owner_phids);
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['ownerPHIDs']) {
$query->withOwnerPHIDs($map['ownerPHIDs']);
}
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
if ($repository_phids) {
$query->withRepositoryPHIDs($repository_phids);
if ($map['repositoryPHIDs']) {
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$owner_phids = $saved->getParameter('ownerPHIDs', array());
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorProjectOrUserDatasource())
->setName('owners')
->setLabel(pht('Owners'))
->setValue($owner_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new DiffusionRepositoryDatasource())
->setName('repositories')
->setLabel(pht('Repositories'))
->setValue($repository_phids));
}
protected function getURI($path) {
return '/owners/'.$path;
}

View file

@ -3,11 +3,6 @@
final class PhabricatorOwnersPackageDatasource
extends PhabricatorTypeaheadDatasource {
public function isBrowsable() {
// TODO: Make this browsable.
return false;
}
public function getBrowseTitle() {
return pht('Browse Packages');
}
@ -26,10 +21,11 @@ final class PhabricatorOwnersPackageDatasource
$results = array();
$packages = id(new PhabricatorOwnersPackageQuery())
->setViewer($viewer)
->execute();
$query = id(new PhabricatorOwnersPackageQuery())
->withNamePrefix($raw_query)
->setOrder('name');
$packages = $this->executeQuery($query);
foreach ($packages as $package) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($package->getName())
@ -37,7 +33,7 @@ final class PhabricatorOwnersPackageDatasource
->setPHID($package->getPHID());
}
return $results;
return $this->filterResultsAgainstTokens($results);
}
}

View file

@ -738,6 +738,41 @@ final class PhabricatorUser
return new DateTimeZone($this->getTimezoneIdentifier());
}
public function getPreference($key) {
$preferences = $this->loadPreferences();
// TODO: After T4103 and T7707 this should eventually be pushed down the
// stack into modular preference definitions and role profiles. This is
// just fixing T8601 and mildly anticipating those changes.
$value = $preferences->getPreference($key);
$allowed_values = null;
switch ($key) {
case PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT:
$allowed_values = array(
'g:i A',
'H:i',
);
break;
case PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT:
$allowed_values = array(
'Y-m-d',
'n/j/Y',
'd-m-Y',
);
break;
}
if ($allowed_values !== null) {
$allowed_values = array_fuse($allowed_values);
if (empty($allowed_values[$value])) {
$value = head($allowed_values);
}
}
return $value;
}
public function __toString() {
return $this->getUsername();
}

View file

@ -1913,7 +1913,25 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$this->delete();
$this->delete();
$books = id(new DivinerBookQuery())
->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($this->getPHID()))
->execute();
foreach ($books as $book) {
$engine->destroyObject($book);
}
$atoms = id(new DivinerAtomQuery())
->setViewer($engine->getViewer())
->withRepositoryPHIDs(array($this->getPHID()))
->execute();
foreach ($atoms as $atom) {
$engine->destroyObject($atom);
}
$this->saveTransaction();
}

View file

@ -199,7 +199,8 @@ abstract class PhabricatorWorker extends Phobject {
}
$tasks = id(new PhabricatorWorkerArchiveTaskQuery())
->withIDs($task_ids);
->withIDs($task_ids)
->execute();
foreach ($tasks as $task) {
if ($task->getResult() != PhabricatorWorkerArchiveTask::RESULT_SUCCESS) {

View file

@ -198,10 +198,7 @@ final class PhabricatorMarkupEngine extends Phobject {
}
if (!isset($this->objects[$key]['output'])) {
throw new Exception(
pht(
'Call %s before using results.',
'process()'));
throw new PhutilInvalidStateException('process');
}
}

View file

@ -45,34 +45,57 @@ final class PhabricatorStorageManagementProbeWorkflow
}
}
$console->writeOut("%s\n", pht('APPROXIMATE TABLE SIZES'));
asort($totals);
$table = id(new PhutilConsoleTable())
->setShowHeader(false)
->setPadding(2)
->addColumn('name', array('title' => pht('Database / Table')))
->addColumn('size', array('title' => pht('Size')))
->addColumn('percentage', array('title' => pht('Percentage')));
foreach ($totals as $db => $size) {
$database_size = $this->formatSize($totals[$db], $overall);
$console->writeOut(
"**%s**\n",
sprintf('%-32.32s %18s', $db, $database_size));
list($database_size, $database_percentage) = $this->formatSize(
$totals[$db],
$overall);
$table->addRow(array(
'name' => phutil_console_format('**%s**', $db),
'size' => phutil_console_format('**%s**', $database_size),
'percentage' => phutil_console_format('**%s**', $database_percentage),
));
$data[$db] = isort($data[$db], '_totalSize');
foreach ($data[$db] as $table => $info) {
$table_size = $this->formatSize($info['_totalSize'], $overall);
$console->writeOut(
"%s\n",
sprintf(' %-28.28s %18s', $table, $table_size));
foreach ($data[$db] as $table_name => $info) {
list($table_size, $table_percentage) = $this->formatSize(
$info['_totalSize'],
$overall);
$table->addRow(array(
'name' => ' '.$table_name,
'size' => $table_size,
'percentage' => $table_percentage,
));
}
}
$overall_size = $this->formatSize($overall, $overall);
$console->writeOut(
"**%s**\n",
sprintf('%-32.32s %18s', pht('TOTAL'), $overall_size));
list($overall_size, $overall_percentage) = $this->formatSize(
$overall,
$overall);
$table->addRow(array(
'name' => phutil_console_format('**%s**', pht('TOTAL')),
'size' => phutil_console_format('**%s**', $overall_size),
'percentage' => phutil_console_format('**%s**', $overall_percentage),
));
$table->draw();
return 0;
}
private function formatSize($n, $o) {
return sprintf(
'%8.8s MB %5.5s%%',
number_format($n / (1024 * 1024), 1),
sprintf('%3.1f', 100 * ($n / $o)));
return array(
sprintf('%8.8s MB', number_format($n / (1024 * 1024), 1)),
sprintf('%3.1f%%', 100 * ($n / $o)),
);
}
}

View file

@ -137,19 +137,13 @@ final class AphrontFormDateControl extends AphrontFormControl {
}
private function getTimeFormat() {
$viewer = $this->getUser();
$preferences = $viewer->loadPreferences();
$pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
return $preferences->getPreference($pref_time_format, 'g:i A');
return $this->getUser()
->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
}
private function getDateFormat() {
$viewer = $this->getUser();
$preferences = $viewer->loadPreferences();
$pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
return $preferences->getPreference($pref_date_format, 'Y-m-d');
return $this->getUser()
->getPreference(PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT);
}
private function getTimeInputValue() {

View file

@ -10,7 +10,6 @@ final class AphrontFormDateControlValue extends Phobject {
private $zone;
private $optional;
public function getValueDate() {
return $this->valueDate;
}
@ -56,6 +55,10 @@ final class AphrontFormDateControlValue extends Phobject {
return $this->optional;
}
public function getViewer() {
return $this->viewer;
}
public static function newFromParts(
PhabricatorUser $viewer,
$year,
@ -71,8 +74,7 @@ final class AphrontFormDateControlValue extends Phobject {
$year,
$month,
$day,
coalesce($time, '12:00 AM'),
$value);
coalesce($time, '12:00 AM'));
$value->valueEnabled = $enabled;
return $value;
@ -85,8 +87,7 @@ final class AphrontFormDateControlValue extends Phobject {
list($value->valueDate, $value->valueTime) =
$value->getFormattedDateFromDate(
$request->getStr($key.'_d'),
$request->getStr($key.'_t'),
$value);
$request->getStr($key.'_t'));
$value->valueEnabled = $request->getStr($key.'_e');
return $value;
@ -108,8 +109,7 @@ final class AphrontFormDateControlValue extends Phobject {
$year,
$month,
$day,
$time,
$value);
$time);
return $value;
}
@ -123,8 +123,7 @@ final class AphrontFormDateControlValue extends Phobject {
list($value->valueDate, $value->valueTime) =
$value->getFormattedDateFromDate(
idx($dictionary, 'd'),
idx($dictionary, 't'),
$value);
idx($dictionary, 't'));
$value->valueEnabled = idx($dictionary, 'e');
@ -205,29 +204,25 @@ final class AphrontFormDateControlValue extends Phobject {
}
private function getTimeFormat() {
$preferences = $this->viewer->loadPreferences();
$pref_time_format = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
return $preferences->getPreference($pref_time_format, 'g:i A');
return $this->getViewer()
->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
}
private function getDateFormat() {
$preferences = $this->viewer->loadPreferences();
$pref_date_format = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
return $preferences->getPreference($pref_date_format, 'Y-m-d');
return $this->getViewer()
->getPreference(PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT);
}
private function getFormattedDateFromDate($date, $time, $value) {
private function getFormattedDateFromDate($date, $time) {
$original_input = $date;
$zone = $value->getTimezone();
$separator = $value->getFormatSeparator();
$zone = $this->getTimezone();
$separator = $this->getFormatSeparator();
$parts = preg_split('@[,./:-]@', $date);
$date = implode($separator, $parts);
$date = id(new DateTime($date, $zone));
if ($date) {
$date = $date->format($value->getDateFormat());
$date = $date->format($this->getDateFormat());
} else {
$date = $original_input;
}
@ -235,8 +230,8 @@ final class AphrontFormDateControlValue extends Phobject {
$date = id(new DateTime("{$date} {$time}", $zone));
return array(
$date->format($value->getDateFormat()),
$date->format($value->getTimeFormat()),
$date->format($this->getDateFormat()),
$date->format($this->getTimeFormat()),
);
}
@ -244,14 +239,14 @@ final class AphrontFormDateControlValue extends Phobject {
$year,
$month,
$day,
$time,
$value) {
$zone = $value->getTimezone();
$time) {
$zone = $this->getTimezone();
$date_time = id(new DateTime("{$year}-{$month}-{$day} {$time}", $zone));
return array(
$date_time->format($value->getDateFormat()),
$date_time->format($value->getTimeFormat()),
$date_time->format($this->getDateFormat()),
$date_time->format($this->getTimeFormat()),
);
}

View file

@ -162,10 +162,10 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
protected function renderInput() {
if (!$this->object) {
throw new Exception(pht('Call setPolicyObject() before rendering!'));
throw new PhutilInvalidStateException('setPolicyObject');
}
if (!$this->capability) {
throw new Exception(pht('Call setCapability() before rendering!'));
throw new PhutilInvalidStateException('setCapability');
}
$policy = $this->object->getPolicy($this->capability);

View file

@ -109,8 +109,11 @@ final class AphrontFormTokenizerControl extends AphrontFormControl {
if (!$viewer) {
throw new Exception(
pht(
'Call setUser() before rendering tokenizers. Use appendControl() '.
'on AphrontFormView to do this easily.'));
'Call %s before rendering tokenizers. '.
'Use %s on %s to do this easily.',
'setUser()',
'appendControl()',
'AphrontFormView'));
}
$values = nonempty($this->getValue(), array());

View file

@ -187,10 +187,10 @@ final class AphrontSideNavFilterView extends AphrontView {
public function render() {
if ($this->menu->getItems()) {
if (!$this->baseURI) {
throw new Exception(pht('Call setBaseURI() before render()!'));
throw new PhutilInvalidStateException('setBaseURI');
}
if ($this->selectedFilter === false) {
throw new Exception(pht('Call selectFilter() before render()!'));
throw new PhutilInvalidStateException('selectFilter');
}
}

View file

@ -29,7 +29,7 @@ final class PhabricatorActionListView extends AphrontView {
public function render() {
if (!$this->user) {
throw new Exception(pht('Call setUser() before render()!'));
throw new PhutilInvalidStateException('setUser');
}
$event = new PhabricatorEvent(

View file

@ -144,7 +144,7 @@ final class PHUITagView extends AphrontTagView {
protected function getTagContent() {
if (!$this->type) {
throw new Exception(pht('You must call setType() before render()!'));
throw new PhutilInvalidStateException('setType', 'render');
}
$color = null;

View file

@ -141,11 +141,8 @@ final class PHUICalendarListView extends AphrontTagView {
}
private function getEventTooltip(AphrontCalendarEventView $event) {
$viewer = $this->getUser();
$preferences = $viewer->loadPreferences();
$time_pref = $preferences->getPreference(
PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT,
'g:i A');
$time_pref = $this->getUser()
->getPreference(PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
Javelin::initBehavior('phabricator-tooltips');

View file

@ -31,32 +31,21 @@ function phabricator_relative_date($epoch, $user, $on = false) {
}
function phabricator_time($epoch, $user) {
$time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
return phabricator_format_local_time(
$epoch,
$user,
phabricator_time_format($user));
$user->getPreference($time_key));
}
function phabricator_datetime($epoch, $user) {
$time_key = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
return phabricator_format_local_time(
$epoch,
$user,
pht('%s, %s',
phutil_date_format($epoch),
phabricator_time_format($user)));
}
function phabricator_time_format($user) {
$prefs = $user->loadPreferences();
$pref = $prefs->getPreference(
PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT);
if (strlen($pref)) {
return $pref;
}
return pht('g:i A');
$user->getPreference($time_key)));
}
/**

View file

@ -99,8 +99,20 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
} else {
sel = [def];
}
sel = sel.join('\n' + ch);
return sel;
if (ch === '>') {
for(var i=0; i < sel.length; i++) {
if (sel[i][0] === '>') {
ch = '>';
} else {
ch = '> ';
}
sel[i] = ch + sel[i];
}
return sel.join('\n');
}
return sel.join('\n' + ch);
}
function assist(area, action, root) {
@ -141,9 +153,9 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
update(area, code_prefix + '```\n', sel, '\n```');
break;
case 'fa-quote-right':
ch = '> ';
ch = '>';
sel = prepend_char_to_lines(ch, sel, pht('Quoted Text'));
update(area, ((r.start === 0) ? '' : '\n\n') + ch, sel, '\n\n');
update(area, ((r.start === 0) ? '' : '\n\n'), sel, '\n\n');
break;
case 'fa-table':
var table_prefix = (r.start === 0 ? '' : '\n\n');