diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1bb27137cc..09e6f6c6de 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -60,6 +60,14 @@ phutil_register_library_map(array( 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorLiskDAO' => 'applications/base/storage/lisk', + 'PhabricatorPHID' => 'applications/phid/storage/phid', + 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate', + 'PhabricatorPHIDController' => 'applications/phid/controller/base', + 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', + 'PhabricatorPHIDListController' => 'applications/phid/controller/list', + 'PhabricatorPHIDType' => 'applications/phid/storage/type', + 'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit', + 'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist', 'PhabricatorStandardPageView' => 'view/page/standard', ), 'function' => @@ -114,6 +122,14 @@ phutil_register_library_map(array( 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorLiskDAO' => 'LiskDAO', + 'PhabricatorPHID' => 'PhabricatorPHIDDAO', + 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', + 'PhabricatorPHIDController' => 'PhabricatorController', + 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', + 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', + 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO', + 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController', + 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController', 'PhabricatorStandardPageView' => 'AphrontPageView', ), 'requires_interface' => diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index f73dda95f0..4765cf56e6 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -35,18 +35,27 @@ class AphrontDefaultApplicationConfiguration 'delete/(?\d+)/$' => 'RepositoryDeleteController', ), '/' => array( - '$' => 'AphrontDirectoryMainController', + '$' => 'PhabricatorDirectoryMainController', ), '/directory/' => array( - 'item/$' => 'AphrontDirectoryItemListController', - 'item/edit/(?:(?\d+)/)?$' => 'AphrontDirectoryItemEditController', - 'item/delete/(?\d+)/' => 'AphrontDirectoryItemDeleteController', + 'item/$' + => 'PhabricatorDirectoryItemListController', + 'item/edit/(?:(?\d+)/)?$' + => 'PhabricatorDirectoryItemEditController', + 'item/delete/(?\d+)/' + => 'PhabricatorDirectoryItemDeleteController', 'category/$' - => 'AphrontDirectoryCategoryListController', + => 'PhabricatorDirectoryCategoryListController', 'category/edit/(?:(?\d+)/)?$' - => 'AphrontDirectoryCategoryEditController', + => 'PhabricatorDirectoryCategoryEditController', 'category/delete/(?\d+)/' - => 'AphrontDirectoryCategoryDeleteController', + => 'PhabricatorDirectoryCategoryDeleteController', + ), + '/phid/' => array( + '$' => 'PhabricatorPHIDListController', + 'type/$' => 'PhabricatorPHIDTypeListController', + 'type/edit/(?:(?\d+)/)?$' => 'PhabricatorPHIDTypeEditController', + 'new/$' => 'PhabricatorPHIDAllocateController', ), '.*' => 'AphrontDefaultApplicationController', ); diff --git a/src/aphront/response/webpage/AphrontWebpageResponse.php b/src/aphront/response/webpage/AphrontWebpageResponse.php index 40ceb9e2eb..94e976a64c 100644 --- a/src/aphront/response/webpage/AphrontWebpageResponse.php +++ b/src/aphront/response/webpage/AphrontWebpageResponse.php @@ -32,4 +32,10 @@ class AphrontWebpageResponse extends AphrontResponse { return $this->content; } + public function getHeaders() { + return array( + array('Content-Type', 'text/html; charset=UTF-8'), + ); + } + } diff --git a/src/applications/base/controller/base/__init__.php b/src/applications/base/controller/base/__init__.php new file mode 100644 index 0000000000..03cfc02dba --- /dev/null +++ b/src/applications/base/controller/base/__init__.php @@ -0,0 +1,14 @@ +getRequest(); + if ($request->isFormPost()) { + $type = $request->getStr('type'); + $phid = PhabricatorPHID::generateNewPHID($type); + + return id(new AphrontRedirectResponse()) + ->setURI('/phid/?phid='.phutil_escape_uri($phid)); + } + + $types = id(new PhabricatorPHIDType())->loadAll(); + + $options = array(); + foreach ($types as $type) { + $options[$type->getType()] = $type->getType().': '.$type->getName(); + } + asort($options); + + $form = new AphrontFormView(); + $form->setAction('/phid/new/'); + + $form + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel('PHID Type') + ->setName('type') + ->setOptions($options)) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Allocate') + ->addCancelButton('/phid/')); + + $panel = new AphrontPanelView(); + $panel->setHeader('Allocate New PHID'); + + $panel->appendChild($form); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + + return $this->buildStandardPageResponse( + array($panel), + array( + 'title' => 'Allocate New PHID', + )); + } + +} diff --git a/src/applications/phid/controller/allocate/__init__.php b/src/applications/phid/controller/allocate/__init__.php new file mode 100644 index 0000000000..0605962517 --- /dev/null +++ b/src/applications/phid/controller/allocate/__init__.php @@ -0,0 +1,20 @@ +setApplicationName('PHID'); + $page->setBaseURI('/phid/'); + $page->setTitle(idx($data, 'title')); + $page->setTabs( + array( + 'phids' => array( + 'href' => '/phid/', + 'name' => 'PHIDs', + ), + 'types' => array( + 'href' => '/phid/type/', + 'name' => 'PHID Types', + ), + ), + idx($data, 'tab')); + $page->setGlyph('#'); + $page->appendChild($view); + + $response = new AphrontWebpageResponse(); + return $response->setContent($page->render()); + } + +} diff --git a/src/applications/phid/controller/base/__init__.php b/src/applications/phid/controller/base/__init__.php new file mode 100644 index 0000000000..44f0f1b94d --- /dev/null +++ b/src/applications/phid/controller/base/__init__.php @@ -0,0 +1,16 @@ +loadAllWhere( + '1 = 1 ORDER BY id DESC limit 100'); + + $rows = array(); + foreach ($items as $item) { + $rows[] = array( + phutil_escape_html($item->getPHID()), + phutil_escape_html($item->getPHIDType()), + phutil_escape_html($item->getOwnerPHID()), + phutil_escape_html($item->getParentPHID()), + ); + } + + $table = new AphrontTableView($rows); + $table->setHeaders( + array( + 'PHID', + 'Type', + 'Owner PHID', + 'Parent PHID', + )); + + $panel = new AphrontPanelView(); + $panel->appendChild($table); + $panel->setHeader('PHIDs'); + $panel->setCreateButton('Allocate New PHID', '/phid/new/'); + + return $this->buildStandardPageResponse($panel, array( + 'title' => 'PHIDs', + 'tab' => 'phids', + )); + } + +} diff --git a/src/applications/phid/controller/list/__init__.php b/src/applications/phid/controller/list/__init__.php new file mode 100644 index 0000000000..913d4fe3f1 --- /dev/null +++ b/src/applications/phid/controller/list/__init__.php @@ -0,0 +1,18 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + + if ($this->id) { + $type = id(new PhabricatorPHIDType())->load($this->id); + if (!$type) { + return new Aphront404Response(); + } + } else { + $type = new PhabricatorPHIDType(); + } + + $e_type = true; + $e_name = true; + $errors = array(); + + $request = $this->getRequest(); + if ($request->isFormPost()) { + $type->setName($request->getStr('name')); + if (!$type->getID()) { + $type->setType($request->getStr('type')); + } + $type->setDescription($request->getStr('description')); + + if (!strlen($type->getType())) { + $errors[] = 'Type code is required.'; + $e_type = 'Required'; + } + + if (!strlen($type->getName())) { + $errors[] = 'Type name is required.'; + $e_name = 'Required'; + } + + if (!$errors) { + $type->save(); + return id(new AphrontRedirectResponse()) + ->setURI('/phid/type/'); + } + } + + $error_view = null; + if ($errors) { + $error_view = id(new AphrontErrorView()) + ->setTitle('Form Errors') + ->setErrors($errors); + } + + $form = new AphrontFormView(); + if ($type->getID()) { + $form->setAction('/phid/type/edit/'.$type->getID().'/'); + } else { + $form->setAction('/phid/type/edit/'); + } + + if ($type->getID()) { + $type_immutable = true; + } else { + $type_immutable = false; + } + + $form + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Type') + ->setName('type') + ->setValue($type->getType()) + ->setError($e_type) + ->setCaption( + 'Four character type identifier. This can not be changed once '. + 'it is created.') + ->setDisabled($type_immutable)) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Name') + ->setName('name') + ->setValue($type->getName()) + ->setError($e_name)) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Description') + ->setName('description') + ->setValue($type->getDescription())) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Save') + ->addCancelButton('/phid/type/')); + + $panel = new AphrontPanelView(); + if ($type->getID()) { + $panel->setHeader('Edit PHID Type'); + } else { + $panel->setHeader('Create New PHID Type'); + } + + $panel->appendChild($form); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + + return $this->buildStandardPageResponse( + array($error_view, $panel), + array( + 'title' => 'Edit PHID Type', + )); + } + +} diff --git a/src/applications/phid/controller/typeedit/__init__.php b/src/applications/phid/controller/typeedit/__init__.php new file mode 100644 index 0000000000..0805e99ff0 --- /dev/null +++ b/src/applications/phid/controller/typeedit/__init__.php @@ -0,0 +1,21 @@ +loadAll(); + + $rows = array(); + foreach ($items as $item) { + $rows[] = array( + $item->getID(), + phutil_escape_html($item->getType()), + phutil_escape_html($item->getName()), + ); + } + + $table = new AphrontTableView($rows); + $table->setHeaders( + array( + 'ID', + 'Type Code', + 'Name', + )); + $table->setColumnClasses( + array( + null, + null, + 'wide', + )); + + $panel = new AphrontPanelView(); + $panel->appendChild($table); + $panel->setHeader('PHID Types'); + $panel->setCreateButton('New Type', '/phid/type/edit/'); + + return $this->buildStandardPageResponse($panel, array( + 'title' => 'PHID Types', + 'tab' => 'types', + )); + } + +} diff --git a/src/applications/phid/controller/typelist/__init__.php b/src/applications/phid/controller/typelist/__init__.php new file mode 100644 index 0000000000..81a4d0557d --- /dev/null +++ b/src/applications/phid/controller/typelist/__init__.php @@ -0,0 +1,18 @@ +setPHIDType($type); + $phid_rec->setOwnerPHID($owner); + $phid_rec->setParentPHID($parent); + $phid_rec->setPHID($phid); + $phid_rec->save(); + + return $phid; + } + +} diff --git a/src/applications/phid/storage/phid/__init__.php b/src/applications/phid/storage/phid/__init__.php new file mode 100644 index 0000000000..5ff7852286 --- /dev/null +++ b/src/applications/phid/storage/phid/__init__.php @@ -0,0 +1,14 @@ +isGUIDPrimaryID() && - $this->getConfigOption(self::CONFIG_AUX_GUID)) { - $properties['guid'] = 'guid'; + if (!$this->isPHIDPrimaryID() && + $this->getConfigOption(self::CONFIG_AUX_PHID)) { + $properties['phid'] = 'phid'; } } return $properties; @@ -792,11 +792,11 @@ abstract class LiskDAO { case self::IDS_AUTOINCREMENT: unset($data[$this->getIDKeyForUse()]); break; - case self::IDS_GUID: + case self::IDS_PHID: if (empty($data[$this->getIDKeyForUse()])) { - $guid = $this->generateGUID(); - $this->setID($guid); - $data[$this->getIDKeyForUse()] = $guid; + $phid = $this->generatePHID(); + $this->setID($phid); + $data[$this->getIDKeyForUse()] = $phid; } break; case self::IDS_MANUAL: @@ -888,11 +888,11 @@ abstract class LiskDAO { /** - * Helper: Whether this class is configured to use GUIDs as the primary ID. + * Helper: Whether this class is configured to use PHIDs as the primary ID. * @task internal */ - private function isGUIDPrimaryID() { - return ($this->getConfigOption(self::CONFIG_IDS) === self::IDS_GUID); + private function isPHIDPrimaryID() { + return ($this->getConfigOption(self::CONFIG_IDS) === self::IDS_PHID); } @@ -906,8 +906,8 @@ abstract class LiskDAO { */ public function getIDKey() { return - $this->isGUIDPrimaryID() ? - 'guid' : + $this->isPHIDPrimaryID() ? + 'phid' : 'id'; } @@ -924,16 +924,16 @@ abstract class LiskDAO { /** - * Generate a new GUID, used by CONFIG_AUX_GUID and IDS_GUID. + * Generate a new PHID, used by CONFIG_AUX_PHID and IDS_PHID. * - * @return guid Unique, newly allocated GUID. + * @return phid Unique, newly allocated PHID. * * @task hook */ - protected function generateGUID() { + protected function generatePHID() { throw new Exception( - "To use CONFIG_AUX_GUID or IDS_GUID, you need to overload ". - "generateGUID() to perform GUID generation."); + "To use CONFIG_AUX_PHID or IDS_PHID, you need to overload ". + "generatePHID() to perform PHID generation."); } @@ -987,14 +987,14 @@ abstract class LiskDAO { $this->setDateModified(time()); } - if (($this->isGUIDPrimaryID() && !$this->getID())) { - // If GUIDs are the primary ID, the subclass could have overridden the + if (($this->isPHIDPrimaryID() && !$this->getID())) { + // If PHIDs are the primary ID, the subclass could have overridden the // name of the ID column. - $this->setID($this->generateGUID()); - } else if ($this->getConfigOption(self::CONFIG_AUX_GUID) && - !$this->getGUID()) { - // The subclass could still want GUIDs. - $this->setGUID($this->generateGUID()); + $this->setID($this->generatePHID()); + } else if ($this->getConfigOption(self::CONFIG_AUX_PHID) && + !$this->getPHID()) { + // The subclass could still want PHIDs. + $this->setPHID($this->generatePHID()); } } diff --git a/src/view/form/control/base/AphrontFormControl.php b/src/view/form/control/base/AphrontFormControl.php index 9fa982b131..1f078710f8 100755 --- a/src/view/form/control/base/AphrontFormControl.php +++ b/src/view/form/control/base/AphrontFormControl.php @@ -23,6 +23,7 @@ abstract class AphrontFormControl extends AphrontView { private $error; private $name; private $value; + private $disabled; public function setLabel($label) { $this->label = $label; @@ -69,6 +70,15 @@ abstract class AphrontFormControl extends AphrontView { return $this->value; } + public function setDisabled($disabled) { + $this->disabled = $disabled; + return $this; + } + + public function getDisabled() { + return $this->disabled; + } + abstract protected function renderInput(); abstract protected function getCustomControlClass(); diff --git a/src/view/form/control/select/AphrontFormSelectControl.php b/src/view/form/control/select/AphrontFormSelectControl.php index a15eda8f49..d2ffaad74d 100755 --- a/src/view/form/control/select/AphrontFormSelectControl.php +++ b/src/view/form/control/select/AphrontFormSelectControl.php @@ -48,7 +48,8 @@ class AphrontFormSelectControl extends AphrontFormControl { return phutil_render_tag( 'select', array( - 'name' => $this->getName(), + 'name' => $this->getName(), + 'disabled' => $this->getDisabled() ? 'disabled' : null, ), implode("\n", $options)); } diff --git a/src/view/form/control/submit/AphrontFormSubmitControl.php b/src/view/form/control/submit/AphrontFormSubmitControl.php index 16dd7b9a5e..7742a20ae0 100755 --- a/src/view/form/control/submit/AphrontFormSubmitControl.php +++ b/src/view/form/control/submit/AphrontFormSubmitControl.php @@ -39,7 +39,8 @@ class AphrontFormSubmitControl extends AphrontFormControl { return phutil_render_tag( 'button', array( - 'name' => '__submit__', + 'name' => '__submit__', + 'disabled' => $this->getDisabled() ? 'disabled' : null, ), phutil_escape_html($this->getValue())). $this->cancelButton; diff --git a/src/view/form/control/text/AphrontFormTextControl.php b/src/view/form/control/text/AphrontFormTextControl.php index f62fd6f463..f8265188af 100755 --- a/src/view/form/control/text/AphrontFormTextControl.php +++ b/src/view/form/control/text/AphrontFormTextControl.php @@ -26,9 +26,10 @@ class AphrontFormTextControl extends AphrontFormControl { return phutil_render_tag( 'input', array( - 'type' => 'text', - 'name' => $this->getName(), - 'value' => $this->getValue(), + 'type' => 'text', + 'name' => $this->getName(), + 'value' => $this->getValue(), + 'disabled' => $this->getDisabled() ? 'disabled' : null, )); } diff --git a/src/view/form/control/textarea/AphrontFormTextAreaControl.php b/src/view/form/control/textarea/AphrontFormTextAreaControl.php index f52cbeb9d6..2668b825b1 100755 --- a/src/view/form/control/textarea/AphrontFormTextAreaControl.php +++ b/src/view/form/control/textarea/AphrontFormTextAreaControl.php @@ -26,7 +26,8 @@ class AphrontFormTextAreaControl extends AphrontFormControl { return phutil_render_tag( 'textarea', array( - 'name' => $this->getName(), + 'name' => $this->getName(), + 'disabled' => $this->getDisabled() ? 'disabled' : null, ), phutil_escape_html($this->getValue())); } diff --git a/webroot/rsrc/css/base.css b/webroot/rsrc/css/base.css index f305a544c2..4e49a892d3 100644 --- a/webroot/rsrc/css/base.css +++ b/webroot/rsrc/css/base.css @@ -476,6 +476,8 @@ a.small:visited { clear: both; margin-right: 25%; margin-left: 15%; + margin-top: 3px; + margin-bottom: 6px; } .aphront-error-view {