From df0c3df3cc6dbaa151e1b32ff4e01052eb3dad3e Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 12 Mar 2013 23:30:03 -0700 Subject: [PATCH] Modernize Maniphest Summary: A few things - pht Maniphest where I could - implement dust background - optimize pages for mobile - adds aphront-two-column-layout - reworks maniphest page with two column layout - tweaks task table for mobile, though we should move to object-list-view Stopping here as I want to get feedback in. Super excited about mobile and the new tasks views. Only sort of excited about the sidebar filters, they need more UI work, but we should talk about that. Test Plan: Test Maniphest, Differential, and Homepage views. Sort tasks, make reports Reviewers: epriestley, btrahan Reviewed By: btrahan CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D5314 --- src/__celerity_resource_map__.php | 106 +++++++------- .../DifferentialRevisionListController.php | 2 + .../ManiphestBatchEditController.php | 13 +- .../controller/ManiphestController.php | 42 +++--- .../controller/ManiphestExportController.php | 46 ++++--- .../controller/ManiphestReportController.php | 70 +++++----- .../ManiphestSavedQueryDeleteController.php | 10 +- .../ManiphestSavedQueryEditController.php | 19 +-- .../ManiphestSavedQueryListController.php | 19 +-- .../ManiphestTaskDetailController.php | 34 ++--- .../ManiphestTaskEditController.php | 18 ++- .../ManiphestTaskListController.php | 130 ++++++++++-------- .../view/ManiphestTaskSummaryView.php | 98 ++++++++----- src/view/form/AphrontFormView.php | 8 +- src/view/layout/AphrontListFilterView.php | 12 +- webroot/rsrc/css/aphront/form-view.css | 46 +------ webroot/rsrc/css/aphront/list-filter-view.css | 19 ++- .../application/maniphest/task-summary.css | 105 +++++++------- webroot/rsrc/css/core/buttons.css | 25 ++-- .../rsrc/image/texture/dust_background.jpg | Bin 6827 -> 7947 bytes 20 files changed, 432 insertions(+), 390 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 8bb0f74731..ef2496b135 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -569,8 +569,8 @@ celerity_register_resource_map(array( ), '/rsrc/image/texture/dust_background.jpg' => array( - 'hash' => 'c32ab9819d4af583f5609bbd3750721a', - 'uri' => '/res/c32ab981/rsrc/image/texture/dust_background.jpg', + 'hash' => '1ff330c03712e08ca2eed006ccc6c1e7', + 'uri' => '/res/1ff330c0/rsrc/image/texture/dust_background.jpg', 'disk' => '/rsrc/image/texture/dust_background.jpg', 'type' => 'jpg', ), @@ -683,7 +683,7 @@ celerity_register_resource_map(array( ), 'aphront-form-view-css' => array( - 'uri' => '/res/efaecc2d/rsrc/css/aphront/form-view.css', + 'uri' => '/res/accfc3a4/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( @@ -692,7 +692,7 @@ celerity_register_resource_map(array( ), 'aphront-list-filter-view-css' => array( - 'uri' => '/res/e783d6e1/rsrc/css/aphront/list-filter-view.css', + 'uri' => '/res/cc6e940e/rsrc/css/aphront/list-filter-view.css', 'type' => 'css', 'requires' => array( @@ -828,7 +828,7 @@ celerity_register_resource_map(array( ), 'conpherence-widget-pane-css' => array( - 'uri' => '/res/e67ad581/rsrc/css/application/conpherence/widget-pane.css', + 'uri' => '/res/2b4113f7/rsrc/css/application/conpherence/widget-pane.css', 'type' => 'css', 'requires' => array( @@ -2591,7 +2591,7 @@ celerity_register_resource_map(array( ), 'maniphest-task-summary-css' => array( - 'uri' => '/res/14e825ce/rsrc/css/application/maniphest/task-summary.css', + 'uri' => '/res/b3930263/rsrc/css/application/maniphest/task-summary.css', 'type' => 'css', 'requires' => array( @@ -2708,7 +2708,7 @@ celerity_register_resource_map(array( ), 'phabricator-core-buttons-css' => array( - 'uri' => '/res/7320ca6d/rsrc/css/core/buttons.css', + 'uri' => '/res/4e6b94c8/rsrc/css/core/buttons.css', 'type' => 'css', 'requires' => array( @@ -2717,7 +2717,7 @@ celerity_register_resource_map(array( ), 'phabricator-core-css' => array( - 'uri' => '/res/1e7afaa9/rsrc/css/core/core.css', + 'uri' => '/res/9df0488c/rsrc/css/core/core.css', 'type' => 'css', 'requires' => array( @@ -3562,7 +3562,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - 'b481b309' => + '4a549b8b' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3605,7 +3605,7 @@ celerity_register_resource_map(array( 35 => 'phabricator-object-item-list-view-css', 36 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/b481b309/core.pkg.css', + 'uri' => '/res/pkg/4a549b8b/core.pkg.css', 'type' => 'css', ), '95ceba95' => @@ -3765,7 +3765,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/cd1d650a/javelin.pkg.js', 'type' => 'js', ), - 'eb35a026' => + 'c41b4907' => array( 'name' => 'maniphest.pkg.css', 'symbols' => @@ -3775,7 +3775,7 @@ celerity_register_resource_map(array( 2 => 'aphront-attached-file-view-css', 3 => 'phabricator-project-tag-css', ), - 'uri' => '/res/pkg/eb35a026/maniphest.pkg.css', + 'uri' => '/res/pkg/c41b4907/maniphest.pkg.css', 'type' => 'css', ), '7707de41' => @@ -3795,18 +3795,18 @@ celerity_register_resource_map(array( ), 'reverse' => array( - 'aphront-attached-file-view-css' => 'eb35a026', - 'aphront-crumbs-view-css' => 'b481b309', - 'aphront-dialog-view-css' => 'b481b309', - 'aphront-error-view-css' => 'b481b309', - 'aphront-form-view-css' => 'b481b309', - 'aphront-list-filter-view-css' => 'b481b309', - 'aphront-pager-view-css' => 'b481b309', - 'aphront-panel-view-css' => 'b481b309', - 'aphront-table-view-css' => 'b481b309', - 'aphront-tokenizer-control-css' => 'b481b309', - 'aphront-tooltip-css' => 'b481b309', - 'aphront-typeahead-control-css' => 'b481b309', + 'aphront-attached-file-view-css' => 'c41b4907', + 'aphront-crumbs-view-css' => '4a549b8b', + 'aphront-dialog-view-css' => '4a549b8b', + 'aphront-error-view-css' => '4a549b8b', + 'aphront-form-view-css' => '4a549b8b', + 'aphront-list-filter-view-css' => '4a549b8b', + 'aphront-pager-view-css' => '4a549b8b', + 'aphront-panel-view-css' => '4a549b8b', + 'aphront-table-view-css' => '4a549b8b', + 'aphront-tokenizer-control-css' => '4a549b8b', + 'aphront-tooltip-css' => '4a549b8b', + 'aphront-typeahead-control-css' => '4a549b8b', 'differential-changeset-view-css' => '8aaacd1b', 'differential-core-view-css' => '8aaacd1b', 'differential-inline-comment-editor' => '322728f3', @@ -3820,7 +3820,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => '8aaacd1b', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => 'b481b309', + 'global-drag-and-drop-css' => '4a549b8b', 'inline-comment-summary-css' => '8aaacd1b', 'javelin-aphlict' => '95ceba95', 'javelin-behavior' => 'cd1d650a', @@ -3892,48 +3892,48 @@ celerity_register_resource_map(array( 'javelin-util' => 'cd1d650a', 'javelin-vector' => 'cd1d650a', 'javelin-workflow' => 'cd1d650a', - 'lightbox-attachment-css' => 'b481b309', - 'maniphest-task-summary-css' => 'eb35a026', - 'maniphest-transaction-detail-css' => 'eb35a026', + 'lightbox-attachment-css' => '4a549b8b', + 'maniphest-task-summary-css' => 'c41b4907', + 'maniphest-transaction-detail-css' => 'c41b4907', 'phabricator-busy' => '95ceba95', 'phabricator-content-source-view-css' => '8aaacd1b', - 'phabricator-core-buttons-css' => 'b481b309', - 'phabricator-core-css' => 'b481b309', - 'phabricator-crumbs-view-css' => 'b481b309', - 'phabricator-directory-css' => 'b481b309', + 'phabricator-core-buttons-css' => '4a549b8b', + 'phabricator-core-css' => '4a549b8b', + 'phabricator-crumbs-view-css' => '4a549b8b', + 'phabricator-directory-css' => '4a549b8b', 'phabricator-drag-and-drop-file-upload' => '322728f3', 'phabricator-dropdown-menu' => '95ceba95', 'phabricator-file-upload' => '95ceba95', - 'phabricator-filetree-view-css' => 'b481b309', - 'phabricator-flag-css' => 'b481b309', - 'phabricator-form-view-css' => 'b481b309', - 'phabricator-header-view-css' => 'b481b309', - 'phabricator-jump-nav' => 'b481b309', + 'phabricator-filetree-view-css' => '4a549b8b', + 'phabricator-flag-css' => '4a549b8b', + 'phabricator-form-view-css' => '4a549b8b', + 'phabricator-header-view-css' => '4a549b8b', + 'phabricator-jump-nav' => '4a549b8b', 'phabricator-keyboard-shortcut' => '95ceba95', 'phabricator-keyboard-shortcut-manager' => '95ceba95', - 'phabricator-main-menu-view' => 'b481b309', + 'phabricator-main-menu-view' => '4a549b8b', 'phabricator-menu-item' => '95ceba95', - 'phabricator-nav-view-css' => 'b481b309', + 'phabricator-nav-view-css' => '4a549b8b', 'phabricator-notification' => '95ceba95', - 'phabricator-notification-css' => 'b481b309', - 'phabricator-notification-menu-css' => 'b481b309', - 'phabricator-object-item-list-view-css' => 'b481b309', + 'phabricator-notification-css' => '4a549b8b', + 'phabricator-notification-menu-css' => '4a549b8b', + 'phabricator-object-item-list-view-css' => '4a549b8b', 'phabricator-object-selector-css' => '8aaacd1b', 'phabricator-paste-file-upload' => '95ceba95', 'phabricator-prefab' => '95ceba95', - 'phabricator-project-tag-css' => 'eb35a026', - 'phabricator-remarkup-css' => 'b481b309', + 'phabricator-project-tag-css' => 'c41b4907', + 'phabricator-remarkup-css' => '4a549b8b', 'phabricator-shaped-request' => '322728f3', - 'phabricator-side-menu-view-css' => 'b481b309', - 'phabricator-standard-page-view' => 'b481b309', + 'phabricator-side-menu-view-css' => '4a549b8b', + 'phabricator-standard-page-view' => '4a549b8b', 'phabricator-textareautils' => '95ceba95', 'phabricator-tooltip' => '95ceba95', - 'phabricator-transaction-view-css' => 'b481b309', - 'phabricator-zindex-css' => 'b481b309', - 'sprite-apps-large-css' => 'b481b309', - 'sprite-gradient-css' => 'b481b309', - 'sprite-icon-css' => 'b481b309', - 'sprite-menu-css' => 'b481b309', - 'syntax-highlighting-css' => 'b481b309', + 'phabricator-transaction-view-css' => '4a549b8b', + 'phabricator-zindex-css' => '4a549b8b', + 'sprite-apps-large-css' => '4a549b8b', + 'sprite-gradient-css' => '4a549b8b', + 'sprite-icon-css' => '4a549b8b', + 'sprite-menu-css' => '4a549b8b', + 'syntax-highlighting-css' => '4a549b8b', ), )); diff --git a/src/applications/differential/controller/DifferentialRevisionListController.php b/src/applications/differential/controller/DifferentialRevisionListController.php index 35bc3fb802..ad1be4bf00 100644 --- a/src/applications/differential/controller/DifferentialRevisionListController.php +++ b/src/applications/differential/controller/DifferentialRevisionListController.php @@ -162,6 +162,7 @@ final class DifferentialRevisionListController extends DifferentialController { $filter_form = id(new AphrontFormView()) ->setMethod('GET') + ->setNoShading(true) ->setAction('/differential/filter/'.$this->filter.'/') ->setUser($user); foreach ($controls as $control) { @@ -199,6 +200,7 @@ final class DifferentialRevisionListController extends DifferentialController { $side_nav, array( 'title' => pht('Differential Home'), + 'dust' => true, )); } diff --git a/src/applications/maniphest/controller/ManiphestBatchEditController.php b/src/applications/maniphest/controller/ManiphestBatchEditController.php index 7ecd0db24c..e73c632bdf 100644 --- a/src/applications/maniphest/controller/ManiphestBatchEditController.php +++ b/src/applications/maniphest/controller/ManiphestBatchEditController.php @@ -60,11 +60,11 @@ final class ManiphestBatchEditController extends ManiphestController { 'sources' => array( 'project' => array( 'src' => '/typeahead/common/projects/', - 'placeholder' => 'Type a project name...', + 'placeholder' => pht('Type a project name...'), ), 'owner' => array( 'src' => '/typeahead/common/searchowner/', - 'placeholder' => 'Type a user name...', + 'placeholder' => pht('Type a user name...'), 'limit' => 1, ), ), @@ -96,7 +96,8 @@ final class ManiphestBatchEditController extends ManiphestController { 'name' => 'actions', 'id' => 'batch-form-actions', ))); - $form->appendChild(phutil_tag('p', array(), 'These tasks will be edited:')); + $form->appendChild( + phutil_tag('p', array(), pht('These tasks will be edited:'))); $form->appendChild($list); $form->appendChild( id(new AphrontFormInsetView()) @@ -109,7 +110,7 @@ final class ManiphestBatchEditController extends ManiphestController { 'sigil' => 'add-action', 'mustcapture' => true, ), - 'Add Another Action')) + pht('Add Another Action'))) ->setContent(javelin_tag( 'table', array( @@ -119,7 +120,7 @@ final class ManiphestBatchEditController extends ManiphestController { ''))) ->appendChild( id(new AphrontFormSubmitControl()) - ->setValue('Update Tasks') + ->setValue(pht('Update Tasks')) ->addCancelButton('/maniphest/', 'Done')); $panel->appendChild($form); @@ -128,7 +129,7 @@ final class ManiphestBatchEditController extends ManiphestController { return $this->buildStandardPageResponse( $panel, array( - 'title' => 'Batch Editor', + 'title' => pht('Batch Editor'), )); } diff --git a/src/applications/maniphest/controller/ManiphestController.php b/src/applications/maniphest/controller/ManiphestController.php index 9439fe8c77..c93a248c89 100644 --- a/src/applications/maniphest/controller/ManiphestController.php +++ b/src/applications/maniphest/controller/ManiphestController.php @@ -10,7 +10,7 @@ abstract class ManiphestController extends PhabricatorController { public function buildStandardPageResponse($view, array $data) { $page = $this->buildStandardPageView(); - $page->setApplicationName('Maniphest'); + $page->setApplicationName(pht('Maniphest')); $page->setBaseURI('/maniphest/'); $page->setTitle(idx($data, 'title')); $page->setGlyph("\xE2\x9A\x93"); @@ -22,7 +22,7 @@ abstract class ManiphestController extends PhabricatorController { return $response->setContent($page->render()); } - protected function buildBaseSideNav() { + protected function buildBaseSideNav($filter = null, $for_app = false) { $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/maniphest/view/')); @@ -50,28 +50,36 @@ abstract class ManiphestController extends PhabricatorController { $query->getName(), '/maniphest/view/custom/?key='.$query->getQueryKey()); } - $nav->addFilter('saved', 'Edit...', '/maniphest/custom/'); + $nav->addFilter('saved', pht('Edit...'), '/maniphest/custom/'); } - $nav->addLabel('User Tasks'); - $nav->addFilter('action', 'Assigned'); - $nav->addFilter('created', 'Created'); - $nav->addFilter('subscribed', 'Subscribed'); - $nav->addFilter('triage', 'Need Triage'); - $nav->addLabel('User Projects'); - $nav->addFilter('projecttriage', 'Need Triage'); - $nav->addFilter('projectall', 'All Tasks'); + if ($for_app) { + $nav->addFilter('', pht('Create Task'), + $this->getApplicationURI('task/create/')); + } + + $nav->addLabel(pht('User Tasks')); + $nav->addFilter('action', pht('Assigned')); + $nav->addFilter('created', pht('Created')); + $nav->addFilter('subscribed', pht('Subscribed')); + $nav->addFilter('triage', pht('Need Triage')); + $nav->addLabel(pht('User Projects')); + $nav->addFilter('projecttriage', pht('Need Triage')); + $nav->addFilter('projectall', pht('All Tasks')); $nav->addLabel('All Tasks'); - $nav->addFilter('alltriage', 'Need Triage'); - $nav->addFilter('all', 'All Tasks'); - $nav->addLabel('Custom'); - $nav->addFilter('custom', 'Custom Query'); - $nav->addLabel('Reports'); - $nav->addFilter('report', 'Reports', '/maniphest/report/'); + $nav->addFilter('alltriage', pht('Need Triage')); + $nav->addFilter('all', pht('All Tasks')); + $nav->addLabel(pht('Custom')); + $nav->addFilter('custom', pht('Custom Query')); + $nav->addFilter('report', pht('Reports'), '/maniphest/report/'); return $nav; } + public function buildApplicationMenu() { + return $this->buildBaseSideNav(null, true)->getMenu(); + } + protected function getDefaultQuery() { return $this->defaultQuery; } diff --git a/src/applications/maniphest/controller/ManiphestExportController.php b/src/applications/maniphest/controller/ManiphestExportController.php index d3a22a9a42..1fc4988850 100644 --- a/src/applications/maniphest/controller/ManiphestExportController.php +++ b/src/applications/maniphest/controller/ManiphestExportController.php @@ -27,18 +27,26 @@ final class ManiphestExportController extends ManiphestController { $dialog = new AphrontDialogView(); $dialog->setUser($user); - $dialog->setTitle('Excel Export Not Configured'); - $dialog->appendChild(hsprintf( - '

This system does not have PHPExcel installed. This software '. + $inst1 = pht( + 'This system does not have PHPExcel installed. This software '. 'component is required to export tasks to Excel. Have your system '. - 'administrator install it from:

'. + 'administrator install it from:'); + + $inst2 = pht( + 'Your PHP "include_path" needs to be updated to include the '. + 'PHPExcel Classes directory.'); + + $dialog->setTitle(pht('Excel Export Not Configured')); + $dialog->appendChild(hsprintf( + '

%s

'. '
'. '

'. 'http://www.phpexcel.net/'. '

'. '
'. - '

Your PHP "include_path" needs to be updated to include the '. - 'PHPExcel Classes/ directory.

')); + '

%s

', + $inst1, + $inst2)); $dialog->addCancelButton('/maniphest/'); return id(new AphrontDialogResponse())->setDialog($dialog); @@ -58,12 +66,12 @@ final class ManiphestExportController extends ManiphestController { $dialog = new AphrontDialogView(); $dialog->setUser($user); - $dialog->setTitle('Export Tasks to Excel'); + $dialog->setTitle(pht('Export Tasks to Excel')); $dialog->appendChild(phutil_tag('p', array(), pht( 'Do you want to export the query results to Excel?'))); $dialog->addCancelButton('/maniphest/'); - $dialog->addSubmitButton('Export to Excel'); + $dialog->addSubmitButton(pht('Export to Excel')); return id(new AphrontDialogResponse())->setDialog($dialog); } @@ -85,7 +93,7 @@ final class ManiphestExportController extends ManiphestController { $workbook = new PHPExcel(); $sheet = $workbook->setActiveSheetIndex(0); - $sheet->setTitle('Tasks'); + $sheet->setTitle(pht('Tasks')); $widths = array( null, @@ -113,16 +121,16 @@ final class ManiphestExportController extends ManiphestController { $rows = array(); $rows[] = array( - 'ID', - 'Owner', - 'Status', - 'Priority', - 'Date Created', - 'Date Updated', - 'Title', - 'Projects', - 'URI', - 'Description', + pht('ID'), + pht('Owner'), + pht('Status'), + pht('Priority'), + pht('Date Created'), + pht('Date Updated'), + pht('Title'), + pht('Projects'), + pht('URI'), + pht('Description'), ); $is_date = array( diff --git a/src/applications/maniphest/controller/ManiphestReportController.php b/src/applications/maniphest/controller/ManiphestReportController.php index b5a1baf73d..ff5f6ba1f3 100644 --- a/src/applications/maniphest/controller/ManiphestReportController.php +++ b/src/applications/maniphest/controller/ManiphestReportController.php @@ -34,11 +34,11 @@ final class ManiphestReportController extends ManiphestController { $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/maniphest/report/')); - $nav->addLabel('Open Tasks'); - $nav->addFilter('user', 'By User'); - $nav->addFilter('project', 'By Project'); - $nav->addLabel('Burnup'); - $nav->addFilter('burn', 'Burnup Rate'); + $nav->addLabel(pht('Open Tasks')); + $nav->addFilter('user', pht('By User')); + $nav->addFilter('project', pht('By Project')); + $nav->addLabel(pht('Burnup')); + $nav->addFilter('burn', pht('Burnup Rate')); $this->view = $nav->selectFilter($this->view, 'user'); @@ -210,20 +210,20 @@ final class ManiphestReportController extends ManiphestController { if ($week) { $rows[] = $this->formatBurnRow( - 'Week To Date', + pht('Week To Date'), $week); $rowc[] = 'week'; } if ($month) { $rows[] = $this->formatBurnRow( - 'Month To Date', + pht('Month To Date'), $month); $rowc[] = 'month'; } $rows[] = $this->formatBurnRow( - 'All Time', + pht('All Time'), $period); $rowc[] = 'aggregate'; @@ -234,10 +234,10 @@ final class ManiphestReportController extends ManiphestController { $table->setRowClasses($rowc); $table->setHeaders( array( - 'Period', - 'Opened', - 'Closed', - 'Change', + pht('Period'), + pht('Opened'), + pht('Closed'), + pht('Change'), )); $table->setColumnClasses( array( @@ -248,16 +248,17 @@ final class ManiphestReportController extends ManiphestController { )); if ($handle) { - $header = pht("Task Burn Rate for Project %s", $handle->renderLink()); - $caption = hsprintf( - "

NOTE: This table reflects tasks currently in ". + $inst = pht( + "NOTE: This table reflects tasks currently in ". "the project. If a task was opened in the past but added to ". "the project recently, it is counted on the day it was ". "opened, not the day it was categorized. If a task was part ". "of this project in the past but no longer is, it is not ". - "counted at all.

"); + "counted at all."); + $header = pht("Task Burn Rate for Project %s", $handle->renderLink()); + $caption = hsprintf("

%s

", $inst); } else { - $header = "Task Burn Rate for All Tasks"; + $header = pht("Task Burn Rate for All Tasks"); $caption = null; } @@ -315,7 +316,7 @@ final class ManiphestReportController extends ManiphestController { ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/searchproject/') - ->setLabel('Project') + ->setLabel(pht('Project')) ->setLimit(1) ->setName('set_project') ->setValue($tokens)); @@ -325,10 +326,10 @@ final class ManiphestReportController extends ManiphestController { $form ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('"Recently" Means') + ->setLabel(pht('Recently Means')) ->setName('set_window') ->setCaption( - 'Configure the cutoff for the "Recently Closed" column.') + pht('Configure the cutoff for the "Recently Closed" column.')) ->setValue($window_str) ->setError($window_error)); } @@ -336,7 +337,7 @@ final class ManiphestReportController extends ManiphestController { $form ->appendChild( id(new AphrontFormSubmitControl()) - ->setValue('Filter By Project')); + ->setValue(pht('Filter By Project'))); $filter = new AphrontListFilterView(); $filter->appendChild($form); @@ -419,9 +420,9 @@ final class ManiphestReportController extends ManiphestController { array( 'href' => $base_link.ManiphestTaskOwner::OWNER_UP_FOR_GRABS, ), - phutil_tag('em', array(), '(Up For Grabs)')); - $col_header = 'User'; - $header = 'Open Tasks by User and Priority ('.$date.')'; + phutil_tag('em', array(), pht('(Up For Grabs)'))); + $col_header = pht('User'); + $header = pht('Open Tasks by User and Priority (%s)', $date); break; case 'project': $result = array(); @@ -456,9 +457,9 @@ final class ManiphestReportController extends ManiphestController { array( 'href' => $base_link.ManiphestTaskOwner::PROJECT_NO_PROJECT, ), - phutil_tag('em', array(), '(No Project)')); - $col_header = 'Project'; - $header = 'Open Tasks by Project and Priority ('.$date.')'; + phutil_tag('em', array(), pht('(No Project)'))); + $col_header = pht('Project'); + $header = pht('Open Tasks by Project and Priority (%s)', $date); break; } @@ -584,36 +585,37 @@ final class ManiphestReportController extends ManiphestController { array( 'sigil' => 'has-tooltip', 'meta' => array( - 'tip' => 'Oldest open task.', + 'tip' => pht('Oldest open task.'), 'size' => 200, ), ), - 'Oldest (All)'); + pht('Oldest (All)')); $cclass[] = 'n'; $cname[] = javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( - 'tip' => 'Oldest open task, excluding those with Low or Wishlist '. - 'priority.', + 'tip' => pht('Oldest open task, excluding those with Low or '. + 'Wishlist priority.'), 'size' => 200, ), ), - 'Oldest (Pri)'); + pht('Oldest (Pri)')); $cclass[] = 'n'; list($ignored, $window_epoch) = $this->getWindow(); + $edate = phabricator_datetime($window_epoch, $user); $cname[] = javelin_tag( 'span', array( 'sigil' => 'has-tooltip', 'meta' => array( - 'tip' => 'Closed after '.phabricator_datetime($window_epoch, $user), + 'tip' => pht('Closed after %s', $edate), 'size' => 260 ), ), - 'Recently Closed'); + pht('Recently Closed')); $cclass[] = 'n'; $table = new AphrontTableView($rows); diff --git a/src/applications/maniphest/controller/ManiphestSavedQueryDeleteController.php b/src/applications/maniphest/controller/ManiphestSavedQueryDeleteController.php index 9fae6869aa..c4fa4d9123 100644 --- a/src/applications/maniphest/controller/ManiphestSavedQueryDeleteController.php +++ b/src/applications/maniphest/controller/ManiphestSavedQueryDeleteController.php @@ -30,15 +30,17 @@ final class ManiphestSavedQueryDeleteController extends ManiphestController { } $name = $query->getName(); + $inst = pht( + 'Really delete the query "%s"? It will be lost forever!', $name); $dialog = id(new AphrontDialogView()) ->setUser($user) - ->setTitle('Really delete this query?') + ->setTitle(pht('Really delete this query?')) ->appendChild(hsprintf( - '

Really delete the query "%s"? It will be lost forever!

', - $name)) + '

%s

', + $inst)) ->addCancelButton('/maniphest/custom/') - ->addSubmitButton('Delete'); + ->addSubmitButton(pht('Delete')); return id(new AphrontDialogResponse())->setDialog($dialog); } diff --git a/src/applications/maniphest/controller/ManiphestSavedQueryEditController.php b/src/applications/maniphest/controller/ManiphestSavedQueryEditController.php index 8fd0e5b32d..fde8404934 100644 --- a/src/applications/maniphest/controller/ManiphestSavedQueryEditController.php +++ b/src/applications/maniphest/controller/ManiphestSavedQueryEditController.php @@ -42,8 +42,8 @@ final class ManiphestSavedQueryEditController extends ManiphestController { $e_name = null; $query->setName($request->getStr('name')); if (!strlen($query->getName())) { - $e_name = 'Required'; - $errors[] = 'Saved query name is required.'; + $e_name = pht('Required'); + $errors[] = pht('Saved query name is required.'); } if (!$errors) { @@ -54,17 +54,17 @@ final class ManiphestSavedQueryEditController extends ManiphestController { if ($errors) { $error_view = new AphrontErrorView(); - $error_view->setTitle('Form Errors'); + $error_view->setTitle(pht('Form Errors')); $error_view->setErrors($errors); } else { $error_view = null; } if ($query->getID()) { - $header = 'Edit Saved Query'; + $header = pht('Edit Saved Query'); $cancel_uri = '/maniphest/custom/'; } else { - $header = 'New Saved Query'; + $header = pht('New Saved Query'); $cancel_uri = '/maniphest/view/custom/?key='.$key; } @@ -74,14 +74,14 @@ final class ManiphestSavedQueryEditController extends ManiphestController { ->addHiddenInput('id', $query->getID()) ->appendChild( id(new AphrontFormTextControl()) - ->setLabel('Name') + ->setLabel(pht('Name')) ->setValue($query->getName()) ->setName('name') ->setError($e_name)) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) - ->setValue('Save')); + ->setValue(pht('Save'))); $panel = new AphrontPanelView(); $panel->setHeader($header); @@ -94,10 +94,11 @@ final class ManiphestSavedQueryEditController extends ManiphestController { $nav->appendChild($error_view); $nav->appendChild($panel); - return $this->buildStandardPageResponse( + return $this->buildApplicationPage( $nav, array( - 'title' => 'Saved Queries', + 'title' => pht('Saved Queries'), + 'device' => true, )); } diff --git a/src/applications/maniphest/controller/ManiphestSavedQueryListController.php b/src/applications/maniphest/controller/ManiphestSavedQueryListController.php index 2f80e6028d..c308739c3f 100644 --- a/src/applications/maniphest/controller/ManiphestSavedQueryListController.php +++ b/src/applications/maniphest/controller/ManiphestSavedQueryListController.php @@ -81,7 +81,7 @@ final class ManiphestSavedQueryListController extends ManiphestController { 'value' => 0, 'checked' => ($default === null ? 'checked' : null), )), - phutil_tag('em', array(), 'No Default'), + phutil_tag('em', array(), pht('No Default')), '', '', ); @@ -89,10 +89,10 @@ final class ManiphestSavedQueryListController extends ManiphestController { $table = new AphrontTableView($rows); $table->setHeaders( array( - 'Default', - 'Name', - 'Edit', - 'Delete', + pht('Default'), + pht('Name'), + pht('Edit'), + pht('Delete'), )); $table->setColumnClasses( array( @@ -103,12 +103,12 @@ final class ManiphestSavedQueryListController extends ManiphestController { )); $panel = new AphrontPanelView(); - $panel->setHeader('Saved Custom Queries'); + $panel->setHeader(pht('Saved Custom Queries')); $panel->addButton( phutil_tag( 'button', array(), - 'Save Default Query')); + pht('Save Default Query'))); $panel->appendChild($table); $form = phabricator_form( @@ -122,10 +122,11 @@ final class ManiphestSavedQueryListController extends ManiphestController { $nav->selectFilter('saved', 'saved'); $nav->appendChild($form); - return $this->buildStandardPageResponse( + return $this->buildApplicationPage( $nav, array( - 'title' => 'Saved Queries', + 'title' => pht('Saved Queries'), + 'device' => true, )); } diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index d90643cc0c..ad7bda8316 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -107,7 +107,7 @@ final class ManiphestTaskDetailController extends ManiphestController { 'href' => '/maniphest/task/create/?parent='.$parent_task->getID(), 'class' => 'green button', ), - 'Create Another Subtask')); + pht('Create Another Subtask'))); $context_bar->appendChild(hsprintf( 'Created a subtask of %s', $this->getHandle($parent_task->getPHID())->renderLink())); @@ -120,15 +120,15 @@ final class ManiphestTaskDetailController extends ManiphestController { 'href' => '/maniphest/task/create/?template='.$task->getID(), 'class' => 'green button', ), - 'Similar Task')); + pht('Similar Task'))); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/', 'class' => 'green button', ), - 'Empty Task')); - $context_bar->appendChild('New task created.'); + pht('Empty Task'))); + $context_bar->appendChild(pht('New task created.')); } $engine = new PhabricatorMarkupEngine(); @@ -201,20 +201,20 @@ final class ManiphestTaskDetailController extends ManiphestController { ->addHiddenInput('taskID', $task->getID()) ->appendChild( id(new AphrontFormSelectControl()) - ->setLabel('Action') + ->setLabel(pht('Action')) ->setName('action') ->setOptions($transaction_types) ->setID('transaction-action')) ->appendChild( id(new AphrontFormSelectControl()) - ->setLabel('Resolution') + ->setLabel(pht('Resolution')) ->setName('resolution') ->setControlID('resolution') ->setControlStyle('display: none') ->setOptions($resolution_types)) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setLabel('Assign To') + ->setLabel(pht('Assign To')) ->setName('assign_to') ->setControlID('assign_to') ->setControlStyle('display: none') @@ -222,7 +222,7 @@ final class ManiphestTaskDetailController extends ManiphestController { ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setLabel('CCs') + ->setLabel(pht('CCs')) ->setName('ccs') ->setControlID('ccs') ->setControlStyle('display: none') @@ -230,7 +230,7 @@ final class ManiphestTaskDetailController extends ManiphestController { ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormSelectControl()) - ->setLabel('Priority') + ->setLabel(pht('Priority')) ->setName('priority') ->setOptions($priority_map) ->setControlID('priority') @@ -238,7 +238,7 @@ final class ManiphestTaskDetailController extends ManiphestController { ->setValue($task->getPriority())) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setLabel('Projects') + ->setLabel(pht('Projects')) ->setName('projects') ->setControlID('projects') ->setControlStyle('display: none') @@ -246,25 +246,25 @@ final class ManiphestTaskDetailController extends ManiphestController { ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormFileControl()) - ->setLabel('File') + ->setLabel(pht('File')) ->setName('file') ->setControlID('file') ->setControlStyle('display: none')) ->appendChild( id(new PhabricatorRemarkupControl()) - ->setLabel('Comments') + ->setLabel(pht('Comments')) ->setName('comments') ->setValue($draft_text) ->setID('transaction-comments') ->setUser($user)) ->appendChild( id(new AphrontFormDragAndDropUploadControl()) - ->setLabel('Attached Files') + ->setLabel(pht('Attached Files')) ->setName('files') ->setActivatedClass('aphront-panel-view-drag-and-drop')) ->appendChild( id(new AphrontFormSubmitControl()) - ->setValue($is_serious ? 'Submit' : 'Avast!')); + ->setValue($is_serious ? pht('Submit') : pht('Avast!'))); $control_map = array( ManiphestTransactionType::TYPE_STATUS => 'resolution', @@ -280,7 +280,7 @@ final class ManiphestTaskDetailController extends ManiphestController { 'id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), - 'placeholder' => 'Type a project name...', + 'placeholder' => pht('Type a project name...'), ), ManiphestTransactionType::TYPE_OWNER => array( 'id' => 'assign-tokenizer', @@ -288,13 +288,13 @@ final class ManiphestTaskDetailController extends ManiphestController { 'value' => $default_claim, 'limit' => 1, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), - 'placeholder' => 'Type a user name...', + 'placeholder' => pht('Type a user name...'), ), ManiphestTransactionType::TYPE_CCS => array( 'id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), - 'placeholder' => 'Type a user or mailing list...', + 'placeholder' => pht('Type a user or mailing list...'), ), ); diff --git a/src/applications/maniphest/controller/ManiphestTaskEditController.php b/src/applications/maniphest/controller/ManiphestTaskEditController.php index 10e1e1a20b..77e4be866a 100644 --- a/src/applications/maniphest/controller/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/ManiphestTaskEditController.php @@ -112,15 +112,15 @@ final class ManiphestTaskEditController extends ManiphestController { $aux_field->setValueFromRequest($request); if ($aux_field->isRequired() && !$aux_field->getValue()) { - $errors[] = $aux_field->getLabel() . ' is required.'; - $aux_field->setError('Required'); + $errors[] = pht('%s is required.', $aux_field->getLabel()); + $aux_field->setError(pht('Required')); } try { $aux_field->validate(); } catch (Exception $e) { $errors[] = $e->getMessage(); - $aux_field->setError('Invalid'); + $aux_field->setError(pht('Invalid')); } } @@ -501,18 +501,22 @@ final class ManiphestTaskEditController extends ManiphestController { $panel->setHeader($header_name); $panel->appendChild($form); $panel->setNoBackground(); + $inst1 = pht('Description Preview'); + $inst2 = pht('Loading preview...'); $description_preview_panel = hsprintf( '
- Description Preview + %s
- Loading preview... + %s
-
'); + ', + $inst1, + $inst2); Javelin::initBehavior( 'maniphest-description-preview', @@ -537,7 +541,7 @@ final class ManiphestTaskEditController extends ManiphestController { array( 'title' => $header_name, 'pageObjects' => $page_objects, - 'device' => true + 'device' => true, )); } } diff --git a/src/applications/maniphest/controller/ManiphestTaskListController.php b/src/applications/maniphest/controller/ManiphestTaskListController.php index 42b6fc8cae..598c385341 100644 --- a/src/applications/maniphest/controller/ManiphestTaskListController.php +++ b/src/applications/maniphest/controller/ManiphestTaskListController.php @@ -120,6 +120,7 @@ final class ManiphestTaskListController extends ManiphestController { $form = id(new AphrontFormView()) ->setUser($user) + ->setNoShading(true) ->setAction( $request->getRequestURI() ->alter('key', null) @@ -142,7 +143,7 @@ final class ManiphestTaskListController extends ManiphestController { id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/searchowner/') ->setName('set_users') - ->setLabel('Users') + ->setLabel(pht('Users')) ->setValue($tokens)); } @@ -150,12 +151,12 @@ final class ManiphestTaskListController extends ManiphestController { $form->appendChild( id(new AphrontFormTextControl()) ->setName('set_search') - ->setLabel('Search') + ->setLabel(pht('Search')) ->setValue($search_text)); $form->appendChild( id(new AphrontFormTextControl()) ->setName('set_tasks') - ->setLabel('Task IDs') + ->setLabel(pht('Task IDs')) ->setValue(join(',', $task_ids))); $tokens = array(); @@ -166,7 +167,7 @@ final class ManiphestTaskListController extends ManiphestController { id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/searchowner/') ->setName('set_owners') - ->setLabel('Owners') + ->setLabel(pht('Owners')) ->setValue($tokens)); $tokens = array(); @@ -177,7 +178,7 @@ final class ManiphestTaskListController extends ManiphestController { id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/users/') ->setName('set_authors') - ->setLabel('Authors') + ->setLabel(pht('Authors')) ->setValue($tokens)); } @@ -189,14 +190,14 @@ final class ManiphestTaskListController extends ManiphestController { $caption = null; if ($this->view == 'custom') { - $caption = 'Find tasks in ALL of these projects ("AND" query).'; + $caption = pht('Find tasks in ALL of these projects ("AND" query).'); } $form->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/searchproject/') ->setName('set_projects') - ->setLabel('Projects') + ->setLabel(pht('Projects')) ->setCaption($caption) ->setValue($tokens)); } @@ -210,8 +211,8 @@ final class ManiphestTaskListController extends ManiphestController { id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/projects/') ->setName('set_aprojects') - ->setLabel('Any Projects') - ->setCaption('Find tasks in ANY of these projects ("OR" query).') + ->setLabel(pht('Any Projects')) + ->setCaption(pht('Find tasks in ANY of these projects ("OR" query).')) ->setValue($atokens)); $tokens = array(); @@ -222,8 +223,8 @@ final class ManiphestTaskListController extends ManiphestController { id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/projects/') ->setName('set_xprojects') - ->setLabel('Exclude Projects') - ->setCaption('Find tasks NOT in any of these projects.') + ->setLabel(pht('Exclude Projects')) + ->setCaption(pht('Find tasks NOT in any of these projects.')) ->setValue($tokens)); $priority = ManiphestTaskPriority::getLowestPriority(); @@ -233,7 +234,7 @@ final class ManiphestTaskListController extends ManiphestController { $form->appendChild( id(new AphrontFormSelectControl()) - ->setLabel('Min Priority') + ->setLabel(pht('Min Priority')) ->setName('set_lpriority') ->setValue($priority) ->setOptions(array_reverse( @@ -246,7 +247,7 @@ final class ManiphestTaskListController extends ManiphestController { $form->appendChild( id(new AphrontFormSelectControl()) - ->setLabel('Max Priority') + ->setLabel(pht('Max Priority')) ->setName('set_hpriority') ->setValue($priority) ->setOptions(ManiphestTaskPriority::getTaskPriorityMap())); @@ -259,7 +260,7 @@ final class ManiphestTaskListController extends ManiphestController { ->appendChild($this->renderOrderControl($q_order)); $submit = id(new AphrontFormSubmitControl()) - ->setValue('Filter Tasks'); + ->setValue(pht('Filter Tasks')); // Only show "Save..." for novel queries which have some kind of query // parameters set. @@ -268,7 +269,7 @@ final class ManiphestTaskListController extends ManiphestController { && $request->getRequestURI()->getQueryParams()) { $submit->addCancelButton( '/maniphest/custom/edit/?key='.$query->getQueryKey(), - 'Save Custom Query...'); + pht('Save Custom Query...')); } $form->appendChild($submit); @@ -285,8 +286,6 @@ final class ManiphestTaskListController extends ManiphestController { $filter->appendChild($form); } - $nav->appendChild($filter); - $have_tasks = false; foreach ($tasks as $group => $list) { if (count($list)) { @@ -302,10 +301,12 @@ final class ManiphestTaskListController extends ManiphestController { '
')); if (!$have_tasks) { + $no_tasks = pht('No matching tasks.'); $list_container->appendChild(hsprintf( '

'. - 'No matching tasks.'. - '

')); + '%s'. + '', + $no_tasks)); } else { $pager = new AphrontPagerView(); $pager->setURI($request->getRequestURI(), 'offset'); @@ -317,13 +318,16 @@ final class ManiphestTaskListController extends ManiphestController { $max = min($pager->getOffset() + $page_size, $total_count); $tot = $total_count; - $list_container->appendChild(hsprintf( - '
'. - "Displaying tasks %s - %s of %s.". - '
', + $results = pht('Displaying tasks %s - %s of %s.', number_format($cur), number_format($max), - number_format($tot))); + number_format($tot)); + $result_count = phutil_tag( + 'div', + array( + 'class' => 'maniphest-total-result-count' + ), + $results); $selector = new AphrontNullView(); @@ -333,8 +337,7 @@ final class ManiphestTaskListController extends ManiphestController { ($order == 'priority') && ($group == 'none' || $group == 'priority'); - $lists = new AphrontNullView(); - $lists->appendChild(hsprintf('
')); + $lists = array(); foreach ($tasks as $group => $list) { $task_list = new ManiphestTaskListView(); $task_list->setShowBatchControls(true); @@ -359,18 +362,19 @@ final class ManiphestTaskListController extends ManiphestController { ), $group.' ('.$count.')'); - - $panel = new AphrontPanelView(); - $panel->appendChild($header); - $panel->appendChild($task_list); - $panel->setNoBackground(); - - $lists->appendChild($panel); + $lists[] = + phutil_tag( + 'div', + array( + 'class' => 'maniphest-task-group' + ), + array( + $header, + $task_list, + )); } - $lists->appendChild(hsprintf('
')); + $selector->appendChild($lists); - - $selector->appendChild($this->renderBatchEditor($query)); $form_id = celerity_generate_unique_node_id(); @@ -394,7 +398,8 @@ final class ManiphestTaskListController extends ManiphestController { )); } - $list_container->appendChild(hsprintf('
')); + $nav->appendChild($filter); + $nav->appendChild($result_count); $nav->appendChild($list_container); $title = pht('Task List'); @@ -411,10 +416,12 @@ final class ManiphestTaskListController extends ManiphestController { $nav->setCrumbs($crumbs); - return $this->buildStandardPageResponse( + return $this->buildApplicationPage( $nav, array( 'title' => $title, + 'device' => true, + 'dust' => true, )); } @@ -653,7 +660,7 @@ final class ManiphestTaskListController extends ManiphestController { 'class' => 'grey button', 'id' => 'batch-select-all', ), - 'Select All'); + pht('Select All')); $select_none = javelin_tag( 'a', @@ -663,7 +670,7 @@ final class ManiphestTaskListController extends ManiphestController { 'class' => 'grey button', 'id' => 'batch-select-none', ), - 'Clear Selection'); + pht('Clear Selection')); $submit = phutil_tag( 'button', @@ -672,7 +679,7 @@ final class ManiphestTaskListController extends ManiphestController { 'disabled' => 'disabled', 'class' => 'disabled', ), - "Batch Edit Selected Tasks \xC2\xBB"); + pht("Batch Edit Selected \xC2\xBB")); $export = javelin_tag( 'a', @@ -680,22 +687,25 @@ final class ManiphestTaskListController extends ManiphestController { 'href' => '/maniphest/export/'.$search_query->getQueryKey().'/', 'class' => 'grey button', ), - 'Export Tasks to Excel...'); + pht('Export to Excel')); return hsprintf( '
'. - '
Batch Task Editor
'. + '
%s
'. ''. ''. ''. ''. - ''. + ''. ''. ''. '
%s%s%s0 Selected Tasks%s%s
'. '', - $select_all, $select_none, + pht('Batch Task Editor'), + $select_all, + $select_none, $export, + pht('0 Selected'), $submit); } @@ -871,35 +881,35 @@ final class ManiphestTaskListController extends ManiphestController { private function getStatusButtonMap() { return array( - 'o' => 'Open', - 'c' => 'Closed', - 'oc' => 'All', + 'o' => pht('Open'), + 'c' => pht('Closed'), + 'oc' => pht('All'), ); } private function getGroupButtonMap() { return array( - 'p' => 'Priority', - 'o' => 'Owner', - 's' => 'Status', - 'j' => 'Project', - 'n' => 'None', + 'p' => pht('Priority'), + 'o' => pht('Owner'), + 's' => pht('Status'), + 'j' => pht('Project'), + 'n' => pht('None'), ); } private function getOrderButtonMap() { return array( - 'p' => 'Priority', - 'u' => 'Updated', - 'c' => 'Created', - 't' => 'Title', + 'p' => pht('Priority'), + 'u' => pht('Updated'), + 'c' => pht('Created'), + 't' => pht('Title'), ); } public function renderStatusControl($value) { $request = $this->getRequest(); return id(new AphrontFormToggleButtonsControl()) - ->setLabel('Status') + ->setLabel(pht('Status')) ->setValue($this->getStatusRequestValue($value)) ->setBaseURI($request->getRequestURI(), $this->getStatusRequestKey()) ->setButtons($this->getStatusButtonMap()); @@ -908,7 +918,7 @@ final class ManiphestTaskListController extends ManiphestController { public function renderOrderControl($value) { $request = $this->getRequest(); return id(new AphrontFormToggleButtonsControl()) - ->setLabel('Order') + ->setLabel(pht('Order')) ->setValue($this->getOrderRequestValue($value)) ->setBaseURI($request->getRequestURI(), $this->getOrderRequestKey()) ->setButtons($this->getOrderButtonMap()); @@ -917,7 +927,7 @@ final class ManiphestTaskListController extends ManiphestController { public function renderGroupControl($value) { $request = $this->getRequest(); return id(new AphrontFormToggleButtonsControl()) - ->setLabel('Group') + ->setLabel(pht('Group')) ->setValue($this->getGroupRequestValue($value)) ->setBaseURI($request->getRequestURI(), $this->getGroupRequestKey()) ->setButtons($this->getGroupButtonMap()); diff --git a/src/applications/maniphest/view/ManiphestTaskSummaryView.php b/src/applications/maniphest/view/ManiphestTaskSummaryView.php index 6e7b13c7ea..6e67098ee5 100644 --- a/src/applications/maniphest/view/ManiphestTaskSummaryView.php +++ b/src/applications/maniphest/view/ManiphestTaskSummaryView.php @@ -63,6 +63,7 @@ final class ManiphestTaskSummaryView extends ManiphestView { $batch = phutil_tag( 'td', array( + 'rowspan' => 2, 'class' => 'maniphest-task-batch', ), javelin_tag( @@ -91,36 +92,14 @@ final class ManiphestTaskSummaryView extends ManiphestView { $handle = javelin_tag( 'td', array( + 'rowspan' => 2, 'class' => 'maniphest-task-handle '.$pri_class.' '.$control_class, 'sigil' => $control_sigil, ), ''); - $task_id = phutil_tag( - 'td', - array( - 'class' => 'maniphest-task-number', - ), - 'T'.$task->getID()); - - $task_status = phutil_tag( - 'td', - array( - 'class' => 'maniphest-task-status', - ), - idx($status_map, $task->getStatus(), 'Unknown')); - - $task_owner = phutil_tag( - 'td', - array( - 'class' => 'maniphest-task-owner', - ), - $task->getOwnerPHID() - ? $handles[$task->getOwnerPHID()]->renderLink() - : phutil_tag('em', array(), pht('None'))); - $task_name = phutil_tag( - 'td', + 'span', array( 'class' => 'maniphest-task-name', ), @@ -131,6 +110,50 @@ final class ManiphestTaskSummaryView extends ManiphestView { ), $task->getTitle())); + $task_updated = phutil_tag( + 'span', + array( + 'class' => 'maniphest-task-updated', + ), + phabricator_date($task->getDateModified(), $this->user)); + + $task_info = phutil_tag( + 'td', + array( + 'colspan' => 2, + 'class' => 'maniphest-task-number', + ), + array( + 'T'.$task->getID(), + $task_name, + $task_updated, + )); + + $owner = ''; + if ($handles[$task->getOwnerPHID()]) { + $owner = pht('Assigned to %s', + $handles[$task->getOwnerPHID()]->renderLink()); + } + + $task_owner = phutil_tag( + 'span', + array( + 'class' => 'maniphest-task-owner', + ), + $task->getOwnerPHID() + ? $owner + : phutil_tag('em', array(), pht('None'))); + + $task_status = phutil_tag( + 'td', + array( + 'class' => 'maniphest-task-status', + ), + array( + idx($status_map, $task->getStatus(), pht('Unknown')), + $task_owner, + )); + $task_projects = phutil_tag( 'td', array( @@ -138,25 +161,21 @@ final class ManiphestTaskSummaryView extends ManiphestView { ), $projects_view->render()); - $task_updated = phutil_tag( - 'td', - array( - 'class' => 'maniphest-task-updated', - ), - phabricator_date($task->getDateModified(), $this->user)); + $row1 = phutil_tag( + 'tr', + array(), + array( + $handle, + $batch, + $task_info, + )); - $row = phutil_tag( + $row2 = phutil_tag( 'tr', array(), array( - $handle, - $batch, - $task_id, $task_status, - $task_owner, - $task_name, $task_projects, - $task_updated, )); return javelin_tag( @@ -168,7 +187,10 @@ final class ManiphestTaskSummaryView extends ManiphestView { 'taskID' => $task->getID(), ), ), - $row); + array( + $row1, + $row2, + )); } } diff --git a/src/view/form/AphrontFormView.php b/src/view/form/AphrontFormView.php index 95e3bd2b74..8bc1c88f68 100644 --- a/src/view/form/AphrontFormView.php +++ b/src/view/form/AphrontFormView.php @@ -10,6 +10,7 @@ final class AphrontFormView extends AphrontView { private $workflow; private $id; private $flexible; + private $noShading; private $sigils = array(); public function setFlexible($flexible) { @@ -17,6 +18,11 @@ final class AphrontFormView extends AphrontView { return $this; } + public function setNoShading($shading) { + $this->noShading = $shading; + return $this; + } + public function setID($id) { $this->id = $id; return $this; @@ -60,7 +66,7 @@ final class AphrontFormView extends AphrontView { $layout = new AphrontFormLayoutView(); - if (!$this->flexible) { + if ((!$this->flexible) && (!$this->noShading)) { $layout ->setBackgroundShading(true) ->setPadded(true); diff --git a/src/view/layout/AphrontListFilterView.php b/src/view/layout/AphrontListFilterView.php index cca43fa770..7470e5a059 100644 --- a/src/view/layout/AphrontListFilterView.php +++ b/src/view/layout/AphrontListFilterView.php @@ -5,11 +5,13 @@ final class AphrontListFilterView extends AphrontView { public function render() { require_celerity_resource('aphront-list-filter-view-css'); return hsprintf( - ''. - ''. - ''. - ''. - '
%s
', + '
'. + ''. + ''. + ''. + ''. + '
%s
'. + '
', $this->renderChildren()); } diff --git a/webroot/rsrc/css/aphront/form-view.css b/webroot/rsrc/css/aphront/form-view.css index 299502a0fc..a4a88a6844 100644 --- a/webroot/rsrc/css/aphront/form-view.css +++ b/webroot/rsrc/css/aphront/form-view.css @@ -14,7 +14,6 @@ padding: 1em; } - .aphront-form-view label.aphront-form-label { padding-top: 4px; width: 19%; @@ -22,7 +21,7 @@ text-align: right; font-weight: bold; font-size: 13px; - color: #666666; + color: #666; } .device-phone .aphront-form-view label.aphront-form-label { @@ -30,6 +29,8 @@ float: none; text-align: left; width: 100%; + color: #777; + margin-bottom: 3px; } .aphront-form-input { @@ -159,7 +160,7 @@ } .aphront-form-control-togglebuttons .aphront-form-input { - padding-top: 5px; + padding: 2px 0 0 0; } table.aphront-form-control-radio-layout, @@ -368,42 +369,3 @@ table.aphront-form-control-checkbox-layout th { padding: 12px; float: right; } - -.aphront-form-control-counted-togglebuttons { - padding-top: 7px; -} - -.aphront-form-control-counted-togglebuttons .toggle { - position: relative; -} - -.aphront-form-control-counted-togglebuttons .toggle-fixed { - cursor: pointer; -} - -.aphront-form-control-counted-togglebuttons .toggle .counter { - font-size: smaller; - display: none; - position: absolute; - top: -9px; - right: -8px; - padding: 0px 3px; - border-radius: 3px; -} - -.aphront-form-control-counted-togglebuttons:hover .toggle .counter { - display: block; -} - -.aphront-form-control-counted-togglebuttons .toggle .counter { - background: gray; - color: #ddd; -} - -.aphront-form-control-counted-togglebuttons .toggle-selected .counter { - color: white; -} - -.aphront-form-control-counted-togglebuttons .toggle.disabled:hover { - background-color: #a7a7a7; -} diff --git a/webroot/rsrc/css/aphront/list-filter-view.css b/webroot/rsrc/css/aphront/list-filter-view.css index da6b24c987..2765482741 100644 --- a/webroot/rsrc/css/aphront/list-filter-view.css +++ b/webroot/rsrc/css/aphront/list-filter-view.css @@ -2,11 +2,23 @@ * @provides aphront-list-filter-view-css */ +.aphront-filter-table-wrapper { + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + border-bottom: 1px solid #c0c5d1; + margin: 0 20px; +} + +.device-phone .aphront-filter-table-wrapper { + margin: 0; + padding: 0; + background: #fff; +} + .aphront-list-filter-view { - background: #f4f5f8; - border-bottom: 1px solid #d4dae0; + background: #fff; width: 100%; - margin-bottom: 1em; + box-shadow: inset 0px 2px 1px rgba(150,150,150,0.25); } .aphront-list-filter-view-controls { @@ -15,6 +27,7 @@ .aphront-list-filter-view-controls .aphront-form-view { border-width: 0; + border-bottom: 1px solid #c0c5d1; padding: 12px 0 6px; } diff --git a/webroot/rsrc/css/application/maniphest/task-summary.css b/webroot/rsrc/css/application/maniphest/task-summary.css index 379a0c2fd9..4d0609d2c6 100644 --- a/webroot/rsrc/css/application/maniphest/task-summary.css +++ b/webroot/rsrc/css/application/maniphest/task-summary.css @@ -4,22 +4,19 @@ .maniphest-task-summary { width: 100%; - margin: 4px 0; + margin: 0 0 -1px 0; border-collapse: separate; - - font-size: 12px; color: #333; + border: 1px solid #c0c5d1; +} + +.maniphest-task-group { + padding-bottom: 30px; } .maniphest-task-summary td { - padding: 6px 4px; + padding: 0 10px; background: #fff; - white-space: nowrap; - - border-style: solid; - border-top-color: #d5dadf; - border-bottom-color: #d5dadf; - border-width: 1px 0; } .maniphest-task-summary td em { @@ -30,21 +27,23 @@ background: #fff; } -.maniphest-task-summary td.maniphest-task-handle { - padding: 0 4px; - width: 1px; - - border-right-width: 1px; - border-right-color: #d5dadf; +.maniphest-task-summary .maniphest-task-handle { + padding: 0 4px 0 0; + width: 5px; } .maniphest-task-summary td.maniphest-task-batch { - padding-right: 0px; - width: 16px; + padding: 15px 4px 0 10px; + width: 8px; text-align: center; overflow: hidden; } +.device-phone .maniphest-task-batch, +.device-phone .maniphest-task-updated { + display: none; +} + .maniphest-task-summary td.maniphest-task-batch, .maniphest-task-summary td.maniphest-task-batch input { cursor: pointer; @@ -55,43 +54,39 @@ } .maniphest-task-summary td.maniphest-task-number { + padding: 6px 0 2px 10px; font-weight: bold; color: #333; - width: 50px; - text-align: right; } .maniphest-task-summary td.maniphest-task-status { - width: 60px; - text-align: center; + padding: 2px 10px 6px 10px; + text-align: left; + color: #777; + font-size: 12px; } -.maniphest-task-summary td.maniphest-task-owner { - width: 100px; +.maniphest-task-summary .maniphest-task-owner { + padding-left: 20px; } -.maniphest-task-summary td.maniphest-task-name { +.maniphest-task-summary .maniphest-task-name { font-weight: bold; - white-space: normal; overflow: hidden; + margin-left: 5px; } .maniphest-task-summary td.maniphest-task-projects { - width: 180px; text-align: right; - white-space: normal; + padding: 0px 8px; } -.maniphest-task-summary td.maniphest-task-updated { - text-align: right; - width: 85px; - padding-right: 8px; - border-right-width: 1px; - border-right-style: solid; - border-right-color: #d5dadf; -} - -.maniphest-task-summary .pri-bullet { +.maniphest-task-summary .maniphest-task-updated { + float: right; + padding: 0 8px; + color: #777; + font-size: 11px; + font-weight: normal; } .maniphest-task-summary .pri-unbreak { @@ -128,19 +123,18 @@ font-size: 16px; font-weight: bold; color: #555; - padding: 5px 0; - margin-left: 20px; -} - -.aphront-panel-view .maniphest-task-group-header { - margin-left: 0; + padding: 0 0 8px 0; } .maniphest-total-result-count { text-align: right; - padding-right: 2em; + padding: 5px 20px 0 0; font-size: 11px; - color: #666666; + color: #777; +} + +.device-phone .maniphest-total-result-count { + padding-right: 5px; } .batch-editor-header { @@ -150,14 +144,17 @@ font-weight: bold; } -.maniphest-batch-editor { - margin: 20px; +/* TODO: Implement */ +.device-phone .maniphest-batch-editor { + display: none; } .maniphest-batch-editor-layout { width: 100%; - border-top: 1px solid #d5dadf; - background: #f4f5f8; + border-left: 1px solid #e7e7e7; + border-right: 1px solid #e7e7e7; + border-bottom: 1px solid #c0c5d1; + background: #fff; } .maniphest-batch-editor-layout td { @@ -203,3 +200,11 @@ td.maniphest-active-handle { position: relative; opacity: 0.5; } + +.maniphest-list-container { + padding: 20px; +} + +.device-phone .maniphest-list-container { + padding: 20px 5px; +} diff --git a/webroot/rsrc/css/core/buttons.css b/webroot/rsrc/css/core/buttons.css index ff2bf696bf..5d4d92b27e 100644 --- a/webroot/rsrc/css/core/buttons.css +++ b/webroot/rsrc/css/core/buttons.css @@ -153,35 +153,28 @@ button.link:hover { a.toggle { display: inline-block; padding: 4px 8px; + font-size: 12px; font-weight: bold; - line-height: 14px; - color: #ffffff; - text-shadow: 0 1px 0 #777; + color: #555; text-decoration: none; white-space: nowrap; vertical-align: baseline; - background-color: #a7a7a7; - font-family: 'Helvetica Neue', Helvetica, Arial; - font-size: 12px; - margin: 0 5px 2px; - - -webkit-border-radius: 3px; - -moz-border-radius: 3px; + background-color: #f7f7f7; + margin: 0 6px 0 0; border-radius: 3px; + box-shadow: inset 0 0 3px rgba(0,0,0,.4); } a.toggle:hover { - background-color: #bbb; + background-color: #14568e; + color: #fff } a.toggle-selected { - background-color: #555; + background-color: #14568e; + color: #fff } a.toggle-fixed { cursor: default; } - -a.toggle-fixed:hover { - background-color: #555; -} diff --git a/webroot/rsrc/image/texture/dust_background.jpg b/webroot/rsrc/image/texture/dust_background.jpg index 0c7a7f78b1459d03d1601364c245e8e89d6c3a5b..dc55a68836b59e852ded5f249bc0602da5fb3c52 100644 GIT binary patch literal 7947 zcma)h2~-o=*6yiFDv%Hm!X$&5wwVHwFoj9b0>PibKp;#qNDxp00tthnLR;~6tBqpk zGAaTFWE6pDqXq@3Rv8pj6a-XMWDuntX|){?UhH>=|E>4mx87NmwNCA`_qX>s^_^*F zadhzsSn8Q2*aCpJw>eM-|1OI!fQCnAY|>5u0ir_e0>I)Ef@MNRhR~VCN=awN#HDVI zXU3)`v$A4@ENi9}3%IP!62`P-jt^@+vDTb zr==#-|LU}};6KOW@E`I1VH@|KV{!bCwk$<3tZ$$8zkTX|iWL0$R{a-o6)*pyete38 z?`aBRFTMh5f6*1h;fe_aEj|E00uqr(M2I8=A(2UnpNcYxq^v@vP*f-ssyg+rqE1y? zqP|3ps;Q}^rKxFXU|?Xl;$H<)Qc_Z-sxDPmU#hRIp{@U~hX3EnA`Uc^p;eHC0BHbN z10rZZi&sG+fWDP~Pk+U%hY8C6r|4TNqz+&hA`lf1;UBG##&_0k0dR~+O#6G~>6LGO zyKVF2tvey`dyW6gT;c0Jpb`|=8Uzin7Q8#r6ZLn`E=QS)Z#|_LNh6L};w|*h)ey8f zwiljyunWw{X`dlyRMQo!umvtDc=0_*3e17PVf7THt`_6b1y;;ormzzGdC2cVB6yHB z!Zmpm`I}wF_*RvjJ8c?S?f-9e~=V*XjZ(@*h z#oKWc82o8~dIs#wd32trUVGNf?#(&iW4jA99Z`8!C#4<0Y(@@C zLyc9W#(CHcFN$EC?6M6Jyuw1pH-Rd=T)vm2y$!?k%L=`-pnPQtkX9vN2cR36eX*!* zea?gEUv&GLb%)5iUFwrgiEBp5HGKWYxLQ5{bEIJh(8l*(-F9yq43W9&nq5%*Hh`Ul zaN-owA3z*D2uEh}S3&)m=w>JPwBc!kvW^St{;m|I4{-7@#-JO?kSR)#FI)ut?`=Yx zxs;Fe7NCPjm6ewJmgw=8@%*2N6JZ3<5dMmieT3O#&yQm|O;CyNc08tk9!i@k(S7k` zRY$JzuW#^`mXIjXng*A`rA1SOKXIzNk4U1M*K6|@p*~;kWiZ&Q>Ekd;{bE#zHGrcx zwjosVBS9kE#AzP4YZq5Uo@m?%ICGqx?|BQ4gmt@dDZ9uGQU_*Vn^RNtY$rmuEfzY zU>t>~tisyGrp^Pj=?GlYFaMIWxP+5d7JESdFo*X7p(KBVS|m2|C$1pTdhcHI-^1zQ zhihoTdjMxEU%Mx_m5A%t$h1TsBnIFC*L(p*517Md(!EK>L{}S7P;zOh{ui-2U0-X( zyIE`-T#Ftz-=^}5(Hr=F^flz;rHfjIXRNeZp`%6nW$>Mg;wFo6I3yD~hLL`yl26Ve z%Z$bLWlh+3>mNG6rQST4dnY%7PtkdZ^SbXt#%c55{4!uHc1}P>b@`-%*K*zYuLHES z+VA6|?U2Yuplx|05o?v|?d+v(N0vED)#*ks3TXvm^~x%^I^pv(V(FdxwZ)}ae>b-L zUIet;a~ev(5QOQ7WM|qwr5h zpiX^|F$Wp}qay=O8!YU^X$QhFra%s5{WOPgLU9_jBSPZq5l}p`qOahmW?W!5JO^nO z61=&Zr{YxHDY5|mw_r$YiMk0w4~G(n4@$H&X3VI=d_=X4`l*lN2Ko3Oh z5LAN;FJLIT#1${)+mRx>cJd>6dD&uyVA~wA(B;lm>|E&rpd~rzW9KG(?g^uq8FOF zM2}e?>4868yenfe-sPb=k)2Y_&@ssF*kp;Oiap_|^dMi2SGc!^?fi@|BhzjIh20Oq z>D5+@GAMQhm*t9wbD)aIEi?Ki!>bUd5O@r%d4r&IF7b;P+`2~Eym1{}H#G-n)u@6? z-d&3T_=TuzqR}$yyg2e53_eW$4F9wgdT3=fK+(mC;ZmJ*Qf2t^kHiV)!nlv26*KT| zBC!IqIt%<>uJ5G;2L3K2O@4y?nm`>t=+`-2jg1hbTA`mKz4 z2hk0?EJme4mDnihq94lt4y)h0LAw70fqOuyxl3uodnhRi1Ni~rSoJ&-qpW6Yj^-j;Vb!NXj!;Jx8^a?24wXgVC_3_tVE`HFTj&*(Jc-60(#*gL~Jy! z0>WL<0{AORNH!f%dIml*&38KHp(Sfv%I)w3I0eL;!>Lm+8VP*EK`q4GhCDI^_7bgI zs7Y;|41OGiCRzaBTzT!w4!rR&IJZmeut#XD7T$-3M_H{pb-x$BxCyQCW0{eSW_)qY z?85dYS})ZpN`qJ%`IW-#G@>$!B&IwWp(_ji@DP}?MpZXdPvXR})_@IzP0s~tEhcP2UHW>)*J`ET;l;sat^*c8)K_w zK#7?@B3(S#=R_19bh%^~=6<}siZkP$8-JTva1@+7pm!roSNpx0>B090!`Ya@z5&fd zYb#=Dii~@C53ZN4K0rI*-9Agub>?HIa*Qe?3o|^lGQmud9+-HwJOn+?$RHJViMPz) zB&Wm&=ioQ_uOM3GbD8d$aO`T|XUOO0yFt)y22QIv^bGo~&cSLTeE{i?<=XlecsmVo z>rO<|Iak*Xf!gvWw63u24aA!*$-!b6VB+0ZRCAh=c?Z1{F12|jo1z*O9NdZ7-S;Ux zHL81F=lBaynjId7vI@N2_sjG}w$^k`^%rQ3_o?CW6$LNCmUc&s?H#7Uf}5+YOd5P; zYKB>FHZ{24x`DMmOp?;d@x)8G-vvx`e~pjrY?-_RADV)$S^~$D(Q^GnJ|;kQCko&8 z>Tyh6f)m4>9Wl~E2FQ*)Pv@K*saI=wL9E;nr)olq)?Ru9jw}!%V!@?ywCX#t!zWZ} zId3z0{b=i)7b~~~Bl`u`Ht0}-$2!oF`P<+TZxwBt)1_>@#0@;~EA&QQ)ztj~Y>H`K zg#4iUxj3!xiSb==__3QHYLguHd%dj~Sp+g-u{<2e`zPrE8HfSoIfX?Wbx<8#O(LVbp{7Xsx-ySkIU3dy=7!spFLHjGhZXnJWqNaO~i9L;;4`Fr5&oOOP zzmKp;eF3GY?NYo$%()9(0Q{HqH*lUR|(V}rp+Tev!PS!)|4}d=CU`)zLGuy%ex+@Wi`fn zUbs9~xT#_F$M_TBJ0JyXdOYh@@=&KVA9nI(dc`yHuryq3p7a8gJ02~Cq8~I%{R`u$ zZ8s0|N#9o&@4x385if~M-h}z*`t7hJzRh}!>K^%7Vyf{opVPis2u<*jH4?;8VteaY zq`bN|jZ{#w30)b_9#g7igCA>NOI6SNSCeSiD)?Zn4ak?8|2umwPEK!#cKXy#k8M*nUU!vxE9KKo#B} z{ORO#)9w?;qR=~mm4RmYxu2j};tTS-Ipj~UpEfs6-tZM?w;0ooihLUgSBeiQ75T5i zG6z(RE=ssFm2OgMTfv>xNmxMEryE0cE{N2z^>!t_7LhsZrb z#^4em^B&lE)k?45d5qj;GN)LRn$07wK0p(oc`3sSN*WxeL}O}^`5X6N&mU723_%T1 zXW%=D2EDY4L!_mIK&(i?kGJ(y$&$8pMIc_j0FG7IN|mN&((>4fGe^#LP!UA@#JImq zX7bPn{vh9}&XG$LoA?dL{%geK5vjIe;KoCkX(LX(+9$Q`dhjz;!Q9j-(`^ZZd|bd) zV1kuFK7!|9OU$+P1pyv;r_kvST)>>k{)B4XbcUw4KWd813F zUBT)pB>WJ@?n|Xd#xwMd9)4LhPL6shRWkY7xEh=dz>uAH@Q6hALn_r@2Xmg3sZ>KB z`%Nxj=D#EQ<;%9YRcNr{kD3iVc1K3_HttkD_W-Sw`w4TGvo!Ws5*WQCQ52BZ-*JXo zWO~`HSF+&A)MlvzSWz8wxF>zG_FrApJX^o8vwPtxeNnQKq#rxxW@G5apq~65xlfSRQ$bP|zb( z^ZmuXaJXX^xVr9cVNztoHBfvV1m^4pYq*_!rI49~O z9ML0DI(8Q`DY#Fut6eQ2Tc#02S@0q_Df|F37eHB;MY#~^i>oF(`UJls6he(x1$@Jg z^(ALztocxu=ehD$g10+nvO!~aD5PT`z&td?uh~Y;Oi6s!;5u zQq7XPSx7%QDc>uXo#LzPdiECSDK&5;Gqi3Xf6(5iRvM9DB#95t#mQS~rJ#z?Ci zJ_CVz$ZMX$M}*iENExZguI| zAu;y>e{238T+1g(xzdMSuDtZ3jPyAiKKFv$`sE0UlCYfH-xo$L;gde?Pb{RCau ze;>qrg0K88Ra{P8F&dYU97mo8%%DF9-2B#@LRNQzjS-Ns7LxNBazJVAVlyAmCMq4Y z+ztgeNZ}MA{0CjtqdSbcV1w1x@fr6ofOTQ0PpAbXNQ7P{JNt6Atx^9UurPETh}y=HchFUtewJann9U!*mT9F_DSx9 zcr{dVa%4SRX)a|;3A^da=LT=#TCR9tw1OQBT+3kv-$G(k_9y)GYfuec&1Mk{=o(y~ zBlI0iRM$)nMVDN2O4*KvOzgR~E_uui`Z%2Td{os;VwwpIWV!9zwB+|epI=ODS{`rc zZ_C?t%%AE8tm~Gy^#r)RbiKX4gt6}|9X+CXNL<14nhWsFxSN8|F1UzIo=#wqFQb&r zM9ez6q5QH``+782yLAVcUPAY7I5qnPVhoQGnas>x;MNWq)xD_v0CE12H2&;SjNN14 zMZMCA+5RjwOR*nS9B~UuB&H*P63y4^r6rbKAE4ecwVLGHy zJCibQKTeKS$J6V2i3`EaXu(A|qndoSyq;XQf@_wj$Ry-?=n2am`F_bB-Ny>atFzL_ zsh3uKzCNEnc?Qi$1?JnRL&jQ1bixxWKu6F*mzGgoASt?6Z)&Vn7SOQkBfZ2}MMX-5 zoW5>DDvkl;eWwp!YFyZt^soCyaG+VRr?I;??x7~wi+#&%)^?QIO8#{ zwZ0YC|44{BJwUjd*b2Nu4k4nlNxoi~A{EGz5z-nB#O{yAsSDnYJBklzvkqMtB{k<7 z74H~8*izy=m|S`rGJ0|uu9FysY1PwjMvqnoujQNbRa3yz(m5wu9@MME*wa1k zJvW@Id##y^TAsTON0yi#eMXOYxM?rBM!TMds~mWyw8o}wE<0p1CC@U1y|NW6J%;)i z%d5esU83ZM7todC9ap08`-_0jGlLqQAw_$DM$UQY3vj;)3OHD^3s-Bsl+1hZj1a0f zM)qsQ%caUiO9#kiLnO^Sti0_u_^*v9t+Uy}Shwksy2@ZB@!>XtwQU4sx_}=aP;mzF z<4UInG&4v$8zv^5t=QgX&`q!sXGek3+J|)F!>E_@g&dKu6TQ+@#r@ztzc_Kgp;>}2 z-QNZjx;(;dCPL7&QJ^gczW{pGi5)hG4~FXJV9mRLxVYjDv7r0{s-_)B-T_CUr4r`f z4Z!wR0_p?u`MhO#u_@r5hvyZ0EvsmT&ZHfclAgSlQ;q{wE8RLFbDRrCh7j{F;x!du z2j~R);vL<1`oto5pFNZBZ5gLlmY;+6v-@`bwyvuqRmlF)&F{0g#DaOLMn9{pqn9}J zpd0h9=V0d-6iaefHgs5};K|DhpPZ~GK9A|Cs@-V2*a*vnK~WjBB~0_f(c|4R#TiL) zIUF{kgyMSBFV#DHm&`xPgrckvt|F6u`UA>4FEQI+I!bu_%lVUv*>5_k@(K|tZf@H@ z!d^;ifH7#~)nZFtz(lB7NE{p>^HtMkb6MvxXh`K9UYU*E!j<^u(47Uq z&a=msgtjv=!-A=*v{F%Y5GmCBy`MvzfyjmwKJ|Dq4~#Uw{%xIpEu#A87(ABaZs=Pf z)ApI>Z~aB5eRN&*2D@PW;4X+6S@q&?yk;H@_iTsOmNbrN%k-scpWvQX1pYEMENCTu zya8qO66+>~Hl4<0Grz4bG(R%BcjF_>VE@5gg@RR*__=D0x~R*wW0#e+%zb-#nW!ck z(`n?>)omW(u9wi(S*ZKE$f|Yk+J=Y-7Da7&A7CwT<|~{1!%P=IZm~tKYolGK!(<*)v@G;sUyh zNFxj`|Gryl_dM=r-HEmwNbl>KX@l40$~LDr`DlMV`y0}od5dfDEtSR^5<5aXx?d)| zv0eOw8}ACi;!E1=`t|bnH}iEhKPRd?wn%wRP{J23?Ep_=$_8r8Y-m-aShV-&*p>n8 ziTWb=Y}U5xOLRF_wg`HaR=jN4Xp$H7{xf#!4A~=O8h$T-)NA|k_j0<@;h-s{ih@f& wslXzKav-0;&P!N#2uv67f)x7Ud8PZ;6R7d>epP0N7v()1@N(E}$>P2L1>fhFL;wH) literal 6827 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

DaLD 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 M=1(g1uAF}UH^mhoJpcdz