1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-03 11:21:01 +01:00

Some owners write workflows.

This commit is contained in:
epriestley 2011-04-03 22:03:27 -07:00
parent 5038ab850c
commit 23f882a0ee
24 changed files with 730 additions and 174 deletions

View file

@ -1,6 +1,6 @@
CREATE DATABASE phabricator_owners; CREATE DATABASE phabricator_owners;
CREATE TABLE phabricator_owners.onwners_package ( CREATE TABLE phabricator_owners.owners_package (
id int unsigned not null auto_increment primary key, id int unsigned not null auto_increment primary key,
phid varchar(64) binary not null, phid varchar(64) binary not null,
unique key(phid), unique key(phid),
@ -23,6 +23,5 @@ CREATE TABLE phabricator_owners.owners_path (
packageID int unsigned not null, packageID int unsigned not null,
key(packageID), key(packageID),
repositoryPHID varchar(64) binary not null, repositoryPHID varchar(64) binary not null,
path varchar(255) not null, path varchar(255) not null
unique key (repositoryPHID, path)
); );

View file

@ -63,7 +63,7 @@ celerity_register_resource_map(array(
), ),
'aphront-list-filter-view-css' => 'aphront-list-filter-view-css' =>
array( array(
'uri' => '/res/89f641c5/rsrc/css/aphront/list-filter-view.css', 'uri' => '/res/50a790ae/rsrc/css/aphront/list-filter-view.css',
'type' => 'css', 'type' => 'css',
'requires' => 'requires' =>
array( array(
@ -81,7 +81,7 @@ celerity_register_resource_map(array(
), ),
'aphront-panel-view-css' => 'aphront-panel-view-css' =>
array( array(
'uri' => '/res/63672373/rsrc/css/aphront/panel-view.css', 'uri' => '/res/8f9f3632/rsrc/css/aphront/panel-view.css',
'type' => 'css', 'type' => 'css',
'requires' => 'requires' =>
array( array(
@ -643,7 +643,7 @@ celerity_register_resource_map(array(
), array ( ), array (
'packages' => 'packages' =>
array ( array (
'e3ec35d7' => '2de9aa4e' =>
array ( array (
'name' => 'core.pkg.css', 'name' => 'core.pkg.css',
'symbols' => 'symbols' =>
@ -663,7 +663,7 @@ celerity_register_resource_map(array(
12 => 'phabricator-remarkup-css', 12 => 'phabricator-remarkup-css',
13 => 'syntax-highlighting-css', 13 => 'syntax-highlighting-css',
), ),
'uri' => '/res/pkg/e3ec35d7/core.pkg.css', 'uri' => '/res/pkg/2de9aa4e/core.pkg.css',
'type' => 'css', 'type' => 'css',
), ),
'76f3c1f8' => '76f3c1f8' =>
@ -710,20 +710,20 @@ celerity_register_resource_map(array(
), ),
'reverse' => 'reverse' =>
array ( array (
'phabricator-core-css' => 'e3ec35d7', 'phabricator-core-css' => '2de9aa4e',
'phabricator-core-buttons-css' => 'e3ec35d7', 'phabricator-core-buttons-css' => '2de9aa4e',
'phabricator-standard-page-view' => 'e3ec35d7', 'phabricator-standard-page-view' => '2de9aa4e',
'aphront-dialog-view-css' => 'e3ec35d7', 'aphront-dialog-view-css' => '2de9aa4e',
'aphront-form-view-css' => 'e3ec35d7', 'aphront-form-view-css' => '2de9aa4e',
'aphront-panel-view-css' => 'e3ec35d7', 'aphront-panel-view-css' => '2de9aa4e',
'aphront-side-nav-view-css' => 'e3ec35d7', 'aphront-side-nav-view-css' => '2de9aa4e',
'aphront-table-view-css' => 'e3ec35d7', 'aphront-table-view-css' => '2de9aa4e',
'aphront-crumbs-view-css' => 'e3ec35d7', 'aphront-crumbs-view-css' => '2de9aa4e',
'aphront-tokenizer-control-css' => 'e3ec35d7', 'aphront-tokenizer-control-css' => '2de9aa4e',
'aphront-typeahead-control-css' => 'e3ec35d7', 'aphront-typeahead-control-css' => '2de9aa4e',
'phabricator-directory-css' => 'e3ec35d7', 'phabricator-directory-css' => '2de9aa4e',
'phabricator-remarkup-css' => 'e3ec35d7', 'phabricator-remarkup-css' => '2de9aa4e',
'syntax-highlighting-css' => 'e3ec35d7', 'syntax-highlighting-css' => '2de9aa4e',
'differential-core-view-css' => '76f3c1f8', 'differential-core-view-css' => '76f3c1f8',
'differential-changeset-view-css' => '76f3c1f8', 'differential-changeset-view-css' => '76f3c1f8',
'differential-revision-detail-css' => '76f3c1f8', 'differential-revision-detail-css' => '76f3c1f8',

View file

@ -320,7 +320,9 @@ phutil_register_library_map(array(
'PhabricatorObjectSelectorDialog' => 'view/control/objectselector', 'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
'PhabricatorOwnersController' => 'applications/owners/controller/base', 'PhabricatorOwnersController' => 'applications/owners/controller/base',
'PhabricatorOwnersDAO' => 'applications/owners/storage/base', 'PhabricatorOwnersDAO' => 'applications/owners/storage/base',
'PhabricatorOwnersDeleteController' => 'applications/owners/controller/delete',
'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail', 'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail',
'PhabricatorOwnersEditController' => 'applications/owners/controller/edit',
'PhabricatorOwnersListController' => 'applications/owners/controller/list', 'PhabricatorOwnersListController' => 'applications/owners/controller/list',
'PhabricatorOwnersOwner' => 'applications/owners/storage/owner', 'PhabricatorOwnersOwner' => 'applications/owners/storage/owner',
'PhabricatorOwnersPackage' => 'applications/owners/storage/package', 'PhabricatorOwnersPackage' => 'applications/owners/storage/package',
@ -677,7 +679,9 @@ phutil_register_library_map(array(
'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
'PhabricatorOwnersController' => 'PhabricatorController', 'PhabricatorOwnersController' => 'PhabricatorController',
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
'PhabricatorOwnersListController' => 'PhabricatorOwnersController', 'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO',

View file

@ -260,8 +260,10 @@ class AphrontDefaultApplicationConfiguration
'/owners/' => array( '/owners/' => array(
'$' => 'PhabricatorOwnersListController', '$' => 'PhabricatorOwnersListController',
'view/(?P<view>[^/]+)/$' => 'PhabricatorOwnersListController', 'view/(?P<view>[^/]+)/$' => 'PhabricatorOwnersListController',
'edit/(?P<id>\d+)/$' => 'PhabricatorOwnersEditController',
'new/$' => 'PhabricatorOwnersEditController',
'package/(?P<id>\d+)/$' => 'PhabricatorOwnersDetailController', 'package/(?P<id>\d+)/$' => 'PhabricatorOwnersDetailController',
'new/$' => 'PhabricatorOwnersDetailController', 'delete/(?P<id>\d+)/$' => 'PhabricatorOwnersDeleteController',
), ),
); );

View file

@ -47,8 +47,7 @@ class DiffusionPathCompleteController extends DiffusionController {
$drequest = DiffusionRequest::newFromAphrontRequestDictionary( $drequest = DiffusionRequest::newFromAphrontRequestDictionary(
array( array(
'callsign' => $repository->getCallsign(), 'callsign' => $repository->getCallsign(),
'path' => $query_dir, 'path' => ':/'.$query_dir,
'nobranch' => true,
)); ));
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest); $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);

View file

@ -39,8 +39,7 @@ class DiffusionPathValidateController extends DiffusionController {
$drequest = DiffusionRequest::newFromAphrontRequestDictionary( $drequest = DiffusionRequest::newFromAphrontRequestDictionary(
array( array(
'callsign' => $repository->getCallsign(), 'callsign' => $repository->getCallsign(),
'path' => $path, 'path' => ':/'.$path,
'nobranch' => true,
)); ));
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest); $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);

View file

@ -24,8 +24,8 @@ class DiffusionGitRequest extends DiffusionRequest {
$path = $this->path; $path = $this->path;
$parts = explode('/', $path); $parts = explode('/', $path);
if (empty($data['nobranch'])) { $branch = array_shift($parts);
$branch = array_shift($parts); if ($branch != ':') {
$this->branch = $this->decodeBranchName($branch); $this->branch = $this->decodeBranchName($branch);
} }

View file

@ -20,6 +20,14 @@ class DiffusionSvnRequest extends DiffusionRequest {
private $loadedCommit; private $loadedCommit;
protected function initializeFromAphrontRequestDictionary(array $data) {
parent::initializeFromAphrontRequestDictionary($data);
if (!strncmp($this->path, ':', 1)) {
$this->path = substr($this->path, 1);
$this->path = ltrim($this->path, '/');
}
}
public function getCommit() { public function getCommit() {
if ($this->commit) { if ($this->commit) {
return $this->commit; return $this->commit;

View file

@ -0,0 +1,55 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorOwnersDeleteController extends PhabricatorOwnersController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$package = id(new PhabricatorOwnersPackage())->load($this->id);
if (!$package) {
return new Aphront404Response();
}
if ($request->isDialogFormPost()) {
$package->delete();
return id(new AphrontRedirectResponse())->setURI('/owners/');
}
$dialog = id(new AphrontDialogView())
->setUser($user)
->setTitle('Really delete this package?')
->appendChild(
'<p>Are you sure you want to delete the "'.
phutil_escape_html($package->getName()).'" package? This operation '.
'can not be undone.</p>')
->addSubmitButton('Delete')
->addCancelButton('/owners/package/'.$package->getID().'/')
->setSubmitURI($request->getRequestURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}

View file

@ -0,0 +1,19 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/dialog');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'view/dialog');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorOwnersDeleteController.php');

View file

@ -21,132 +21,122 @@ class PhabricatorOwnersDetailController extends PhabricatorOwnersController {
private $id; private $id;
public function willProcessRequest(array $data) { public function willProcessRequest(array $data) {
$this->id = idx($data, 'id'); $this->id = $data['id'];
} }
public function processRequest() { public function processRequest() {
$request = $this->getRequest(); $request = $this->getRequest();
$user = $request->getUser(); $user = $request->getUser();
if ($this->id) { $package = id(new PhabricatorOwnersPackage())->load($this->id);
$package = id(new PhabricatorOwnersPackage())->load($this->id); if (!$package) {
if (!$package) { return new Aphront404Response();
return new Aphront404Response();
}
} else {
$package = new PhabricatorOwnersPackage();
$package->setPrimaryOwnerPHID($user->getPHID());
} }
$e_name = true; $paths = $package->loadPaths();
$e_primary = true; $owners = $package->loadOwners();
$phids = array();
$token_primary_owner = array(); foreach ($paths as $path) {
$token_all_owners = array(); $phids[$path->getRepositoryPHID()] = true;
$title = $package->getID() ? 'Edit Package' : 'New Package';
$repos = id(new PhabricatorRepository())->loadAll();
$default_paths = array();
foreach ($repos as $repo) {
$default_path = $repo->getDetail('default-owners-path');
if ($default_path) {
$default_paths[$repo->getPHID()] = $default_path;
}
} }
foreach ($owners as $owner) {
$phids[$owner->getUserPHID()] = true;
}
$phids = array_keys($phids);
$repos = mpull($repos, 'getCallsign', 'getPHID'); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$template = new AphrontTypeaheadTemplateView(); $rows = array();
$template = $template->render();
$rows[] = array(
'Name',
phutil_escape_html($package->getName()));
$rows[] = array(
'Description',
phutil_escape_html($package->getDescription()));
Javelin::initBehavior( $primary_owner = null;
'owners-path-editor', $primary_phid = $package->getPrimaryOwnerPHID();
if ($primary_phid && isset($handles[$primary_phid])) {
$primary_owner =
'<strong>'.$handles[$primary_phid]->renderLink().'</strong>';
}
$rows[] = array(
'Primary Owner',
$primary_owner,
);
$owner_links = array();
foreach ($owners as $owner) {
$owner_links[] = $handles[$owner->getUserPHID()]->renderLink();
}
$owner_links = implode('<br />', $owner_links);
$rows[] = array(
'Owners',
$owner_links);
$path_links = array();
foreach ($paths as $path) {
$callsign = $handles[$path->getRepositoryPHID()]->getName();
$repo = phutil_escape_html('r'.$callsign);
$path_link = phutil_render_tag(
'a',
array(
'href' => '/diffusion/'.$callsign.'/browse/:'.$path->getPath(),
),
phutil_escape_html($path->getPath()));
$path_links[] = $repo.' '.$path_link;
}
$path_links = implode('<br />', $path_links);
$rows[] = array(
'Paths',
$path_links);
$table = new AphrontTableView($rows);
$table->setColumnClasses(
array( array(
'root' => 'path-editor', 'header',
'table' => 'paths', 'wide',
'add_button' => 'addpath',
'repositories' => $repos,
'input_template' => $template,
'path_refs' => array(),
'completeURI' => '/diffusion/services/path/complete/',
'validateURI' => '/diffusion/services/path/validate/',
'repositoryDefaultPaths' => $default_paths,
)); ));
require_celerity_resource('owners-path-editor-css');
$form = id(new AphrontFormView())
->setUser($user)
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Name')
->setName('name')
->setValue($package->getName())
->setError($e_name))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setLabel('Primary Owner')
->setName('primary')
->setLimit(1)
->setValue($token_primary_owner)
->setError($e_primary))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setLabel('Owners')
->setName('owners')
->setValue($token_all_owners)
->setError($e_primary))
->appendChild(
'<h1>Paths</h1>'.
'<div class="aphront-form-inset" id="path-editor">'.
'<div style="float: right;">'.
javelin_render_tag(
'a',
array(
'href' => '#',
'class' => 'button green',
'sigil' => 'addpath',
'mustcapture' => true,
),
'Add New Path').
'</div>'.
'<p>Specify the files and directories which comprise this '.
'package.</p>'.
'<div style="clear: both;"></div>'.
javelin_render_tag(
'table',
array(
'class' => 'owners-path-editor-table',
'sigil' => 'paths',
),
'').
'</div>')
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Description')
->setName('description')
->setValue($package->getDescription()))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Save Package'));
$panel = new AphrontPanelView(); $panel = new AphrontPanelView();
$panel->setHeader($title); $panel->setHeader(
$panel->setWidth(AphrontPanelView::WIDTH_WIDE); 'Package Details for "'.phutil_escape_html($package->getName()).'"');
$panel->appendChild($form); $panel->addButton(
javelin_render_tag(
'a',
array(
'href' => '/owners/delete/'.$package->getID().'/',
'class' => 'button grey',
'sigil' => 'workflow',
),
'Delete Package'));
$panel->addButton(
phutil_render_tag(
'a',
array(
'href' => '/owners/edit/'.$package->getID().'/',
'class' => 'button',
),
'Edit Package'));
$panel->appendChild($table);
$nav = new AphrontSideNavView();
$nav->appendChild($panel);
$nav->addNavItem(
phutil_render_tag(
'a',
array(
'href' => '/owners/package/'.$package->getID().'/',
'class' => 'aphront-side-nav-selected',
),
'Package Details'));
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
$panel, $nav,
array( array(
'title' => $title, 'title' => "Package '".$package->getName()."'",
)); ));
} }

View file

@ -9,14 +9,13 @@
phutil_require_module('phabricator', 'aphront/response/404'); phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'applications/owners/controller/base'); phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/package'); phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'applications/repository/storage/repository'); phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'infrastructure/javelin/markup');
phutil_require_module('phabricator', 'infrastructure/javelin/api'); phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/control/typeahead');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/layout/panel'); phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils'); phutil_require_module('phutil', 'utils');

View file

@ -0,0 +1,258 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorOwnersEditController extends PhabricatorOwnersController {
private $id;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
if ($this->id) {
$package = id(new PhabricatorOwnersPackage())->load($this->id);
if (!$package) {
return new Aphront404Response();
}
} else {
$package = new PhabricatorOwnersPackage();
$package->setPrimaryOwnerPHID($user->getPHID());
}
$e_name = true;
$e_primary = true;
$e_owners = true;
$errors = array();
if ($request->isFormPost()) {
$package->setName($request->getStr('name'));
$package->setDescription($request->getStr('description'));
$primary = $request->getArr('primary');
$primary = reset($primary);
$package->setPrimaryOwnerPHID($primary);
$owners = $request->getArr('owners');
if ($primary) {
array_unshift($owners, $primary);
}
$owners = array_unique($owners);
$paths = $request->getArr('path');
$repos = $request->getArr('repo');
$path_refs = array();
for ($ii = 0; $ii < count($paths); $ii++) {
if (empty($paths[$ii]) || empty($repos[$ii])) {
continue;
}
$path_refs[] = array(
'repositoryPHID' => $repos[$ii],
'path' => $paths[$ii],
);
}
if (!strlen($package->getName())) {
$e_name = 'Required';
$errors[] = 'Package name is required.';
} else {
$e_name = null;
}
if (!$package->getPrimaryOwnerPHID()) {
$e_primary = 'Required';
$errors[] = 'Package must have a primary owner.';
} else {
$e_primary = null;
}
if (!$owners) {
$e_owners = 'Required';
$errors[] = 'Package must have at least one owner.';
} else {
$e_owners = null;
}
if (!$path_refs) {
$errors[] = 'Package must include at least one path.';
}
if (!$errors) {
$package->attachUnsavedOwners($owners);
$package->attachUnsavedPaths($path_refs);
try {
$package->save();
return id(new AphrontRedirectResponse())
->setURI('/owners/package/'.$package->getID().'/');
} catch (AphrontQueryDuplicateKeyException $ex) {
$e_name = 'Duplicate';
$errors[] = 'Package name must be unique.';
}
}
} else {
$owners = $package->loadOwners();
$owners = mpull($owners, 'getUserPHID');
$paths = $package->loadPaths();
$path_refs = array();
foreach ($paths as $path) {
$path_refs[] = array(
'repositoryPHID' => $path->getRepositoryPHID(),
'path' => $path->getPath(),
);
}
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle('Package Errors');
$error_view->setErrors($errors);
}
$handles = id(new PhabricatorObjectHandleData($owners))
->loadHandles();
$primary = $package->getPrimaryOwnerPHID();
if ($primary && isset($handles[$primary])) {
$token_primary_owner = array(
$primary => $handles[$primary]->getFullName(),
);
} else {
$token_primary_owner = array();
}
$token_all_owners = array_select_keys($handles, $owners);
$token_all_owners = mpull($token_all_owners, 'getFullName');
$title = $package->getID() ? 'Edit Package' : 'New Package';
$repos = id(new PhabricatorRepository())->loadAll();
$default_paths = array();
foreach ($repos as $repo) {
$default_path = $repo->getDetail('default-owners-path');
if ($default_path) {
$default_paths[$repo->getPHID()] = $default_path;
}
}
$repos = mpull($repos, 'getCallsign', 'getPHID');
$template = new AphrontTypeaheadTemplateView();
$template = $template->render();
Javelin::initBehavior(
'owners-path-editor',
array(
'root' => 'path-editor',
'table' => 'paths',
'add_button' => 'addpath',
'repositories' => $repos,
'input_template' => $template,
'pathRefs' => $path_refs,
'completeURI' => '/diffusion/services/path/complete/',
'validateURI' => '/diffusion/services/path/validate/',
'repositoryDefaultPaths' => $default_paths,
));
require_celerity_resource('owners-path-editor-css');
$cancel_uri = $package->getID()
? '/owners/package/'.$package->getID().'/'
: '/owners/';
$form = id(new AphrontFormView())
->setUser($user)
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Name')
->setName('name')
->setValue($package->getName())
->setError($e_name))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setLabel('Primary Owner')
->setName('primary')
->setLimit(1)
->setValue($token_primary_owner)
->setError($e_primary))
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setLabel('Owners')
->setName('owners')
->setValue($token_all_owners)
->setError($e_owners))
->appendChild(
'<h1>Paths</h1>'.
'<div class="aphront-form-inset" id="path-editor">'.
'<div style="float: right;">'.
javelin_render_tag(
'a',
array(
'href' => '#',
'class' => 'button green',
'sigil' => 'addpath',
'mustcapture' => true,
),
'Add New Path').
'</div>'.
'<p>Specify the files and directories which comprise this '.
'package.</p>'.
'<div style="clear: both;"></div>'.
javelin_render_tag(
'table',
array(
'class' => 'owners-path-editor-table',
'sigil' => 'paths',
),
'').
'</div>')
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Description')
->setName('description')
->setValue($package->getDescription()))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue('Save Package'));
$panel = new AphrontPanelView();
$panel->setHeader($title);
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
$panel->appendChild($error_view);
$panel->appendChild($form);
return $this->buildStandardPageResponse(
$panel,
array(
'title' => $title,
));
}
}

View file

@ -0,0 +1,26 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/repository/storage/repository');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'infrastructure/javelin/api');
phutil_require_module('phabricator', 'view/control/typeahead');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorOwnersEditController.php');

View file

@ -58,18 +58,42 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
phutil_escape_html($name))); phutil_escape_html($name)));
} }
$package = new PhabricatorOwnersPackage();
switch ($this->view) { switch ($this->view) {
case 'search': case 'search':
$content = $this->renderPackageTable(array(), 'Search Results'); $packages = array();
$header = 'Search Results';
$nodata = 'No packages match your query.';
break; break;
case 'owned': case 'owned':
$content = $this->renderOwnedView(); $owner = new PhabricatorOwnersOwner();
$data = queryfx_all(
$package->establishConnection('r'),
'SELECT p.* FROM %T p JOIN %T o ON p.id = o.packageID
WHERE o.userPHID = %s GROUP BY p.id',
$package->getTableName(),
$owner->getTableName(),
$user->getPHID());
$packages = $package->loadAllFromArray($data);
$header = 'Owned Packages';
$nodata = 'No owned packages';
break; break;
case 'all': case 'all':
$content = $this->renderAllView(); $packages = $package->loadAll();
$header = 'All Packages';
$nodata = 'There are no defined packages.';
break; break;
} }
$content = $this->renderPackageTable(
$packages,
$header,
$nodata);
$filter = new AphrontListFilterView(); $filter = new AphrontListFilterView();
$filter->addButton( $filter->addButton(
phutil_render_tag( phutil_render_tag(
@ -127,26 +151,68 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
)); ));
} }
private function renderOwnedView() { private function renderPackageTable(array $packages, $header, $nodata) {
$packages = array();
return $this->renderPackageTable($packages, 'Owned Packages'); if ($packages) {
} $package_ids = mpull($packages, 'getID');
private function renderAllView() { $owners = id(new PhabricatorOwnersOwner())->loadAllWhere(
$packages = array(); 'packageID IN (%Ld)',
$package_ids);
return $this->renderPackageTable($packages, 'All Packages'); $paths = id(new PhabricatorOwnersPath())->loadAllWhere(
} 'packageID in (%Ld)',
$package_ids);
private function renderPackageTable(array $packages, $header) { $phids = array();
foreach ($owners as $owner) {
$phids[$owner->getUserPHID()] = true;
}
foreach ($paths as $path) {
$phids[$path->getRepositoryPHID()] = true;
}
$phids = array_keys($phids);
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$owners = mgroup($owners, 'getPackageID');
$paths = mgroup($paths, 'getPackageID');
} else {
$handles = array();
$owners = array();
$paths = array();
}
$rows = array(); $rows = array();
foreach ($packages as $package) { foreach ($packages as $package) {
$pkg_owners = idx($owners, $package->getID(), array());
foreach ($pkg_owners as $key => $owner) {
$pkg_owners[$key] = $handles[$owner->getUserPHID()]->renderLink();
if ($owner->getUserPHID() == $package->getPrimaryOwnerPHID()) {
$pkg_owners[$key] = '<strong>'.$pkg_owners[$key].'</strong>';
}
}
$pkg_owners = implode('<br />', $pkg_owners);
$pkg_paths = idx($paths, $package->getID(), array());
foreach ($pkg_paths as $key => $path) {
$repo = $handles[$path->getRepositoryPHID()]->getName();
$pkg_paths[$key] =
'<strong>'.$repo.'</strong> '.
phutil_escape_html($path->getPath());
}
$pkg_paths = implode('<br />', $pkg_paths);
$rows[] = array( $rows[] = array(
'x', phutil_render_tag(
'y', 'a',
'z', array(
'href' => '/owners/package/'.$package->getID().'/',
),
phutil_escape_html($package->getName())),
$pkg_owners,
$pkg_paths,
); );
} }
@ -159,7 +225,7 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
)); ));
$table->setColumnClasses( $table->setColumnClasses(
array( array(
'', 'pri',
'', '',
'wide wrap', 'wide wrap',
)); ));

View file

@ -7,7 +7,11 @@
phutil_require_module('phabricator', 'applications/owners/controller/base'); phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/owner');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'applications/owners/storage/path');
phutil_require_module('phabricator', 'applications/phid/handle/data'); phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/form/base'); phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit'); phutil_require_module('phabricator', 'view/form/control/submit');

View file

@ -24,7 +24,7 @@ class PhabricatorOwnersOwner extends PhabricatorOwnersDAO {
public function getConfiguration() { public function getConfiguration() {
return array( return array(
self::CONFIG_TIMESTAMPS => false, self::CONFIG_TIMESTAMPS => false,
); ) + parent::getConfiguration();
} }
} }

View file

@ -23,16 +23,110 @@ class PhabricatorOwnersPackage extends PhabricatorOwnersDAO {
protected $description; protected $description;
protected $primaryOwnerPHID; protected $primaryOwnerPHID;
private $unsavedOwners;
private $unsavedPaths;
public function getConfiguration() { public function getConfiguration() {
return array( return array(
// This information is better available from the history table. // This information is better available from the history table.
self::CONFIG_TIMESTAMPS => false, self::CONFIG_TIMESTAMPS => false,
self::CONFIG_AUX_PHID => true, self::CONFIG_AUX_PHID => true,
); ) + parent::getConfiguration();
} }
public function generatePHID() { public function generatePHID() {
return PhabricatorPHID::generateNew('OPKG'); return PhabricatorPHID::generateNewPHID('OPKG');
}
public function attachUnsavedOwners(array $owners) {
$this->unsavedOwners = $owners;
return $this;
}
public function attachUnsavedPaths(array $paths) {
$this->unsavedPaths = $paths;
return $this;
}
public function loadOwners() {
if (!$this->getID()) {
return array();
}
return id(new PhabricatorOwnersOwner())->loadAllWhere(
'packageID = %d',
$this->getID());
}
public function loadPaths() {
if (!$this->getID()) {
return array();
}
return id(new PhabricatorOwnersPath())->loadAllWhere(
'packageID = %d',
$this->getID());
}
public function save() {
// TODO: Transactions!
$ret = parent::save();
if ($this->unsavedOwners) {
$new_owners = array_fill_keys($this->unsavedOwners, true);
$cur_owners = array();
foreach ($this->loadOwners() as $owner) {
if (empty($new_owners[$owner->getUserPHID()])) {
$owner->delete();
continue;
}
$cur_owners[$owner->getUserPHID()] = true;
}
$add_owners = array_diff_key($new_owners, $cur_owners);
foreach ($add_owners as $phid => $ignored) {
$owner = new PhabricatorOwnersOwner();
$owner->setPackageID($this->getID());
$owner->setUserPHID($phid);
$owner->save();
}
unset($this->unsavedOwners);
}
if ($this->unsavedPaths) {
$new_paths = igroup($this->unsavedPaths, 'repositoryPHID', 'path');
$cur_paths = $this->loadPaths();
foreach ($cur_paths as $key => $path) {
if (empty($new_paths[$path->getRepositoryPHID()][$path->getPath()])) {
$path->delete();
unset($cur_paths[$key]);
}
}
$cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath');
foreach ($new_paths as $repository_phid => $paths) {
foreach ($paths as $path => $ignored) {
if (empty($cur_paths[$repository_phid][$path])) {
$obj = new PhabricatorOwnersPath();
$obj->setPackageID($this->getID());
$obj->setRepositoryPHID($repository_phid);
$obj->setPath($path);
$obj->save();
}
}
}
unset($this->unsavedPaths);
}
return $ret;
}
public function delete() {
foreach ($this->loadOwners() as $owner) {
$owner->delete();
}
foreach ($this->loadPaths() as $path) {
$path->delete();
}
return parent::delete();
} }
} }

View file

@ -7,7 +7,11 @@
phutil_require_module('phabricator', 'applications/owners/storage/base'); phutil_require_module('phabricator', 'applications/owners/storage/base');
phutil_require_module('phabricator', 'applications/owners/storage/owner');
phutil_require_module('phabricator', 'applications/owners/storage/path');
phutil_require_module('phabricator', 'applications/phid/storage/phid'); phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorOwnersPackage.php'); phutil_require_source('PhabricatorOwnersPackage.php');

View file

@ -25,7 +25,7 @@ class PhabricatorOwnersPath extends PhabricatorOwnersDAO {
public function getConfiguration() { public function getConfiguration() {
return array( return array(
self::CONFIG_TIMESTAMPS => false, self::CONFIG_TIMESTAMPS => false,
); ) + parent::getConfiguration();
} }
} }

View file

@ -201,6 +201,28 @@ class PhabricatorObjectHandleData {
$handles[$phid] = $handle; $handles[$phid] = $handle;
} }
break; break;
case PhabricatorPHIDConstants::PHID_TYPE_REPO:
$class = 'PhabricatorRepository';
PhutilSymbolLoader::loadClass($class);
$object = newv($class, array());
$repositories = $object->loadAllWhere('phid in (%Ls)', $phids);
$repositories = mpull($repositories, null, 'getPHID');
foreach ($phids as $phid) {
$handle = new PhabricatorObjectHandle();
$handle->setPHID($phid);
$handle->setType($type);
if (empty($repositories[$phid])) {
$handle->setName('Unknown Repository');
} else {
$repository = $repositories[$phid];
$handle->setName($repository->getCallsign());
$handle->setURI('/diffusion/'.$repository->getCallsign().'/');
}
$handles[$phid] = $handle;
}
break;
default: default:
$loader = null; $loader = null;
if (isset($external_loaders[$type])) { if (isset($external_loaders[$type])) {

View file

@ -22,20 +22,25 @@ final class AphrontPanelView extends AphrontView {
const WIDTH_FORM = 'form'; const WIDTH_FORM = 'form';
const WIDTH_WIDE = 'wide'; const WIDTH_WIDE = 'wide';
private $createButton; private $buttons = array();
private $header; private $header;
private $width; private $width;
public function setCreateButton($create_button, $href) { public function setCreateButton($create_button, $href) {
$this->addButton(
phutil_render_tag(
'a',
array(
'href' => $href,
'class' => 'button green',
),
$create_button));
$this->createButton = phutil_render_tag( return $this;
'a', }
array(
'href' => $href,
'class' => 'create-button button green',
),
$create_button);
public function addButton($button) {
$this->buttons[] = $button;
return $this; return $this;
} }
@ -56,10 +61,12 @@ final class AphrontPanelView extends AphrontView {
$header = null; $header = null;
} }
if ($this->createButton !== null) { $buttons = null;
$button = $this->createButton; if ($this->buttons) {
} else { $buttons =
$button = null; '<div class="aphront-panel-view-buttons">'.
implode(" ", $this->buttons).
'</div>';
} }
$table = $this->renderChildren(); $table = $this->renderChildren();
@ -73,7 +80,7 @@ final class AphrontPanelView extends AphrontView {
return return
'<div class="'.implode(' ', $class).'">'. '<div class="'.implode(' ', $class).'">'.
$button. $buttons.
$header. $header.
$table. $table.
'</div>'; '</div>';

View file

@ -6,6 +6,7 @@
background: #f6f6f6; background: #f6f6f6;
border-bottom: 1px solid #bbbbbb; border-bottom: 1px solid #bbbbbb;
width: 100%; width: 100%;
margin-bottom: 2em;
} }
.aphront-list-filter-view-buttons { .aphront-list-filter-view-buttons {
@ -24,7 +25,7 @@
.aphront-list-filter-view-controls .aphront-form-view { .aphront-list-filter-view-controls .aphront-form-view {
border-width: 0; border-width: 0;
padding: 0 0 6px; padding: 12px 0 6px;
} }
.aphront-list-filter-view-controls .aphront-form-view .aphront-form-label { .aphront-list-filter-view-controls .aphront-form-view .aphront-form-label {

View file

@ -17,7 +17,7 @@
padding: 2px 0 8px; padding: 2px 0 8px;
} }
.aphront-panel-view a.create-button { .aphront-panel-view-buttons {
float: right; float: right;
} }