mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Some owners read workflows.
This commit is contained in:
parent
65e1386753
commit
5038ab850c
25 changed files with 1026 additions and 28 deletions
|
@ -117,7 +117,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'aphront-tokenizer-control-css' =>
|
||||
array(
|
||||
'uri' => '/res/a3d23074/rsrc/css/aphront/tokenizer.css',
|
||||
'uri' => '/res/190349be/rsrc/css/aphront/tokenizer.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -297,6 +297,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/objectselector/object-selector.css',
|
||||
),
|
||||
'owners-path-editor-css' =>
|
||||
array(
|
||||
'uri' => '/res/f40dc6b1/rsrc/css/application/owners/owners-path-editor.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/owners/owners-path-editor.css',
|
||||
),
|
||||
'phabricator-profile-css' =>
|
||||
array(
|
||||
'uri' => '/res/259ad37f/rsrc/css/application/people/profile.css',
|
||||
|
@ -503,16 +512,28 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'herald-rule-editor' =>
|
||||
array(
|
||||
'uri' => '/res/8b5e9d5e/rsrc/js/application/herald/HeraldRuleEditor.js',
|
||||
'uri' => '/res/ec8e2110/rsrc/js/application/herald/HeraldRuleEditor.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'multirow-row-manager',
|
||||
1 => 'javelin-lib-dev',
|
||||
2 => 'javelin-typeahead-dev',
|
||||
3 => 'path-typeahead',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/herald/HeraldRuleEditor.js',
|
||||
),
|
||||
'path-typeahead' =>
|
||||
array(
|
||||
'uri' => '/res/42fb76c3/rsrc/js/application/herald/PathTypeahead.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-lib-dev',
|
||||
1 => 'javelin-typeahead-dev',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/herald/PathTypeahead.js',
|
||||
),
|
||||
'javelin-behavior-maniphest-transaction-controls' =>
|
||||
array(
|
||||
'uri' => '/res/fc6a8722/rsrc/js/application/maniphest/behavior-transaction-controls.js',
|
||||
|
@ -523,6 +544,30 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/maniphest/behavior-transaction-controls.js',
|
||||
),
|
||||
'javelin-behavior-owners-path-editor' =>
|
||||
array(
|
||||
'uri' => '/res/7568aa22/rsrc/js/application/owners/owners-path-editor.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'owners-path-editor',
|
||||
1 => 'javelin-lib-dev',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/owners/owners-path-editor.js',
|
||||
),
|
||||
'owners-path-editor' =>
|
||||
array(
|
||||
'uri' => '/res/b01c1ca9/rsrc/js/application/owners/OwnersPathEditor.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'multirow-row-manager',
|
||||
1 => 'javelin-lib-dev',
|
||||
2 => 'javelin-typeahead-dev',
|
||||
3 => 'path-typeahead',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/owners/OwnersPathEditor.js',
|
||||
),
|
||||
'javelin-magical-init' =>
|
||||
array(
|
||||
'uri' => '/res/76614f84/rsrc/js/javelin/init.dev.js',
|
||||
|
@ -598,7 +643,7 @@ celerity_register_resource_map(array(
|
|||
), array (
|
||||
'packages' =>
|
||||
array (
|
||||
'ce1b9ed3' =>
|
||||
'e3ec35d7' =>
|
||||
array (
|
||||
'name' => 'core.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -618,7 +663,7 @@ celerity_register_resource_map(array(
|
|||
12 => 'phabricator-remarkup-css',
|
||||
13 => 'syntax-highlighting-css',
|
||||
),
|
||||
'uri' => '/res/pkg/ce1b9ed3/core.pkg.css',
|
||||
'uri' => '/res/pkg/e3ec35d7/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'76f3c1f8' =>
|
||||
|
@ -665,20 +710,20 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'reverse' =>
|
||||
array (
|
||||
'phabricator-core-css' => 'ce1b9ed3',
|
||||
'phabricator-core-buttons-css' => 'ce1b9ed3',
|
||||
'phabricator-standard-page-view' => 'ce1b9ed3',
|
||||
'aphront-dialog-view-css' => 'ce1b9ed3',
|
||||
'aphront-form-view-css' => 'ce1b9ed3',
|
||||
'aphront-panel-view-css' => 'ce1b9ed3',
|
||||
'aphront-side-nav-view-css' => 'ce1b9ed3',
|
||||
'aphront-table-view-css' => 'ce1b9ed3',
|
||||
'aphront-crumbs-view-css' => 'ce1b9ed3',
|
||||
'aphront-tokenizer-control-css' => 'ce1b9ed3',
|
||||
'aphront-typeahead-control-css' => 'ce1b9ed3',
|
||||
'phabricator-directory-css' => 'ce1b9ed3',
|
||||
'phabricator-remarkup-css' => 'ce1b9ed3',
|
||||
'syntax-highlighting-css' => 'ce1b9ed3',
|
||||
'phabricator-core-css' => 'e3ec35d7',
|
||||
'phabricator-core-buttons-css' => 'e3ec35d7',
|
||||
'phabricator-standard-page-view' => 'e3ec35d7',
|
||||
'aphront-dialog-view-css' => 'e3ec35d7',
|
||||
'aphront-form-view-css' => 'e3ec35d7',
|
||||
'aphront-panel-view-css' => 'e3ec35d7',
|
||||
'aphront-side-nav-view-css' => 'e3ec35d7',
|
||||
'aphront-table-view-css' => 'e3ec35d7',
|
||||
'aphront-crumbs-view-css' => 'e3ec35d7',
|
||||
'aphront-tokenizer-control-css' => 'e3ec35d7',
|
||||
'aphront-typeahead-control-css' => 'e3ec35d7',
|
||||
'phabricator-directory-css' => 'e3ec35d7',
|
||||
'phabricator-remarkup-css' => 'e3ec35d7',
|
||||
'syntax-highlighting-css' => 'e3ec35d7',
|
||||
'differential-core-view-css' => '76f3c1f8',
|
||||
'differential-changeset-view-css' => '76f3c1f8',
|
||||
'differential-revision-detail-css' => '76f3c1f8',
|
||||
|
|
|
@ -61,6 +61,7 @@ phutil_register_library_map(array(
|
|||
'AphrontSideNavView' => 'view/layout/sidenav',
|
||||
'AphrontTableView' => 'view/control/table',
|
||||
'AphrontTokenizerTemplateView' => 'view/control/tokenizer',
|
||||
'AphrontTypeaheadTemplateView' => 'view/control/typeahead',
|
||||
'AphrontURIMapper' => 'aphront/mapper',
|
||||
'AphrontView' => 'view/base',
|
||||
'AphrontWebpageResponse' => 'aphront/response/webpage',
|
||||
|
@ -180,6 +181,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionLastModifiedQuery' => 'applications/diffusion/query/lastmodified/base',
|
||||
'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
|
||||
'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/base',
|
||||
'DiffusionPathCompleteController' => 'applications/diffusion/controller/pathcomplete',
|
||||
'DiffusionPathValidateController' => 'applications/diffusion/controller/pathvalidate',
|
||||
'DiffusionRepositoryController' => 'applications/diffusion/controller/repository',
|
||||
'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
|
||||
'DiffusionRequest' => 'applications/diffusion/request/base',
|
||||
|
@ -487,6 +490,7 @@ phutil_register_library_map(array(
|
|||
'AphrontSideNavView' => 'AphrontView',
|
||||
'AphrontTableView' => 'AphrontView',
|
||||
'AphrontTokenizerTemplateView' => 'AphrontView',
|
||||
'AphrontTypeaheadTemplateView' => 'AphrontView',
|
||||
'AphrontWebpageResponse' => 'AphrontResponse',
|
||||
'CelerityResourceController' => 'AphrontController',
|
||||
'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
|
||||
|
@ -566,6 +570,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionHistoryTableView' => 'DiffusionView',
|
||||
'DiffusionHomeController' => 'DiffusionController',
|
||||
'DiffusionLastModifiedController' => 'DiffusionController',
|
||||
'DiffusionPathCompleteController' => 'DiffusionController',
|
||||
'DiffusionPathValidateController' => 'DiffusionController',
|
||||
'DiffusionRepositoryController' => 'DiffusionController',
|
||||
'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery',
|
||||
'DiffusionSvnDiffQuery' => 'DiffusionDiffQuery',
|
||||
|
|
|
@ -218,6 +218,12 @@ class AphrontDefaultApplicationConfiguration
|
|||
'$'
|
||||
=> 'DiffusionLastModifiedController',
|
||||
),
|
||||
'services/' => array(
|
||||
'path/' => array(
|
||||
'complete/$' => 'DiffusionPathCompleteController',
|
||||
'validate/$' => 'DiffusionPathValidateController',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
'/daemon/' => array(
|
||||
|
@ -255,6 +261,7 @@ class AphrontDefaultApplicationConfiguration
|
|||
'$' => 'PhabricatorOwnersListController',
|
||||
'view/(?P<view>[^/]+)/$' => 'PhabricatorOwnersListController',
|
||||
'package/(?P<id>\d+)/$' => 'PhabricatorOwnersDetailController',
|
||||
'new/$' => 'PhabricatorOwnersDetailController',
|
||||
),
|
||||
|
||||
);
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<?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 DiffusionPathCompleteController extends DiffusionController {
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
// Don't build a DiffusionRequest.
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
$repository_phid = $request->getStr('repositoryPHID');
|
||||
$repository = id(new PhabricatorRepository())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$repository_phid);
|
||||
if (!$repository) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$query_path = $request->getStr('q');
|
||||
$query_path = ltrim($query_path, '/');
|
||||
if (preg_match('@/$@', $query_path)) {
|
||||
$query_dir = $query_path;
|
||||
} else {
|
||||
$query_dir = dirname($query_path);
|
||||
if ($query_dir == '.') {
|
||||
$query_dir = '';
|
||||
}
|
||||
}
|
||||
|
||||
$drequest = DiffusionRequest::newFromAphrontRequestDictionary(
|
||||
array(
|
||||
'callsign' => $repository->getCallsign(),
|
||||
'path' => $query_dir,
|
||||
'nobranch' => true,
|
||||
));
|
||||
|
||||
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$paths = $browse_query->loadPaths();
|
||||
|
||||
$output = array();
|
||||
foreach ($paths as $path) {
|
||||
$full_path = $query_dir.$path->getPath();
|
||||
if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
|
||||
$full_path .= '/';
|
||||
}
|
||||
$output[] = array('/'.$full_path, null, substr(md5($full_path), 0, 7));
|
||||
}
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent($output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/400');
|
||||
phutil_require_module('phabricator', 'aphront/response/ajax');
|
||||
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/query/browse/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/request/base');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DiffusionPathCompleteController.php');
|
|
@ -0,0 +1,80 @@
|
|||
<?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 DiffusionPathValidateController extends DiffusionController {
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
// Don't build a DiffusionRequest.
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
$repository_phid = $request->getStr('repositoryPHID');
|
||||
$repository = id(new PhabricatorRepository())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$repository_phid);
|
||||
if (!$repository) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$path = $request->getStr('path');
|
||||
$path = ltrim($path, '/');
|
||||
|
||||
$drequest = DiffusionRequest::newFromAphrontRequestDictionary(
|
||||
array(
|
||||
'callsign' => $repository->getCallsign(),
|
||||
'path' => $path,
|
||||
'nobranch' => true,
|
||||
));
|
||||
|
||||
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$browse_query->needValidityOnly(true);
|
||||
$valid = $browse_query->loadPaths();
|
||||
|
||||
if (!$valid) {
|
||||
switch ($browse_query->getReasonForEmptyResultSet()) {
|
||||
case DiffusionBrowseQuery::REASON_IS_FILE:
|
||||
$valid = true;
|
||||
break;
|
||||
case DiffusionBrowseQuery::REASON_IS_EMPTY:
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$output = array(
|
||||
'valid' => (bool)$valid,
|
||||
);
|
||||
|
||||
if (!$valid) {
|
||||
$branch = $drequest->getBranch();
|
||||
if ($branch) {
|
||||
$message = 'Not found in '.$branch;
|
||||
} else {
|
||||
$message = 'Not found at HEAD';
|
||||
}
|
||||
} else {
|
||||
$message = 'OK';
|
||||
}
|
||||
|
||||
$output['message'] = $message;
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent($output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/400');
|
||||
phutil_require_module('phabricator', 'aphront/response/ajax');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/query/browse/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/request/base');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DiffusionPathValidateController.php');
|
|
@ -23,6 +23,7 @@ abstract class DiffusionBrowseQuery {
|
|||
protected $reason;
|
||||
protected $existedAtCommit;
|
||||
protected $deletedAtCommit;
|
||||
protected $validityOnly;
|
||||
|
||||
const REASON_IS_FILE = 'is-file';
|
||||
const REASON_IS_DELETED = 'is-deleted';
|
||||
|
@ -79,5 +80,14 @@ abstract class DiffusionBrowseQuery {
|
|||
return $this->executeQuery();
|
||||
}
|
||||
|
||||
final public function shouldOnlyTestValidity() {
|
||||
return $this->validityOnly;
|
||||
}
|
||||
|
||||
final public function needValidityOnly($need_validity_only) {
|
||||
$this->validityOnly = $need_validity_only;
|
||||
return $this;
|
||||
}
|
||||
|
||||
abstract protected function executeQuery();
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ final class DiffusionGitBrowseQuery extends DiffusionBrowseQuery {
|
|||
return array();
|
||||
}
|
||||
|
||||
if ($this->shouldOnlyTestValidity()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list($stdout) = execx(
|
||||
"(cd %s && git ls-tree -l %s:%s)",
|
||||
$local_path,
|
||||
|
|
|
@ -103,6 +103,10 @@ final class DiffusionSvnBrowseQuery extends DiffusionBrowseQuery {
|
|||
return array();
|
||||
}
|
||||
|
||||
if ($this->shouldOnlyTestValidity()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$sql = array();
|
||||
foreach ($index as $row) {
|
||||
$sql[] = '('.(int)$row['pathID'].', '.(int)$row['maxCommit'].')';
|
||||
|
|
|
@ -67,12 +67,12 @@ class DiffusionRequest {
|
|||
$object->commit = idx($data, 'commit');
|
||||
$object->path = idx($data, 'path');
|
||||
|
||||
$object->initializeFromAphrontRequestDictionary();
|
||||
$object->initializeFromAphrontRequestDictionary($data);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected function initializeFromAphrontRequestDictionary() {
|
||||
protected function initializeFromAphrontRequestDictionary(array $data) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -18,14 +18,16 @@
|
|||
|
||||
class DiffusionGitRequest extends DiffusionRequest {
|
||||
|
||||
protected function initializeFromAphrontRequestDictionary() {
|
||||
parent::initializeFromAphrontRequestDictionary();
|
||||
protected function initializeFromAphrontRequestDictionary(array $data) {
|
||||
parent::initializeFromAphrontRequestDictionary($data);
|
||||
|
||||
$path = $this->path;
|
||||
$parts = explode('/', $path);
|
||||
|
||||
if (empty($data['nobranch'])) {
|
||||
$branch = array_shift($parts);
|
||||
$this->branch = $this->decodeBranchName($branch);
|
||||
}
|
||||
|
||||
foreach ($parts as $key => $part) {
|
||||
// Prevent any hyjinx since we're ultimately shipping this to the
|
||||
|
|
|
@ -18,11 +18,135 @@
|
|||
|
||||
class PhabricatorOwnersDetailController extends PhabricatorOwnersController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = idx($data, 'id');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
return $this->buildStandardPageResponse(
|
||||
'quack',
|
||||
$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;
|
||||
|
||||
|
||||
$token_primary_owner = array();
|
||||
$token_all_owners = array();
|
||||
|
||||
$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(
|
||||
'title' => 'detail',
|
||||
'root' => 'path-editor',
|
||||
'table' => 'paths',
|
||||
'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->setHeader($title);
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
|
||||
$panel->appendChild($form);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$panel,
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,18 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'applications/owners/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/package');
|
||||
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/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorOwnersDetailController.php');
|
||||
|
|
|
@ -26,6 +26,9 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
|
|||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$views = array(
|
||||
'owned' => 'Owned Packages',
|
||||
'all' => 'All Packages',
|
||||
|
@ -57,7 +60,7 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
|
|||
|
||||
switch ($this->view) {
|
||||
case 'search':
|
||||
$content = 'search goes here';
|
||||
$content = $this->renderPackageTable(array(), 'Search Results');
|
||||
break;
|
||||
case 'owned':
|
||||
$content = $this->renderOwnedView();
|
||||
|
@ -67,6 +70,54 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
|
|||
break;
|
||||
}
|
||||
|
||||
$filter = new AphrontListFilterView();
|
||||
$filter->addButton(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/owners/new/',
|
||||
'class' => 'green button',
|
||||
),
|
||||
'Create New Package'));
|
||||
|
||||
$owners_search_value = array();
|
||||
if ($request->getArr('owner')) {
|
||||
$phids = $request->getArr('owner');
|
||||
$phid = reset($phids);
|
||||
$handles = id(new PhabricatorObjectHandleData(array($phid)))
|
||||
->loadHandles();
|
||||
$owners_search_value = array(
|
||||
$phid => $handles[$phid]->getFullName(),
|
||||
);
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->setAction('/owners/view/search/')
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('name')
|
||||
->setLabel('Name')
|
||||
->setValue($request->getStr('name')))
|
||||
->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/users/')
|
||||
->setLimit(1)
|
||||
->setName('owner')
|
||||
->setLabel('Owner')
|
||||
->setValue($owners_search_value))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('path')
|
||||
->setLabel('Path')
|
||||
->setValue($request->getStr('path')))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Search for Packages'));
|
||||
|
||||
$filter->appendChild($form);
|
||||
|
||||
$nav->appendChild($filter);
|
||||
$nav->appendChild($content);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
|
|
|
@ -7,6 +7,16 @@
|
|||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/owners/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/layout/listfilter');
|
||||
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_source('PhabricatorOwnersListController.php');
|
||||
|
|
|
@ -234,6 +234,12 @@ class PhabricatorRepositoryEditController
|
|||
$request->getStr('default-branch'));
|
||||
}
|
||||
|
||||
$repository->setDetail(
|
||||
'default-owners-path',
|
||||
$request->getStr(
|
||||
'default-owners-path',
|
||||
'/'));
|
||||
|
||||
$repository->setDetail(
|
||||
'detail-parser',
|
||||
$request->getStr(
|
||||
|
@ -358,6 +364,17 @@ class PhabricatorRepositoryEditController
|
|||
'Default <strong>remote</strong> branch to show in Diffusion.'));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('default-owners-path')
|
||||
->setLabel('Default Owners Path')
|
||||
->setValue(
|
||||
$repository->getDetail(
|
||||
'default-owners-path',
|
||||
'/'))
|
||||
->setCaption('Default path in Owners tool.'));
|
||||
|
||||
$parsers = id(new PhutilSymbolLoader())
|
||||
->setAncestorClass('PhabricatorRepositoryCommitMessageDetailParser')
|
||||
->selectSymbolsWithoutLoading();
|
||||
|
|
81
src/view/control/typeahead/AphrontTypeaheadTemplateView.php
Normal file
81
src/view/control/typeahead/AphrontTypeaheadTemplateView.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?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 AphrontTypeaheadTemplateView extends AphrontView {
|
||||
|
||||
private $value;
|
||||
private $name;
|
||||
private $id;
|
||||
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setValue(array $value) {
|
||||
$this->value = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getValue() {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('aphront-typeahead-control-css');
|
||||
|
||||
$id = $this->id;
|
||||
$name = $this->getName();
|
||||
$values = nonempty($this->getValue(), array());
|
||||
|
||||
$tokens = array();
|
||||
foreach ($values as $key => $value) {
|
||||
$tokens[] = $this->renderToken($key, $value);
|
||||
}
|
||||
|
||||
$input = javelin_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'name' => $name,
|
||||
'class' => 'jx-typeahead-input',
|
||||
'sigil' => 'typeahead',
|
||||
'type' => 'text',
|
||||
'value' => $this->value,
|
||||
'autocomplete' => 'off',
|
||||
));
|
||||
|
||||
return javelin_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'id' => $id,
|
||||
'sigil' => 'typeahead-hardpoint',
|
||||
'class' => 'jx-typeahead-hardpoint',
|
||||
),
|
||||
$input.
|
||||
'<div style="clear: both;"></div>');
|
||||
}
|
||||
}
|
16
src/view/control/typeahead/__init__.php
Normal file
16
src/view/control/typeahead/__init__.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('AphrontTypeaheadTemplateView.php');
|
|
@ -14,6 +14,8 @@ div.jx-tokenizer-container {
|
|||
background: #fff;
|
||||
border: 1px solid #96A6C5;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
var.jx-tokenizer-metrics {
|
||||
|
|
37
webroot/rsrc/css/application/owners/owners-path-editor.css
Normal file
37
webroot/rsrc/css/application/owners/owners-path-editor.css
Normal file
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @provides owners-path-editor-css
|
||||
*/
|
||||
|
||||
.owners-path-editor-table {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.owners-path-editor-table td {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.owners-path-editor-table select {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.owners-path-editor-table input {
|
||||
width: 550px;
|
||||
}
|
||||
|
||||
.owners-path-editor-table div.error-display {
|
||||
width: 200px;
|
||||
padding: 4px 12px 0;
|
||||
}
|
||||
|
||||
.owners-path-editor-table div.validating {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.owners-path-editor-table div.invalid {
|
||||
color: #aa0000;
|
||||
}
|
||||
|
||||
.owners-path-editor-table div.valid {
|
||||
color: #00aa00;
|
||||
font-weight: bold;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
* @requires multirow-row-manager
|
||||
* javelin-lib-dev
|
||||
* javelin-typeahead-dev
|
||||
* path-typeahead
|
||||
* @provides herald-rule-editor
|
||||
* @javelin
|
||||
*/
|
||||
|
|
202
webroot/rsrc/js/application/herald/PathTypeahead.js
Normal file
202
webroot/rsrc/js/application/herald/PathTypeahead.js
Normal file
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
* @requires javelin-lib-dev
|
||||
* javelin-typeahead-dev
|
||||
* @provides path-typeahead
|
||||
* @javelin
|
||||
*/
|
||||
|
||||
JX.install('PathTypeahead', {
|
||||
construct : function(config) {
|
||||
this._repositorySelect = config.repo_select;
|
||||
this._hardpoint = config.hardpoint;
|
||||
this._input = config.path_input;
|
||||
this._completeURI = config.completeURI;
|
||||
this._validateURI = config.validateURI;
|
||||
this._errorDisplay = config.error_display;
|
||||
|
||||
/*
|
||||
* Default values to preload the typeahead with, for extremely common
|
||||
* cases.
|
||||
*/
|
||||
this._textInputValues = config.repositoryDefaultPaths;
|
||||
|
||||
this._initializeDatasource();
|
||||
this._initializeTypeahead(this._input);
|
||||
},
|
||||
members : {
|
||||
/*
|
||||
* DOM <select> elem for choosing the repository of a path.
|
||||
*/
|
||||
_repositorySelect : null,
|
||||
/*
|
||||
* DOM parent div "hardpoint" to be passed to the JX.Typeahead.
|
||||
*/
|
||||
_hardpoint : null,
|
||||
/*
|
||||
* DOM element to display errors.
|
||||
*/
|
||||
_errorDisplay : null,
|
||||
/*
|
||||
* URI to query for typeahead results, to be passed to the
|
||||
* TypeaheadOnDemandSource.
|
||||
*/
|
||||
_completeURI : null,
|
||||
|
||||
/*
|
||||
* Underlying JX.TypeaheadOnDemandSource instance
|
||||
*/
|
||||
_datasource : null,
|
||||
|
||||
/*
|
||||
* Underlying JX.Typeahead instance
|
||||
*/
|
||||
_typeahead : null,
|
||||
|
||||
/*
|
||||
* Underlying input
|
||||
*/
|
||||
_input : null,
|
||||
|
||||
/*
|
||||
* Whenever the user changes the typeahead value, we track the change
|
||||
* here, keyed by the selected repository ID. That way, we can restore
|
||||
* typed values if they change the repository choice and then change back.
|
||||
*/
|
||||
_textInputValues : null,
|
||||
|
||||
/*
|
||||
* Configurable endpoint for server-side path validation
|
||||
*/
|
||||
_validateURI : null,
|
||||
|
||||
/*
|
||||
* Keep the validation AJAX request so we don't send several.
|
||||
*/
|
||||
_validationInflight : null,
|
||||
|
||||
/*
|
||||
* Installs path-specific behaviors and then starts the underlying
|
||||
* typeahead.
|
||||
*/
|
||||
start : function() {
|
||||
if (this._typeahead.getValue()) {
|
||||
this._textInputValues[this._repositorySelect.value] =
|
||||
this._typeahead.getValue();
|
||||
}
|
||||
|
||||
this._typeahead.listen(
|
||||
'change',
|
||||
JX.bind(this, function(value) {
|
||||
this._textInputValues[this._repositorySelect.value] = value;
|
||||
this._validate();
|
||||
}));
|
||||
|
||||
this._typeahead.listen(
|
||||
'choose',
|
||||
JX.bind(this, function() {
|
||||
JX.defer(
|
||||
JX.bind(this._typeahead, this._typeahead.refresh));
|
||||
}));
|
||||
|
||||
var repo_set_input = JX.bind(this, this._onrepochange);
|
||||
|
||||
this._typeahead.listen('start', repo_set_input);
|
||||
JX.DOM.listen(
|
||||
this._repositorySelect,
|
||||
'change',
|
||||
null,
|
||||
repo_set_input);
|
||||
|
||||
this._typeahead.start();
|
||||
this._validate();
|
||||
},
|
||||
|
||||
_onrepochange : function() {
|
||||
this._setPathInputBasedOnRepository(
|
||||
this._typeahead,
|
||||
this._textInputValues);
|
||||
|
||||
this._datasource.setAuxiliaryData(
|
||||
{repositoryPHID : this._repositorySelect.value}
|
||||
);
|
||||
},
|
||||
|
||||
_setPathInputBasedOnRepository : function(typeahead, lookup) {
|
||||
if (lookup[this._repositorySelect.value]) {
|
||||
typeahead.setValue(lookup[this._repositorySelect.value]);
|
||||
} else {
|
||||
typeahead.setValue('/');
|
||||
}
|
||||
},
|
||||
|
||||
_initializeDatasource : function() {
|
||||
this._datasource = new JX.TypeaheadOnDemandSource(this._completeURI);
|
||||
this._datasource.setNormalizer(this._datasourceNormalizer);
|
||||
this._datasource.setQueryDelay(40);
|
||||
},
|
||||
|
||||
/*
|
||||
* Construct and initialize the Typeahead.
|
||||
* Must be called after initializing the datasource.
|
||||
*/
|
||||
_initializeTypeahead : function(path_input) {
|
||||
this._typeahead = new JX.Typeahead(this._hardpoint, path_input);
|
||||
this._datasource.setMaximumResultCount(15);
|
||||
this._typeahead.setDatasource(this._datasource);
|
||||
},
|
||||
|
||||
_datasourceNormalizer : function(str) {
|
||||
return ('' + str).replace(/[\/]+/g, '\/');
|
||||
},
|
||||
|
||||
_validate : function() {
|
||||
var input = this._input;
|
||||
var repo_id = this._repositorySelect.value;
|
||||
var input_value = input.value;
|
||||
var error_display = this._errorDisplay;
|
||||
|
||||
if (!input_value.length) {
|
||||
input.value = '/';
|
||||
input_value = '/';
|
||||
}
|
||||
|
||||
if (this._validationInflight) {
|
||||
this._validationInflight.abort();
|
||||
this._validationInflight = null;
|
||||
}
|
||||
|
||||
var validation_request = new JX.Request(
|
||||
this._validateURI,
|
||||
function(payload) {
|
||||
// Don't change validation display state if the input has been
|
||||
// changed since we started validation
|
||||
if (input.value === input_value) {
|
||||
if (payload.valid) {
|
||||
JX.DOM.alterClass(error_display, 'invalid', false);
|
||||
JX.DOM.alterClass(error_display, 'valid', true);
|
||||
} else {
|
||||
JX.DOM.alterClass(error_display, 'invalid', true);
|
||||
JX.DOM.alterClass(error_display, 'valid', false);
|
||||
}
|
||||
JX.DOM.setContent(error_display, payload.message);
|
||||
}
|
||||
});
|
||||
|
||||
validation_request.listen('finally', function() {
|
||||
JX.DOM.alterClass(error_display, 'validating', false);
|
||||
this._validationInflight = null;
|
||||
});
|
||||
|
||||
validation_request.setData(
|
||||
{
|
||||
repositoryPHID : repo_id,
|
||||
path : input_value
|
||||
});
|
||||
|
||||
this._validationInflight = validation_request;
|
||||
|
||||
validation_request.setTimeout(750);
|
||||
validation_request.send();
|
||||
}
|
||||
}
|
||||
});
|
171
webroot/rsrc/js/application/owners/OwnersPathEditor.js
Normal file
171
webroot/rsrc/js/application/owners/OwnersPathEditor.js
Normal file
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* @requires multirow-row-manager
|
||||
* javelin-lib-dev
|
||||
* javelin-typeahead-dev
|
||||
* path-typeahead
|
||||
* @provides owners-path-editor
|
||||
* @javelin
|
||||
*/
|
||||
|
||||
JX.install('OwnersPathEditor', {
|
||||
construct : function(config) {
|
||||
var root = JX.$(config.root);
|
||||
|
||||
this._rowManager = new JX.MultirowRowManager(
|
||||
JX.DOM.find(root, 'table', config.table));
|
||||
|
||||
JX.DOM.listen(
|
||||
JX.DOM.find(root, 'a', config.add_button),
|
||||
'click',
|
||||
null,
|
||||
JX.bind(this, this._onaddpath));
|
||||
|
||||
this._count = 0;
|
||||
this._repositories = config.repositories;
|
||||
this._inputTemplate = config.input_template;
|
||||
|
||||
this._completeURI = config.completeURI;
|
||||
this._validateURI = config.validateURI;
|
||||
this._repositoryDefaultPaths = config.repositoryDefaultPaths;
|
||||
|
||||
this._initializePaths(config.pathRefs);
|
||||
},
|
||||
members : {
|
||||
/*
|
||||
* MultirowRowManager for controlling add/remove behavior
|
||||
*/
|
||||
_rowManager : null,
|
||||
|
||||
/*
|
||||
* Array of objects with 'name' and 'repo_id' keys for
|
||||
* selecting the repository of a path.
|
||||
*/
|
||||
_repositories : null,
|
||||
|
||||
/*
|
||||
* How many rows have been created, for form name generation.
|
||||
*/
|
||||
_count : 0,
|
||||
/*
|
||||
* URL for the typeahead datasource.
|
||||
*/
|
||||
_completeURI : null,
|
||||
/*
|
||||
* URL for path validation requests.
|
||||
*/
|
||||
_validateURI : null,
|
||||
/*
|
||||
* Template typeahead markup to be copied per row.
|
||||
*/
|
||||
_inputTemplate : null,
|
||||
/*
|
||||
* Most packages will be in one repository, so remember whenever
|
||||
* the user chooses a repository, and use that repository as the
|
||||
* default for future rows.
|
||||
*/
|
||||
_lastRepositoryChoice : null,
|
||||
|
||||
_repositoryDefaultPaths : null,
|
||||
|
||||
/*
|
||||
* Initialize with 0 or more rows.
|
||||
* Adds one initial row if none are given.
|
||||
*/
|
||||
_initializePaths : function(path_refs) {
|
||||
for (var k in path_refs) {
|
||||
this.addPath(path_refs[k]);
|
||||
}
|
||||
if (!JX.keys(path_refs).length) {
|
||||
this.addPath();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Build a row.
|
||||
*/
|
||||
addPath : function(path_ref) {
|
||||
// Smart default repository. See _lastRepositoryChoice.
|
||||
if (path_ref) {
|
||||
this._lastRepositoryChoice = path_ref.repositoryPHID;
|
||||
}
|
||||
path_ref = path_ref || {};
|
||||
|
||||
var selected_repository = path_ref.repositoryPHID ||
|
||||
this._lastRepositoryChoice;
|
||||
var options = this._buildRepositoryOptions(selected_repository);
|
||||
var attrs = {
|
||||
name : "repo[" + this._count + "]"
|
||||
};
|
||||
var repo_select = JX.$N('select', attrs, options);
|
||||
|
||||
JX.DOM.listen(repo_select, 'change', null, JX.bind(this, function(e) {
|
||||
this._lastRepositoryChoice = repo_select.value;
|
||||
}));
|
||||
|
||||
var repo_cell = JX.$N('td', {}, repo_select);
|
||||
var typeahead_cell = JX.$N(
|
||||
'td',
|
||||
JX.HTML(this._inputTemplate));
|
||||
|
||||
// Text input for path.
|
||||
var path_input = JX.DOM.find(typeahead_cell, 'input');
|
||||
JX.copy(
|
||||
path_input,
|
||||
{
|
||||
value : path_ref.path || "",
|
||||
name : "path[" + this._count + "]",
|
||||
});
|
||||
|
||||
// The Typeahead requires a display div called hardpoint.
|
||||
var hardpoint = JX.DOM.find(
|
||||
typeahead_cell,
|
||||
'div',
|
||||
'typeahead-hardpoint');
|
||||
|
||||
var error_display = JX.$N(
|
||||
'div',
|
||||
{
|
||||
className : "error-display validating"
|
||||
},
|
||||
'Validating...');
|
||||
|
||||
var error_display_cell = JX.$N('td', {}, error_display);
|
||||
|
||||
var row = this._rowManager.addRow(
|
||||
[repo_cell, typeahead_cell, error_display_cell]);
|
||||
|
||||
new JX.PathTypeahead({
|
||||
repositoryDefaultPaths : this._repositoryDefaultPaths,
|
||||
repo_select : repo_select,
|
||||
path_input : path_input,
|
||||
hardpoint : hardpoint,
|
||||
error_display : error_display,
|
||||
completeURI : this._completeURI,
|
||||
validateURI : this._validateURI}).start();
|
||||
|
||||
this._count++;
|
||||
return row;
|
||||
},
|
||||
|
||||
_onaddpath : function(e) {
|
||||
e.kill();
|
||||
this.addPath();
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper to build the options for the repository choice dropdown.
|
||||
*/
|
||||
_buildRepositoryOptions : function(selected) {
|
||||
var repos = this._repositories;
|
||||
var result = [];
|
||||
for (var k in repos) {
|
||||
var attr = {
|
||||
value : k,
|
||||
selected : (selected == k)
|
||||
};
|
||||
result.push(JX.$N('option', attr, repos[k]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
});
|
10
webroot/rsrc/js/application/owners/owners-path-editor.js
Normal file
10
webroot/rsrc/js/application/owners/owners-path-editor.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* @requires owners-path-editor
|
||||
* javelin-lib-dev
|
||||
* @provides javelin-behavior-owners-path-editor
|
||||
* @javelin
|
||||
*/
|
||||
|
||||
JX.behavior('owners-path-editor', function(config) {
|
||||
new JX.OwnersPathEditor(config);
|
||||
});
|
Loading…
Reference in a new issue