Merge branch 'develop' of projects.ceondo.com:indefero into develop
This commit is contained in:
commit
8b2363fd6f
@ -1,62 +0,0 @@
|
|||||||
# monotone implementation notes
|
|
||||||
|
|
||||||
## general
|
|
||||||
|
|
||||||
This version of indefero contains an implementation of the monotone
|
|
||||||
automation interface. It needs at least monotone version 0.99
|
|
||||||
(interface version 13.0) or newer.
|
|
||||||
|
|
||||||
To set up a new IDF project with monotone quickly, all you need to do
|
|
||||||
is to create a new monotone database with
|
|
||||||
|
|
||||||
$ mtn db init -d project.mtn
|
|
||||||
|
|
||||||
in the configured repository path `$cfg['mtn_repositories']` and
|
|
||||||
configure `$cfg['mtn_db_access']` to "local".
|
|
||||||
|
|
||||||
To have a really workable setup, this database needs an initial commit
|
|
||||||
on the configured master branch of the project. This can be done easily
|
|
||||||
with
|
|
||||||
|
|
||||||
$ mkdir tmp && touch tmp/remove_me
|
|
||||||
$ mtn import -d project.mtn -b master.branch.name \
|
|
||||||
-m "initial commit" tmp
|
|
||||||
$ rm -rf tmp
|
|
||||||
|
|
||||||
Its expected that more scripts arrive soon to automate this and other
|
|
||||||
tasks in the future for (multi)forge setups.
|
|
||||||
|
|
||||||
## current state / internals
|
|
||||||
|
|
||||||
The implementation should be fairly stable and fast, though some
|
|
||||||
information, such as individual file sizes or last change information,
|
|
||||||
won't scale well with the tree size. Its expected that the mtn
|
|
||||||
automation interface improves in this area in the future and that
|
|
||||||
these parts can then be rewritten with speed in mind.
|
|
||||||
|
|
||||||
As the idf.conf-dist explains more in detail, different access patterns
|
|
||||||
are possible to retrieve changeset data from monotone. Please refer
|
|
||||||
to the documentation there for more information.
|
|
||||||
|
|
||||||
## indefero critique:
|
|
||||||
|
|
||||||
It was not always 100% clear what some of the abstract SCM API method
|
|
||||||
wanted in return. While it helped a lot to have prior art in form of the
|
|
||||||
SVN and git implementation, the documentation of the abstract IDF_Scm
|
|
||||||
should probably still be improved.
|
|
||||||
|
|
||||||
Since branch and tag names can be of arbitrary size, it was not possible
|
|
||||||
to display them completely in the default layout. This might be a problem
|
|
||||||
in other SCMs as well, in particular for the monotone implementation I
|
|
||||||
introduced a special filter, called "IDF_Views_Source_ShortenString".
|
|
||||||
|
|
||||||
The API methods getPathInfo() and getTree() return similar VCS "objects"
|
|
||||||
which unfortunately do not have a well-defined structure - this should
|
|
||||||
probably addressed in future indefero releases.
|
|
||||||
|
|
||||||
While the returned objects from getTree() contain all the needed
|
|
||||||
information, indefero doesn't seem to use them to sort the output
|
|
||||||
f.e. alphabetically or in such a way that directories are outputted
|
|
||||||
before files. It was unclear if the SCM implementor should do this
|
|
||||||
task or not and what the admired default sorting should be.
|
|
||||||
|
|
175
doc/syncmonotone.mdtext
Normal file
175
doc/syncmonotone.mdtext
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
# Plugin SyncMonotone by Thomas Keller (me@thomaskeller.biz)
|
||||||
|
|
||||||
|
The SyncMonotone plugin allow the direct creation and synchronisation of
|
||||||
|
monotone repositories with the InDefero database. It has been built to
|
||||||
|
work together with monotone's "super server" usher, which is used to control
|
||||||
|
several repositories at once, acts as proxy and single entrance.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
* a unixoid operating system
|
||||||
|
* monotone >= 0.99
|
||||||
|
* for a proxy setup with usher:
|
||||||
|
* boost headers (for usher compilation)
|
||||||
|
* a current version of usher
|
||||||
|
* a daemonizer, like supervise
|
||||||
|
|
||||||
|
## Installation of monotone
|
||||||
|
|
||||||
|
If you install monotone from a distribution package, ensure you do not
|
||||||
|
install and / or activate the server component. We just need a plain
|
||||||
|
client installation which usually consists only of the `mtn` binary and
|
||||||
|
a few docs.
|
||||||
|
|
||||||
|
If you install monotone from source (<http://monotone.ca/downloads.php>),
|
||||||
|
please follow the `INSTALL` document which comes with the software.
|
||||||
|
It contains detailed instructions, including all needed dependencies.
|
||||||
|
|
||||||
|
## Choose your indefero setup
|
||||||
|
|
||||||
|
The monotone plugin can be used in several different ways:
|
||||||
|
|
||||||
|
1. One database for everything. This is the easiest setup and of possible
|
||||||
|
use in case you do not want indefero to manage the access to your project.
|
||||||
|
Your `idf.php` should look like this:
|
||||||
|
|
||||||
|
$ cat idf.php
|
||||||
|
...
|
||||||
|
$cfg['mtn_path'] = 'mtn';
|
||||||
|
$cfg['mtn_opts'] = array('--no-workspace', '--no-standard-rcfiles');
|
||||||
|
$cfg['mtn_repositories'] = '/home/monotone/all_projects.mtn';
|
||||||
|
$cfg['mtn_remote_url'] = 'ssh://monotone@my.server.com:~all_projects.mtn';
|
||||||
|
$cfg['mtn_db_access'] = 'local';
|
||||||
|
...
|
||||||
|
|
||||||
|
Pro:
|
||||||
|
* easy to setup and to manage
|
||||||
|
|
||||||
|
Con:
|
||||||
|
* you need to give committers SSH access to your machine
|
||||||
|
* database lock problem: the database from which
|
||||||
|
indefero reads its data might be locked in case a user
|
||||||
|
syncs at the very moment via SSH
|
||||||
|
|
||||||
|
2. One database for every project. Similar to the above setup, but this
|
||||||
|
time you use the '%s' placeholder which is replaced with the short name
|
||||||
|
of the indefero project:
|
||||||
|
|
||||||
|
$ cat idf.php
|
||||||
|
...
|
||||||
|
$cfg['mtn_path'] = 'mtn';
|
||||||
|
$cfg['mtn_opts'] = array('--no-workspace', '--no-standard-rcfiles');
|
||||||
|
$cfg['mtn_repositories'] = '/home/monotone/%s.mtn';
|
||||||
|
$cfg['mtn_remote_url'] = 'ssh://monotone@my.server.com:~%s.mtn';
|
||||||
|
$cfg['mtn_db_access'] = 'local';
|
||||||
|
...
|
||||||
|
|
||||||
|
The same pro's and con's apply. Additionally you have to be careful about
|
||||||
|
not giving people physical read/write access of another project's database.
|
||||||
|
|
||||||
|
Furthermore, if you do not want to use `ssh`, but `netsync` transport,
|
||||||
|
each project's database must be served over a separate port.
|
||||||
|
|
||||||
|
3. One database for every project, all managed with usher. This is the
|
||||||
|
recommended setup for a mid-size forge setup. The remaining part of this
|
||||||
|
document will describe the process to set this up in detail.
|
||||||
|
|
||||||
|
Pro:
|
||||||
|
* access rights can be granted per project and are automatically
|
||||||
|
managed by indefero, just like the user's public monotone keys
|
||||||
|
* no database locking issues
|
||||||
|
* one public server running on the one well-known port
|
||||||
|
|
||||||
|
Con:
|
||||||
|
* harder to setup
|
||||||
|
|
||||||
|
## Installation and configuration of usher
|
||||||
|
|
||||||
|
1. Clone usher's monotone repository:
|
||||||
|
|
||||||
|
$ mtn clone "mtn://monotone.ca?net.venge.monotone.contrib.usher"
|
||||||
|
|
||||||
|
2. Compile usher:
|
||||||
|
|
||||||
|
$ autoreconf -i
|
||||||
|
$ ./configure && make
|
||||||
|
$ sudo make install
|
||||||
|
|
||||||
|
This installs the usher binary in $prefix/bin.
|
||||||
|
|
||||||
|
3. Create a new usher user:
|
||||||
|
|
||||||
|
$ adduser --system --disabled-login --home /var/lib/usher usher
|
||||||
|
|
||||||
|
4. Create the basic usher setup:
|
||||||
|
|
||||||
|
$ cd /var/lib/usher
|
||||||
|
$ mkdir projects logs
|
||||||
|
$ cat > usher.conf
|
||||||
|
userpass "admin" "<secret-password>"
|
||||||
|
adminaddr "127.0.0.1:12345"
|
||||||
|
logdir "log"
|
||||||
|
^D
|
||||||
|
$ chmod 600 usher.conf
|
||||||
|
|
||||||
|
Your indefero www user needs later write access to `usher.conf` and
|
||||||
|
`projects/`. There are two ways of setting this up:
|
||||||
|
|
||||||
|
* Make the usher user the web user, for example via Apache's `suexec`
|
||||||
|
* Use acls, like this:
|
||||||
|
|
||||||
|
$ setfacl -m u:www:rw usher.conf
|
||||||
|
$ setfacl -m d:u:www:rwx projects/
|
||||||
|
|
||||||
|
5. Wrap a daemonizer around usher, for example supervise from daemontools
|
||||||
|
(<http://cr.yp.to/damontools.html>):
|
||||||
|
|
||||||
|
$ cat > run
|
||||||
|
#!/bin/sh
|
||||||
|
cd /var/lib/usher
|
||||||
|
exec 2>&1
|
||||||
|
exec \
|
||||||
|
setuidgid usher \
|
||||||
|
usher usher.conf
|
||||||
|
^D
|
||||||
|
|
||||||
|
The service can now be started through supervise:
|
||||||
|
|
||||||
|
$ supervise /var/lib/usher
|
||||||
|
|
||||||
|
## Configuration of indefero
|
||||||
|
|
||||||
|
Based on the above setup, the configuration in `src/IDF/conf/idf.php` should
|
||||||
|
look like this:
|
||||||
|
|
||||||
|
$ cat idf.php
|
||||||
|
...
|
||||||
|
$cfg['mtn_path'] = 'mtn';
|
||||||
|
$cfg['mtn_opts'] = array('--no-workspace', '--no-standard-rcfiles');
|
||||||
|
$cfg['mtn_repositories'] = '/var/lib/usher/projects/%s/';
|
||||||
|
$cfg['mtn_remote_url'] = 'mtn://my.server.com/%s';
|
||||||
|
$cfg['mtn_db_access'] = 'remote';
|
||||||
|
$cfg['mtn_remote_auth'] = true;
|
||||||
|
$cfg['mtn_usher_conf'] = '/var/lib/usher/usher.conf';
|
||||||
|
...
|
||||||
|
|
||||||
|
The `%s` placeholders are automatically replaced by the name of the
|
||||||
|
indefero project. The plugin assumes that every project is separated
|
||||||
|
by a distinct server name in the monotone URL (hence the use of `/%s`),
|
||||||
|
so if a user calls
|
||||||
|
|
||||||
|
$ mtn sync mtn://my.server.com/project1
|
||||||
|
|
||||||
|
then the database / repository of the indefero `project1` is used.
|
||||||
|
Note that 'mtn_remote_url' is also used as internal URI to query the data
|
||||||
|
for indefero's source view, so it *must* be a valid host!
|
||||||
|
|
||||||
|
Usher also allows the identification of a project repository by hostname,
|
||||||
|
which would allow an URL template like `mtn://%s.my.server.com`, however
|
||||||
|
the plugin does not write out the configuration which is needed for this
|
||||||
|
yet.
|
||||||
|
|
||||||
|
For even more advanced setups, usher can also be used to forward sync
|
||||||
|
requests to other remote servers for load balancing, please consult the
|
||||||
|
README file for more information.
|
||||||
|
|
@ -15,8 +15,7 @@ res=$(cd "$dir" && /bin/pwd || "$dir")
|
|||||||
SCRIPTDIR="$res/$(readlink $0)"
|
SCRIPTDIR="$res/$(readlink $0)"
|
||||||
PHP_POST_PUSH=$SCRIPTDIR/mtnpostpush.php
|
PHP_POST_PUSH=$SCRIPTDIR/mtnpostpush.php
|
||||||
|
|
||||||
base=$(basename "$0")
|
TMPFILE=$(mktemp /tmp/mtn-post-push.XXXXXX) || exit 1
|
||||||
TMPFILE=$(mktemp /tmp/${tempfoo}.XXXXXX) || exit 1
|
|
||||||
while read rev; do echo $rev >> $TMPFILE; done
|
while read rev; do echo $rev >> $TMPFILE; done
|
||||||
|
|
||||||
echo php $PHP_POST_PUSH "$1" \< $TMPFILE \&\& rm -f $TMPFILE |\
|
echo php $PHP_POST_PUSH "$1" \< $TMPFILE \&\& rm -f $TMPFILE |\
|
||||||
|
@ -72,6 +72,9 @@ class IDF_Diff
|
|||||||
$indiff = true;
|
$indiff = true;
|
||||||
continue;
|
continue;
|
||||||
} else if (0 === strpos($line, '=========')) {
|
} else if (0 === strpos($line, '=========')) {
|
||||||
|
// ignore pseudo stanzas with a hint of a binary file
|
||||||
|
if (preg_match("/^# (.+) is binary/", $this->lines[$i]))
|
||||||
|
continue;
|
||||||
// by default always use the new name of a possibly renamed file
|
// by default always use the new name of a possibly renamed file
|
||||||
$current_file = self::getMtnFile($this->lines[$i+1]);
|
$current_file = self::getMtnFile($this->lines[$i+1]);
|
||||||
// mtn 0.48 and newer set /dev/null as file path for dropped files
|
// mtn 0.48 and newer set /dev/null as file path for dropped files
|
||||||
|
@ -313,6 +313,7 @@ class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
|||||||
'labels_download_one_max' => IDF_Form_UploadConf::init_one_max,
|
'labels_download_one_max' => IDF_Form_UploadConf::init_one_max,
|
||||||
'labels_wiki_predefined' => IDF_Form_WikiConf::init_predefined,
|
'labels_wiki_predefined' => IDF_Form_WikiConf::init_predefined,
|
||||||
'labels_wiki_one_max' => IDF_Form_WikiConf::init_one_max,
|
'labels_wiki_one_max' => IDF_Form_WikiConf::init_one_max,
|
||||||
|
'labels_issue_template' => IDF_Form_IssueTrackingConf::init_template,
|
||||||
'labels_issue_open' => IDF_Form_IssueTrackingConf::init_open,
|
'labels_issue_open' => IDF_Form_IssueTrackingConf::init_open,
|
||||||
'labels_issue_closed' => IDF_Form_IssueTrackingConf::init_closed,
|
'labels_issue_closed' => IDF_Form_IssueTrackingConf::init_closed,
|
||||||
'labels_issue_predefined' => IDF_Form_IssueTrackingConf::init_predefined,
|
'labels_issue_predefined' => IDF_Form_IssueTrackingConf::init_predefined,
|
||||||
|
@ -45,6 +45,9 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||||
$this->show_full = true;
|
$this->show_full = true;
|
||||||
}
|
}
|
||||||
|
$contentTemplate = $this->project->getConf()->getVal(
|
||||||
|
'labels_issue_template', IDF_Form_IssueTrackingConf::init_template
|
||||||
|
);
|
||||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => true,
|
array('required' => true,
|
||||||
'label' => __('Summary'),
|
'label' => __('Summary'),
|
||||||
@ -57,7 +60,7 @@ class IDF_Form_IssueCreate extends Pluf_Form
|
|||||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => true,
|
array('required' => true,
|
||||||
'label' => __('Description'),
|
'label' => __('Description'),
|
||||||
'initial' => '',
|
'initial' => $contentTemplate,
|
||||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||||
'widget_attrs' => array(
|
'widget_attrs' => array(
|
||||||
'cols' => 58,
|
'cols' => 58,
|
||||||
|
@ -31,6 +31,15 @@ class IDF_Form_IssueTrackingConf extends Pluf_Form
|
|||||||
* Defined as constants to easily access the value in the
|
* Defined as constants to easily access the value in the
|
||||||
* IssueUpdate/Create form in the case nothing is in the db yet.
|
* IssueUpdate/Create form in the case nothing is in the db yet.
|
||||||
*/
|
*/
|
||||||
|
const init_template = 'Steps to reproduce the problem:
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
Expected result:
|
||||||
|
|
||||||
|
Actual result:
|
||||||
|
';
|
||||||
const init_open = 'New = Issue has not had initial review yet
|
const init_open = 'New = Issue has not had initial review yet
|
||||||
Accepted = Problem reproduced / Need acknowledged
|
Accepted = Problem reproduced / Need acknowledged
|
||||||
Started = Work on this issue has begun';
|
Started = Work on this issue has begun';
|
||||||
@ -66,6 +75,15 @@ Maintainability = Hinders future changes';
|
|||||||
|
|
||||||
public function initFields($extra=array())
|
public function initFields($extra=array())
|
||||||
{
|
{
|
||||||
|
$this->fields['labels_issue_template'] = new Pluf_Form_Field_Varchar(
|
||||||
|
array('required' => false,
|
||||||
|
'label' => __('Define an issue template to hint the reporter to provide certain information'),
|
||||||
|
'initial' => self::init_template,
|
||||||
|
'widget_attrs' => array('rows' => 7,
|
||||||
|
'cols' => 75),
|
||||||
|
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||||
|
));
|
||||||
|
|
||||||
$this->fields['labels_issue_open'] = new Pluf_Form_Field_Varchar(
|
$this->fields['labels_issue_open'] = new Pluf_Form_Field_Varchar(
|
||||||
array('required' => true,
|
array('required' => true,
|
||||||
'label' => __('Open issue status values'),
|
'label' => __('Open issue status values'),
|
||||||
@ -99,8 +117,6 @@ Maintainability = Hinders future changes';
|
|||||||
'widget_attrs' => array('size' => 60),
|
'widget_attrs' => array('size' => 60),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class IDF_Key extends Pluf_Model
|
|||||||
if (preg_match('#^\[pubkey ([^\]]+)\]\s*(\S+)\s*\[end\]$#', $this->content, $m)) {
|
if (preg_match('#^\[pubkey ([^\]]+)\]\s*(\S+)\s*\[end\]$#', $this->content, $m)) {
|
||||||
return array('mtn', $m[1], $m[2]);
|
return array('mtn', $m[1], $m[2]);
|
||||||
}
|
}
|
||||||
else if (preg_match('#^ssh\-[a-z]{3}\s(\S+)\s(\S+)$#', $this->content, $m)) {
|
else if (preg_match('#^ssh\-[a-z]{3}\s(\S+)(?:\s(\S+))?$#', $this->content, $m)) {
|
||||||
return array('ssh', $m[2], $m[1]);
|
return array('ssh', $m[2], $m[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +112,7 @@ function IDF_Middleware_ContextPreProcessor($request)
|
|||||||
$c = array_merge($c, $request->rights);
|
$c = array_merge($c, $request->rights);
|
||||||
}
|
}
|
||||||
$c['usherConfigured'] = Pluf::f("mtn_usher_conf", null) !== null;
|
$c['usherConfigured'] = Pluf::f("mtn_usher_conf", null) !== null;
|
||||||
|
$c['allProjects'] = IDF_Views::getProjects($request->user);
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Pluf::f('mtn_db_access', 'local') == 'local') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$projecttempl = Pluf::f('mtn_repositories', false);
|
$projecttempl = Pluf::f('mtn_repositories', false);
|
||||||
if ($projecttempl === false) {
|
if ($projecttempl === false) {
|
||||||
throw new IDF_Scm_Exception(
|
throw new IDF_Scm_Exception(
|
||||||
@ -246,7 +250,9 @@ class IDF_Plugin_SyncMonotone
|
|||||||
array('key' => 'server', 'values' => array($shortname)),
|
array('key' => 'server', 'values' => array($shortname)),
|
||||||
array('key' => 'local', 'values' => array(
|
array('key' => 'local', 'values' => array(
|
||||||
'--confdir', $projectpath,
|
'--confdir', $projectpath,
|
||||||
'-d', $dbfile
|
'-d', $dbfile,
|
||||||
|
'--timestamps',
|
||||||
|
'--ticker=dot'
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -278,6 +284,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Pluf::f('mtn_db_access', 'local') == 'local') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$mtn = IDF_Scm_Monotone::factory($project);
|
$mtn = IDF_Scm_Monotone::factory($project);
|
||||||
$stdio = $mtn->getStdio();
|
$stdio = $mtn->getStdio();
|
||||||
|
|
||||||
@ -338,6 +348,10 @@ class IDF_Plugin_SyncMonotone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Pluf::f('mtn_db_access', 'local') == 'local') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$usher_config = Pluf::f('mtn_usher_conf', false);
|
$usher_config = Pluf::f('mtn_usher_conf', false);
|
||||||
if (!$usher_config || !is_writable($usher_config)) {
|
if (!$usher_config || !is_writable($usher_config)) {
|
||||||
throw new IDF_Scm_Exception(
|
throw new IDF_Scm_Exception(
|
||||||
@ -419,8 +433,13 @@ class IDF_Plugin_SyncMonotone
|
|||||||
*/
|
*/
|
||||||
public function processKeyCreate($key)
|
public function processKeyCreate($key)
|
||||||
{
|
{
|
||||||
if ($key->getType() != 'mtn')
|
if ($key->getType() != 'mtn') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pluf::f('mtn_db_access', 'local') == 'local') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
||||||
$conf = new IDF_Conf();
|
$conf = new IDF_Conf();
|
||||||
@ -525,8 +544,13 @@ class IDF_Plugin_SyncMonotone
|
|||||||
*/
|
*/
|
||||||
public function processKeyDelete($key)
|
public function processKeyDelete($key)
|
||||||
{
|
{
|
||||||
if ($key->getType() != 'mtn')
|
if ($key->getType() != 'mtn') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pluf::f('mtn_db_access', 'local') == 'local') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
||||||
$conf = new IDF_Conf();
|
$conf = new IDF_Conf();
|
||||||
|
@ -157,9 +157,11 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
*/
|
*/
|
||||||
private function _getCerts($rev)
|
private function _getCerts($rev)
|
||||||
{
|
{
|
||||||
static $certCache = array();
|
$cache = Pluf_Cache::factory();
|
||||||
|
$cachekey = 'mtn-plugin-certs-for-rev-' . $rev;
|
||||||
if (!array_key_exists($rev, $certCache)) {
|
$certs = $cache->get($cachekey);
|
||||||
|
|
||||||
|
if ($certs === null) {
|
||||||
$out = $this->stdio->exec(array('certs', $rev));
|
$out = $this->stdio->exec(array('certs', $rev));
|
||||||
|
|
||||||
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
||||||
@ -183,10 +185,10 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$certCache[$rev] = $certs;
|
$cache->set($cachekey, $certs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $certCache[$rev];
|
return $certs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,34 +214,6 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
return array_unique($certValues);
|
return array_unique($certValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the revision in which the file has been last changed,
|
|
||||||
* starting from the start rev
|
|
||||||
*
|
|
||||||
* @param string
|
|
||||||
* @param string
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function _getLastChangeFor($file, $startrev)
|
|
||||||
{
|
|
||||||
$out = $this->stdio->exec(array(
|
|
||||||
'get_content_changed', $startrev, $file
|
|
||||||
));
|
|
||||||
|
|
||||||
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
|
||||||
|
|
||||||
// FIXME: we only care about the first returned content mark
|
|
||||||
// everything else seem to be very, very rare cases
|
|
||||||
foreach ($stanzas as $stanza) {
|
|
||||||
foreach ($stanza as $stanzaline) {
|
|
||||||
if ($stanzaline['key'] == 'content_mark') {
|
|
||||||
return $stanzaline['hash'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IDF_Scm::inBranches()
|
* @see IDF_Scm::inBranches()
|
||||||
*/
|
*/
|
||||||
@ -296,6 +270,84 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
return $this->_getUniqueCertValuesFor($revs, 'tag', 't:');
|
return $this->_getUniqueCertValuesFor($revs, 'tag', 't:');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a single stanza coming from an extended manifest output
|
||||||
|
* and converts it into a file structure used by IDF
|
||||||
|
*
|
||||||
|
* @param string $forceBasedir If given then the element's path is checked
|
||||||
|
* to be directly beneath the given directory.
|
||||||
|
* If not, null is returned and the parsing is
|
||||||
|
* aborted.
|
||||||
|
* @return array | null
|
||||||
|
*/
|
||||||
|
private function _fillFileEntry(array $manifestEntry, $forceBasedir = null)
|
||||||
|
{
|
||||||
|
$fullpath = $manifestEntry[0]['values'][0];
|
||||||
|
$filename = basename($fullpath);
|
||||||
|
$dirname = dirname($fullpath);
|
||||||
|
$dirname = $dirname == '.' ? '' : $dirname;
|
||||||
|
|
||||||
|
if ($forceBasedir !== null && $forceBasedir != $dirname) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = array();
|
||||||
|
$file['file'] = $filename;
|
||||||
|
$file['fullpath'] = $fullpath;
|
||||||
|
$file['efullpath'] = self::smartEncode($fullpath);
|
||||||
|
|
||||||
|
$wanted_mark = '';
|
||||||
|
if ($manifestEntry[0]['key'] == 'dir') {
|
||||||
|
$file['type'] = 'tree';
|
||||||
|
$file['size'] = 0;
|
||||||
|
$wanted_mark = 'path_mark';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$file['type'] = 'blob';
|
||||||
|
$file['hash'] = $manifestEntry[1]['hash'];
|
||||||
|
$size = 0;
|
||||||
|
foreach ($manifestEntry as $line) {
|
||||||
|
if ($line['key'] == 'size') {
|
||||||
|
$size = $line['values'][0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$file['size'] = $size;
|
||||||
|
$wanted_mark = 'content_mark';
|
||||||
|
}
|
||||||
|
|
||||||
|
$rev_mark = null;
|
||||||
|
foreach ($manifestEntry as $line) {
|
||||||
|
if ($line['key'] == $wanted_mark) {
|
||||||
|
$rev_mark = $line['hash'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rev_mark !== null) {
|
||||||
|
$file['rev'] = $rev_mark;
|
||||||
|
$certs = $this->_getCerts($rev_mark);
|
||||||
|
|
||||||
|
// FIXME: this assumes that author, date and changelog are always given
|
||||||
|
$file['author'] = implode(", ", $certs['author']);
|
||||||
|
|
||||||
|
$dates = array();
|
||||||
|
foreach ($certs['date'] as $date)
|
||||||
|
$dates[] = date('Y-m-d H:i:s', strtotime($date));
|
||||||
|
$file['date'] = implode(', ', $dates);
|
||||||
|
$combinedChangelog = implode("\n---\n", $certs['changelog']);
|
||||||
|
$split = preg_split("/[\n\r]/", $combinedChangelog, 2);
|
||||||
|
// FIXME: the complete log message is currently not used in the
|
||||||
|
// tree view (the same is true for the other SCM implementations)
|
||||||
|
// but we _should_ really use or at least return that here
|
||||||
|
// in case we want to do fancy stuff like described in
|
||||||
|
// issue 492
|
||||||
|
$file['log'] = $split[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IDF_Scm::getTree()
|
* @see IDF_Scm::getTree()
|
||||||
*/
|
*/
|
||||||
@ -307,59 +359,21 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
}
|
}
|
||||||
|
|
||||||
$out = $this->stdio->exec(array(
|
$out = $this->stdio->exec(array(
|
||||||
'get_manifest_of', $revs[0]
|
'get_extended_manifest_of', $revs[0]
|
||||||
));
|
));
|
||||||
|
|
||||||
$files = array();
|
$files = array();
|
||||||
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
|
||||||
$folder = $folder == '/' || empty($folder) ? '' : $folder.'/';
|
$folder = $folder == '/' || empty($folder) ? '' : $folder;
|
||||||
|
|
||||||
foreach ($stanzas as $stanza) {
|
foreach ($stanzas as $stanza) {
|
||||||
if ($stanza[0]['key'] == 'format_version')
|
if ($stanza[0]['key'] == 'format_version')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$path = $stanza[0]['values'][0];
|
$file = $this->_fillFileEntry($stanza, $folder);
|
||||||
if (!preg_match('#^'.$folder.'([^/]+)$#', $path, $m))
|
if ($file === null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$file = array();
|
|
||||||
$file['file'] = $m[1];
|
|
||||||
$file['fullpath'] = $path;
|
|
||||||
$file['efullpath'] = self::smartEncode($path);
|
|
||||||
|
|
||||||
if ($stanza[0]['key'] == 'dir') {
|
|
||||||
$file['type'] = 'tree';
|
|
||||||
$file['size'] = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$file['type'] = 'blob';
|
|
||||||
$file['hash'] = $stanza[1]['hash'];
|
|
||||||
$file['size'] = strlen($this->getFile((object)$file));
|
|
||||||
}
|
|
||||||
|
|
||||||
$rev = $this->_getLastChangeFor($file['fullpath'], $revs[0]);
|
|
||||||
if ($rev !== null) {
|
|
||||||
$file['rev'] = $rev;
|
|
||||||
$certs = $this->_getCerts($rev);
|
|
||||||
|
|
||||||
// FIXME: this assumes that author, date and changelog are always given
|
|
||||||
$file['author'] = implode(", ", $certs['author']);
|
|
||||||
|
|
||||||
$dates = array();
|
|
||||||
foreach ($certs['date'] as $date)
|
|
||||||
$dates[] = date('Y-m-d H:i:s', strtotime($date));
|
|
||||||
$file['date'] = implode(', ', $dates);
|
|
||||||
$combinedChangelog = implode("\n---\n", $certs['changelog']);
|
|
||||||
$split = preg_split("/[\n\r]/", $combinedChangelog, 2);
|
|
||||||
// FIXME: the complete log message is currently not used in the
|
|
||||||
// tree view (the same is true for the other SCM implementations)
|
|
||||||
// but we _should_ really use or at least return that here
|
|
||||||
// in case we want to do fancy stuff like described in
|
|
||||||
// issue 492
|
|
||||||
$file['log'] = $split[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
$files[] = (object) $file;
|
$files[] = (object) $file;
|
||||||
}
|
}
|
||||||
return $files;
|
return $files;
|
||||||
@ -399,7 +413,7 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
$certs = $scm->_getCerts($revs[0]);
|
$certs = $scm->_getCerts($revs[0]);
|
||||||
// for the very seldom case that a revision
|
// for the very seldom case that a revision
|
||||||
// has no branch certificate
|
// has no branch certificate
|
||||||
if (count($certs['branch']) == 0) {
|
if (!array_key_exists('branch', $certs)) {
|
||||||
$branch = '*';
|
$branch = '*';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -505,7 +519,7 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
$out = $this->stdio->exec(array(
|
$out = $this->stdio->exec(array(
|
||||||
'get_manifest_of', $revs[0]
|
'get_extended_manifest_of', $revs[0]
|
||||||
));
|
));
|
||||||
|
|
||||||
$files = array();
|
$files = array();
|
||||||
@ -515,43 +529,10 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
if ($stanza[0]['key'] == 'format_version')
|
if ($stanza[0]['key'] == 'format_version')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$path = $stanza[0]['values'][0];
|
if ($stanza[0]['values'][0] != $file)
|
||||||
if (!preg_match('#^'.$file.'$#', $path, $m))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
$file = array();
|
$file = $this->_fillFileEntry($stanza);
|
||||||
$file['fullpath'] = $path;
|
|
||||||
|
|
||||||
if ($stanza[0]['key'] == "dir") {
|
|
||||||
$file['type'] = "tree";
|
|
||||||
$file['hash'] = null;
|
|
||||||
$file['size'] = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$file['type'] = 'blob';
|
|
||||||
$file['hash'] = $stanza[1]['hash'];
|
|
||||||
$file['size'] = strlen($this->getFile((object)$file));
|
|
||||||
}
|
|
||||||
|
|
||||||
$pathinfo = pathinfo($file['fullpath']);
|
|
||||||
$file['file'] = $pathinfo['basename'];
|
|
||||||
|
|
||||||
$rev = $this->_getLastChangeFor($file['fullpath'], $revs[0]);
|
|
||||||
if ($rev !== null) {
|
|
||||||
$file['rev'] = $rev;
|
|
||||||
$certs = $this->_getCerts($rev);
|
|
||||||
|
|
||||||
// FIXME: this assumes that author, date and changelog are always given
|
|
||||||
$file['author'] = implode(", ", $certs['author']);
|
|
||||||
|
|
||||||
$dates = array();
|
|
||||||
foreach ($certs['date'] as $date)
|
|
||||||
$dates[] = date('Y-m-d H:i:s', strtotime($date));
|
|
||||||
$file['date'] = implode(', ', $dates);
|
|
||||||
$file['log'] = implode("\n---\n", $certs['changelog']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (object) $file;
|
return (object) $file;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -623,10 +604,12 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
$dates[] = date('Y-m-d H:i:s', strtotime($date));
|
$dates[] = date('Y-m-d H:i:s', strtotime($date));
|
||||||
$res['date'] = implode(', ', $dates);
|
$res['date'] = implode(', ', $dates);
|
||||||
|
|
||||||
$res['title'] = implode("\n---\n", $certs['changelog']);
|
$combinedChangelog = implode("\n---\n", $certs['changelog']);
|
||||||
|
$split = preg_split("/[\n\r]/", $combinedChangelog, 2);
|
||||||
|
$res['title'] = $split[0];
|
||||||
|
$res['full_message'] = (isset($split[1])) ? trim($split[1]) : '';
|
||||||
|
|
||||||
$res['commit'] = $revs[0];
|
$res['commit'] = $revs[0];
|
||||||
|
|
||||||
$res['changes'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
|
$res['changes'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
|
||||||
|
|
||||||
return (object) $res;
|
return (object) $res;
|
||||||
@ -680,11 +663,18 @@ class IDF_Scm_Monotone extends IDF_Scm
|
|||||||
|
|
||||||
// read in the initial branches we should follow
|
// read in the initial branches we should follow
|
||||||
if (count($initialBranches) == 0) {
|
if (count($initialBranches) == 0) {
|
||||||
|
if (!isset($certs['branch'])) {
|
||||||
|
throw new IDF_Scm_Exception(sprintf(
|
||||||
|
__("revision %s has no branch cert - cannot start ".
|
||||||
|
"logging from this revision"), $rev
|
||||||
|
));
|
||||||
|
}
|
||||||
$initialBranches = $certs['branch'];
|
$initialBranches = $certs['branch'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// only add it to our log if it is on one of the initial branches
|
// only add it to our log if it is on one of the initial branches
|
||||||
if (count(array_intersect($initialBranches, $certs['branch'])) > 0) {
|
// ignore revisions without any branch certificate
|
||||||
|
if (count(array_intersect($initialBranches, (array)@$certs['branch'])) > 0) {
|
||||||
--$n;
|
--$n;
|
||||||
|
|
||||||
$log = array();
|
$log = array();
|
||||||
|
@ -38,14 +38,15 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
{
|
{
|
||||||
$pos = 0;
|
$pos = 0;
|
||||||
$stanzas = array();
|
$stanzas = array();
|
||||||
|
$length = strlen($in);
|
||||||
|
|
||||||
while ($pos < strlen($in)) {
|
while ($pos < $length) {
|
||||||
$stanza = array();
|
$stanza = array();
|
||||||
while ($pos < strlen($in)) {
|
while ($pos < $length) {
|
||||||
if ($in[$pos] == "\n") break;
|
if ($in[$pos] == "\n") break;
|
||||||
|
|
||||||
$stanzaLine = array('key' => '', 'values' => array(), 'hash' => null);
|
$stanzaLine = array('key' => '', 'values' => array(), 'hash' => null);
|
||||||
while ($pos < strlen($in)) {
|
while ($pos < $length) {
|
||||||
$ch = $in[$pos];
|
$ch = $in[$pos];
|
||||||
if ($ch == '"' || $ch == '[') break;
|
if ($ch == '"' || $ch == '[') break;
|
||||||
++$pos;
|
++$pos;
|
||||||
@ -53,6 +54,9 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
$stanzaLine['key'] .= $ch;
|
$stanzaLine['key'] .= $ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// symbol w/o a value list
|
||||||
|
if ($pos >= $length || $in[$pos] == "\n") break;
|
||||||
|
|
||||||
if ($in[$pos] == '[') {
|
if ($in[$pos] == '[') {
|
||||||
unset($stanzaLine['values']);
|
unset($stanzaLine['values']);
|
||||||
++$pos; // opening square bracket
|
++$pos; // opening square bracket
|
||||||
@ -64,18 +68,31 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
{
|
{
|
||||||
unset($stanzaLine['hash']);
|
unset($stanzaLine['hash']);
|
||||||
$valCount = 0;
|
$valCount = 0;
|
||||||
while ($in[$pos] == '"') {
|
// if hashs and plain values are encountered in the same
|
||||||
++$pos; // opening quote
|
// value list, we add the hash values as simple values as well
|
||||||
|
while ($in[$pos] == '"' || $in[$pos] == '[') {
|
||||||
|
$isHashValue = $in[$pos] == '[';
|
||||||
|
++$pos; // opening quote / bracket
|
||||||
$stanzaLine['values'][$valCount] = '';
|
$stanzaLine['values'][$valCount] = '';
|
||||||
while ($pos < strlen($in)) {
|
while ($pos < $length) {
|
||||||
$ch = $in[$pos]; $pr = $in[$pos-1];
|
$ch = $in[$pos]; $pr = $in[$pos-1];
|
||||||
if ($ch == '"' && $pr != '\\') break;
|
if (($isHashValue && $ch == ']')
|
||||||
|
||(!$isHashValue && $ch == '"' && $pr != '\\'))
|
||||||
|
break;
|
||||||
++$pos;
|
++$pos;
|
||||||
$stanzaLine['values'][$valCount] .= $ch;
|
$stanzaLine['values'][$valCount] .= $ch;
|
||||||
}
|
}
|
||||||
++$pos; // closing quote
|
++$pos; // closing quote
|
||||||
|
|
||||||
if ($pos >= strlen($in))
|
if (!$isHashValue) {
|
||||||
|
$stanzaLine['values'][$valCount] = str_replace(
|
||||||
|
array("\\\\", "\\\""),
|
||||||
|
array("\\", "\""),
|
||||||
|
$stanzaLine['values'][$valCount]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pos >= $length)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ($in[$pos] == ' ') {
|
if ($in[$pos] == ' ') {
|
||||||
@ -83,14 +100,6 @@ class IDF_Scm_Monotone_BasicIO
|
|||||||
++$valCount;
|
++$valCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 0; $i <= $valCount; $i++) {
|
|
||||||
$stanzaLine['values'][$i] = str_replace(
|
|
||||||
array("\\\\", "\\\""),
|
|
||||||
array("\\", "\""),
|
|
||||||
$stanzaLine['values'][$i]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stanza[] = $stanzaLine;
|
$stanza[] = $stanzaLine;
|
||||||
|
@ -76,7 +76,7 @@ class IDF_Scm_Monotone_Usher
|
|||||||
$single_conns = preg_split('/[ ]/', $conn);
|
$single_conns = preg_split('/[ ]/', $conn);
|
||||||
$ret = array();
|
$ret = array();
|
||||||
foreach ($single_conns as $conn) {
|
foreach ($single_conns as $conn) {
|
||||||
preg_match('/\(\w+\)([^:]):(\d+)/', $conn, $matches);
|
preg_match('/\((\w+)\)([^:]+):(\d+)/', $conn, $matches);
|
||||||
$ret[$matches[1]][] = (object)array(
|
$ret[$matches[1]][] = (object)array(
|
||||||
'server' => $matches[1],
|
'server' => $matches[1],
|
||||||
'address' => $matches[2],
|
'address' => $matches[2],
|
||||||
@ -84,6 +84,12 @@ class IDF_Scm_Monotone_Usher
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($server !== null) {
|
||||||
|
if (array_key_exists($server, $ret))
|
||||||
|
return $ret[$server];
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,66 @@ class IDF_Views_Project
|
|||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an associative array with available model filters
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function getAvailableModelFilters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'all' => __('All Updates'),
|
||||||
|
'commits' => __('Commits'),
|
||||||
|
'issues' => __('Issues and Comments'),
|
||||||
|
'downloads' => __('Downloads'),
|
||||||
|
'documents' => __('Documents'),
|
||||||
|
'reviews' => __('Reviews and Patches'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of model classes for which the current user
|
||||||
|
* has rights and which should be used according to his filter
|
||||||
|
*
|
||||||
|
* @param object $request
|
||||||
|
* @param string $model_filter
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function determineModelClasses($request, $model_filter = 'all')
|
||||||
|
{
|
||||||
|
$classes = array();
|
||||||
|
if (true === IDF_Precondition::accessSource($request) &&
|
||||||
|
($model_filter == 'all' || $model_filter == 'commits')) {
|
||||||
|
$classes[] = '\'IDF_Commit\'';
|
||||||
|
// FIXME: this looks like a hack...
|
||||||
|
IDF_Scm::syncTimeline($request->project);
|
||||||
|
}
|
||||||
|
if (true === IDF_Precondition::accessIssues($request) &&
|
||||||
|
($model_filter == 'all' || $model_filter == 'issues')) {
|
||||||
|
$classes[] = '\'IDF_Issue\'';
|
||||||
|
$classes[] = '\'IDF_IssueComment\'';
|
||||||
|
}
|
||||||
|
if (true === IDF_Precondition::accessDownloads($request) &&
|
||||||
|
($model_filter == 'all' || $model_filter == 'downloads')) {
|
||||||
|
$classes[] = '\'IDF_Upload\'';
|
||||||
|
}
|
||||||
|
if (true === IDF_Precondition::accessWiki($request) &&
|
||||||
|
($model_filter == 'all' || $model_filter == 'documents')) {
|
||||||
|
$classes[] = '\'IDF_WikiPage\'';
|
||||||
|
$classes[] = '\'IDF_WikiRevision\'';
|
||||||
|
}
|
||||||
|
if (true === IDF_Precondition::accessReview($request) &&
|
||||||
|
($model_filter == 'all' || $model_filter == 'reviews')) {
|
||||||
|
$classes[] = '\'IDF_Review_Comment\'';
|
||||||
|
$classes[] = '\'IDF_Review_Patch\'';
|
||||||
|
}
|
||||||
|
if (count($classes) == 0) {
|
||||||
|
$classes[] = '\'IDF_Dummy\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeline of the project.
|
* Timeline of the project.
|
||||||
*/
|
*/
|
||||||
@ -68,38 +128,21 @@ class IDF_Views_Project
|
|||||||
public function timeline($request, $match)
|
public function timeline($request, $match)
|
||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$title = sprintf(__('%s Updates'), (string) $prj);
|
|
||||||
$team = $prj->getMembershipData();
|
$model_filter = @$match[2];
|
||||||
|
$all_model_filters = self::getAvailableModelFilters();
|
||||||
|
if (!array_key_exists($model_filter, $all_model_filters)) {
|
||||||
|
$model_filter = 'all';
|
||||||
|
}
|
||||||
|
$title = (string)$prj . ' ' . $all_model_filters[$model_filter];
|
||||||
|
|
||||||
$pag = new IDF_Timeline_Paginator(new IDF_Timeline());
|
$pag = new IDF_Timeline_Paginator(new IDF_Timeline());
|
||||||
$pag->class = 'recent-issues';
|
$pag->class = 'recent-issues';
|
||||||
$pag->item_extra_props = array('request' => $request);
|
$pag->item_extra_props = array('request' => $request);
|
||||||
$pag->summary = __('This table shows the project updates.');
|
$pag->summary = __('This table shows the project updates.');
|
||||||
// Need to check the rights
|
|
||||||
$rights = array();
|
$classes = self::determineModelClasses($request, $model_filter);
|
||||||
if (true === IDF_Precondition::accessSource($request)) {
|
$sql = sprintf('model_class IN (%s)', implode(', ', $classes));
|
||||||
$rights[] = '\'IDF_Commit\'';
|
|
||||||
IDF_Scm::syncTimeline($request->project);
|
|
||||||
}
|
|
||||||
if (true === IDF_Precondition::accessIssues($request)) {
|
|
||||||
$rights[] = '\'IDF_Issue\'';
|
|
||||||
$rights[] = '\'IDF_IssueComment\'';
|
|
||||||
}
|
|
||||||
if (true === IDF_Precondition::accessDownloads($request)) {
|
|
||||||
$rights[] = '\'IDF_Upload\'';
|
|
||||||
}
|
|
||||||
if (true === IDF_Precondition::accessWiki($request)) {
|
|
||||||
$rights[] = '\'IDF_WikiPage\'';
|
|
||||||
$rights[] = '\'IDF_WikiRevision\'';
|
|
||||||
}
|
|
||||||
if (true === IDF_Precondition::accessReview($request)) {
|
|
||||||
$rights[] = '\'IDF_Review_Comment\'';
|
|
||||||
$rights[] = '\'IDF_Review_Patch\'';
|
|
||||||
}
|
|
||||||
if (count($rights) == 0) {
|
|
||||||
$rights[] = '\'IDF_Dummy\'';
|
|
||||||
}
|
|
||||||
$sql = sprintf('model_class IN (%s)', implode(', ', $rights));
|
|
||||||
$pag->forced_where = new Pluf_SQL('project=%s AND '.$sql,
|
$pag->forced_where = new Pluf_SQL('project=%s AND '.$sql,
|
||||||
array($prj->id));
|
array($prj->id));
|
||||||
$pag->sort_order = array('creation_dtime', 'ASC');
|
$pag->sort_order = array('creation_dtime', 'ASC');
|
||||||
@ -113,32 +156,23 @@ class IDF_Views_Project
|
|||||||
$pag->items_per_page = 20;
|
$pag->items_per_page = 20;
|
||||||
$pag->no_results_text = __('No changes were found.');
|
$pag->no_results_text = __('No changes were found.');
|
||||||
$pag->setFromRequest($request);
|
$pag->setFromRequest($request);
|
||||||
$downloads = array();
|
|
||||||
if ($request->rights['hasDownloadsAccess']) {
|
|
||||||
$tags = IDF_Views_Download::getDownloadTags($prj);
|
|
||||||
// the first tag is the featured, the last is the deprecated.
|
|
||||||
$downloads = $tags[0]->get_idf_upload_list();
|
|
||||||
}
|
|
||||||
$pages = array();
|
|
||||||
if ($request->rights['hasWikiAccess']) {
|
|
||||||
$tags = IDF_Views_Wiki::getWikiTags($prj);
|
|
||||||
$pages = $tags[0]->get_idf_wikipage_list();
|
|
||||||
}
|
|
||||||
if (!$request->user->isAnonymous() and $prj->isRestricted()) {
|
if (!$request->user->isAnonymous() and $prj->isRestricted()) {
|
||||||
$feedurl = Pluf_HTTP_URL_urlForView('idf_project_timeline_feed_auth',
|
$feedurl = Pluf_HTTP_URL_urlForView('idf_project_timeline_feed_auth',
|
||||||
array($prj->shortname,
|
array($prj->shortname,
|
||||||
|
$model_filter,
|
||||||
IDF_Precondition::genFeedToken($prj, $request->user)));
|
IDF_Precondition::genFeedToken($prj, $request->user)));
|
||||||
} else {
|
} else {
|
||||||
$feedurl = Pluf_HTTP_URL_urlForView('idf_project_timeline_feed',
|
$feedurl = Pluf_HTTP_URL_urlForView('idf_project_timeline_feed',
|
||||||
array($prj->shortname));
|
array($prj->shortname, $model_filter));
|
||||||
}
|
}
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/project/timeline.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/project/timeline.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $title,
|
'page_title' => $title,
|
||||||
'feedurl' => $feedurl,
|
'feedurl' => $feedurl,
|
||||||
'timeline' => $pag,
|
'timeline' => $pag,
|
||||||
'team' => $team,
|
'model_filter' => $model_filter,
|
||||||
'downloads' => $downloads,
|
'all_model_filters' => $all_model_filters,
|
||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
|
|
||||||
@ -156,31 +190,17 @@ class IDF_Views_Project
|
|||||||
public function timelineFeed($request, $match)
|
public function timelineFeed($request, $match)
|
||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
// Need to check the rights
|
$model_filter = @$match[2];
|
||||||
$rights = array();
|
|
||||||
if (true === IDF_Precondition::accessSource($request)) {
|
$model_filter = @$match[2];
|
||||||
$rights[] = '\'IDF_Commit\'';
|
$all_model_filters = self::getAvailableModelFilters();
|
||||||
IDF_Scm::syncTimeline($request->project);
|
if (!array_key_exists($model_filter, $all_model_filters)) {
|
||||||
|
$model_filter = 'all';
|
||||||
}
|
}
|
||||||
if (true === IDF_Precondition::accessIssues($request)) {
|
$title = $all_model_filters[$model_filter];
|
||||||
$rights[] = '\'IDF_Issue\'';
|
|
||||||
$rights[] = '\'IDF_IssueComment\'';
|
$classes = self::determineModelClasses($request, $model_filter);
|
||||||
}
|
$sqls = sprintf('model_class IN (%s)', implode(', ', $classes));
|
||||||
if (true === IDF_Precondition::accessDownloads($request)) {
|
|
||||||
$rights[] = '\'IDF_Upload\'';
|
|
||||||
}
|
|
||||||
if (true === IDF_Precondition::accessWiki($request)) {
|
|
||||||
$rights[] = '\'IDF_WikiPage\'';
|
|
||||||
$rights[] = '\'IDF_WikiRevision\'';
|
|
||||||
}
|
|
||||||
if (true === IDF_Precondition::accessReview($request)) {
|
|
||||||
$rights[] = '\'IDF_Review_Comment\'';
|
|
||||||
$rights[] = '\'IDF_Review_Patch\'';
|
|
||||||
}
|
|
||||||
if (count($rights) == 0) {
|
|
||||||
$rights[] = '\'IDF_Dummy\'';
|
|
||||||
}
|
|
||||||
$sqls = sprintf('model_class IN (%s)', implode(', ', $rights));
|
|
||||||
$sql = new Pluf_SQL('project=%s AND '.$sqls, array($prj->id));
|
$sql = new Pluf_SQL('project=%s AND '.$sqls, array($prj->id));
|
||||||
$params = array(
|
$params = array(
|
||||||
'filter' => $sql->gen(),
|
'filter' => $sql->gen(),
|
||||||
@ -203,7 +223,6 @@ class IDF_Views_Project
|
|||||||
}
|
}
|
||||||
$out = Pluf_Template::markSafe(implode("\n", $out));
|
$out = Pluf_Template::markSafe(implode("\n", $out));
|
||||||
$tmpl = new Pluf_Template('idf/index.atom');
|
$tmpl = new Pluf_Template('idf/index.atom');
|
||||||
$title = __('Updates');
|
|
||||||
$feedurl = Pluf::f('url_base').Pluf::f('idf_base').$request->query;
|
$feedurl = Pluf::f('url_base').Pluf::f('idf_base').$request->query;
|
||||||
$viewurl = Pluf_HTTP_URL_urlForView('IDF_Views_Project::timeline',
|
$viewurl = Pluf_HTTP_URL_urlForView('IDF_Views_Project::timeline',
|
||||||
array($prj->shortname));
|
array($prj->shortname));
|
||||||
@ -277,7 +296,8 @@ class IDF_Views_Project
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$params = array();
|
$params = array();
|
||||||
$keys = array('labels_issue_open', 'labels_issue_closed',
|
$keys = array('labels_issue_template',
|
||||||
|
'labels_issue_open', 'labels_issue_closed',
|
||||||
'labels_issue_predefined', 'labels_issue_one_max');
|
'labels_issue_predefined', 'labels_issue_one_max');
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
$_val = $conf->getVal($key, false);
|
$_val = $conf->getVal($key, false);
|
||||||
@ -535,4 +555,4 @@ class IDF_Views_Project
|
|||||||
),
|
),
|
||||||
$request);
|
$request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -533,8 +533,10 @@ class IDF_Views_Source
|
|||||||
if (0 === strpos($fileinfo[0], 'text/')) {
|
if (0 === strpos($fileinfo[0], 'text/')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$ext = 'mdtext php-dist h gitignore diff patch'
|
$ext = 'mdtext php-dist h gitignore diff patch';
|
||||||
.Pluf::f('idf_extra_text_ext', '');
|
$extra_ext = trim(Pluf::f('idf_extra_text_ext', ''));
|
||||||
|
if (!empty($extra_ext))
|
||||||
|
$ext .= ' ' . $extra_ext;
|
||||||
$ext = array_merge(self::$supportedExtenstions, explode(' ' , $ext));
|
$ext = array_merge(self::$supportedExtenstions, explode(' ' , $ext));
|
||||||
return (in_array($fileinfo[2], $ext));
|
return (in_array($fileinfo[2], $ext));
|
||||||
}
|
}
|
||||||
|
@ -73,90 +73,31 @@ $cfg['git_write_remote_url'] = 'git@localhost:%s.git';
|
|||||||
$cfg['svn_repositories'] = 'file:///home/svn/repositories/%s';
|
$cfg['svn_repositories'] = 'file:///home/svn/repositories/%s';
|
||||||
$cfg['svn_remote_url'] = 'http://localhost/svn/%s';
|
$cfg['svn_remote_url'] = 'http://localhost/svn/%s';
|
||||||
|
|
||||||
# Path to the monotone binary (you need mtn 0.99 or newer)
|
#
|
||||||
|
# You can setup monotone for use with indefero in several ways.
|
||||||
|
# Please look into doc/syncmonotone.mdtext for more information.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Path to the monotone binary
|
||||||
$cfg['mtn_path'] = 'mtn';
|
$cfg['mtn_path'] = 'mtn';
|
||||||
|
|
||||||
# Additional options for the started monotone process
|
# Additional options for the started monotone process
|
||||||
$cfg['mtn_opts'] = array('--no-workspace', '--no-standard-rcfiles');
|
$cfg['mtn_opts'] = array('--no-workspace', '--no-standard-rcfiles');
|
||||||
#
|
|
||||||
# You can setup monotone for use with indefero in several ways. The
|
# The path to a specific database (local use) or a writable project
|
||||||
# two most-used should be:
|
# directory (remote / usher use). %s is replaced with the project name
|
||||||
#
|
|
||||||
# 1) One database for everything:
|
|
||||||
#
|
|
||||||
# Set 'mtn_repositories' below to a fixed database path, such as
|
|
||||||
# '/home/mtn/repositories/all_projects.mtn'
|
|
||||||
#
|
|
||||||
# Pro: - easy to setup and to manage
|
|
||||||
# Con: - while read access can be configured per-branch,
|
|
||||||
# granting write access rights to a user means that
|
|
||||||
# he can write anything in the global database
|
|
||||||
# - database lock problem: the database from which
|
|
||||||
# indefero reads its data cannot be used to serve the
|
|
||||||
# contents to the users, as the serve process locks
|
|
||||||
# the database
|
|
||||||
#
|
|
||||||
# 2) One database for every project with 'usher':
|
|
||||||
#
|
|
||||||
# Download and configure 'usher'
|
|
||||||
# (mtn clone mtn://monotone.ca?net.venge.monotone.contrib.usher)
|
|
||||||
# which acts as proxy in front of all single project databases.
|
|
||||||
# Create a basic configuration file for it and add a secret admin
|
|
||||||
# username and password. Finally, point the below variable
|
|
||||||
# 'mtn_usher_conf' to this configuration file.
|
|
||||||
#
|
|
||||||
# Then set 'mtn_remote_url' below to a string which matches your setup.
|
|
||||||
# Again, the '%s' placeholder will be expanded to the project's
|
|
||||||
# short name. Note that 'mtn_remote_url' is used as internal
|
|
||||||
# URI (to access the data for indefero) as well as external URI
|
|
||||||
# (for end users) at the same time. 'mtn_repositories' should then
|
|
||||||
# point to a directory where all project-related files (databases,
|
|
||||||
# keys, configurations) are kept, as these are automatically created
|
|
||||||
# on project creation by IDF.
|
|
||||||
#
|
|
||||||
# Example: 'mtn_repositories' is configured to be '/var/monotone/%s'
|
|
||||||
#
|
|
||||||
# - IDF tries to create /var/monotone/<projectname> as root directory
|
|
||||||
# - The database is placed in as /var/monotone/<projectname>/database.mtn
|
|
||||||
# - The server key is put into /var/monotone/<projectname>/keys and
|
|
||||||
# is named "<projectname>-server@<host>", where host is the host part
|
|
||||||
# of 'mtn_remote_url'
|
|
||||||
#
|
|
||||||
# therefor /var/monotone MUST be read/writable for the www user and all
|
|
||||||
# files which are created underknees MUST be read/writable by the user
|
|
||||||
# who is executing the usher instance! The best way to achieve this is with
|
|
||||||
# default (POSIX) ACLs on /var/monotone.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# You could also choose to setup usher by hand, i.e. with individual
|
|
||||||
# databases, in this case leave 'mtn_usher_conf' below commented out.
|
|
||||||
#
|
|
||||||
# Pro: - read and write access can be granted per project
|
|
||||||
# - no database locking issues
|
|
||||||
# - one public server running on the one well-known port
|
|
||||||
# Con: - harder to setup
|
|
||||||
#
|
|
||||||
# Usher can also be used to forward sync requests to remote servers,
|
|
||||||
# please consult its README file for more information.
|
|
||||||
#
|
|
||||||
# monotone also allows to use SSH as transport protocol, so if you do not plan
|
|
||||||
# to setup a netsync server as described above, then just enter a URI like
|
|
||||||
# 'ssh://my-host.biz/home/mtn/repositories/%s.mtn' in 'mtn_remote_url'.
|
|
||||||
#
|
|
||||||
$cfg['mtn_repositories'] = '/home/mtn/repositories/%s.mtn';
|
$cfg['mtn_repositories'] = '/home/mtn/repositories/%s.mtn';
|
||||||
|
|
||||||
|
# The URL which is displayed as sync URL to the user and which is also
|
||||||
|
# used to connect to a remote usher
|
||||||
$cfg['mtn_remote_url'] = 'mtn://my-host.biz/%s';
|
$cfg['mtn_remote_url'] = 'mtn://my-host.biz/%s';
|
||||||
#
|
|
||||||
# Whether the particular database(s) are accessed locally (via automate stdio)
|
# Whether the particular database(s) are accessed locally (via automate stdio)
|
||||||
# or remotely (via automate remote_stdio). 'remote' is the default for
|
# or remotely (via automate remote_stdio). 'remote' is the default for
|
||||||
# netsync setups, while 'local' access should be choosed for ssh access.
|
# use with usher and the SyncMonotone plugin, while 'local' access should be
|
||||||
#
|
# choosed for manual setups and / or ssh access.
|
||||||
# Note that you need to setup the hook 'get_remote_automate_permitted' for
|
$cfg['mtn_db_access'] = 'local';
|
||||||
# each remotely accessible database. A full HOWTO set this up is beyond this
|
|
||||||
# scope, please refer to the documentation of monotone and / or ask on the
|
|
||||||
# mailing list (monotone-users@nongnu.org) or IRC channel
|
|
||||||
# (irc.oftc.net/#monotone)
|
|
||||||
#
|
|
||||||
$cfg['mtn_db_access'] = 'remote';
|
|
||||||
#
|
|
||||||
# If true, each access to the database is authenticated with an auto-generated
|
# If true, each access to the database is authenticated with an auto-generated
|
||||||
# project key which is stored in the IDF project configuration
|
# project key which is stored in the IDF project configuration
|
||||||
# ('mtn_client_key_*') and written out to $cfg['tmp_folder']/mtn-client-keys
|
# ('mtn_client_key_*') and written out to $cfg['tmp_folder']/mtn-client-keys
|
||||||
@ -167,18 +108,17 @@ $cfg['mtn_db_access'] = 'remote';
|
|||||||
# the remote monotone server instance. In this case no project-specific
|
# the remote monotone server instance. In this case no project-specific
|
||||||
# keys are generated and the server must be configured to allow at least
|
# keys are generated and the server must be configured to allow at least
|
||||||
# anonymous read access to the main functions.
|
# anonymous read access to the main functions.
|
||||||
#
|
#$cfg['mtn_remote_auth'] = true;
|
||||||
$cfg['mtn_remote_auth'] = true;
|
|
||||||
#
|
# Needs to be configured for remote / usher usage.
|
||||||
# If configured, this allows basic control of a running usher process
|
# This allows basic control of a running usher process via the forge
|
||||||
# via the forge administration. The variable must point to the full (writable)
|
# administration. The variable must point to the full (writable)
|
||||||
# path of the usher configuration file which gets updated when new projects
|
# path of the usher configuration file which gets updated when new projects
|
||||||
# are added
|
# are added
|
||||||
#
|
|
||||||
#$cfg['mtn_usher_conf'] = '/path/to/usher.conf';
|
#$cfg['mtn_usher_conf'] = '/path/to/usher.conf';
|
||||||
|
|
||||||
# Mercurial repositories path
|
# Mercurial repositories path
|
||||||
#$cfg['mercurial_repositories'] = '/home/mercurial/repositories/%s';
|
$cfg['mercurial_repositories'] = '/home/mercurial/repositories/%s';
|
||||||
#$cfg['mercurial_remote_url'] = 'http://projects.ceondo.com/hg/%s';
|
#$cfg['mercurial_remote_url'] = 'http://projects.ceondo.com/hg/%s';
|
||||||
|
|
||||||
# admins will get an email in case of errors in the system in non
|
# admins will get an email in case of errors in the system in non
|
||||||
@ -265,8 +205,8 @@ $cfg['db_database'] = 'website'; # put absolute path to the db if you
|
|||||||
# are using SQLite.
|
# are using SQLite.
|
||||||
#
|
#
|
||||||
# The extension of the downloads are limited. You can add extra
|
# The extension of the downloads are limited. You can add extra
|
||||||
# extensions here. The list must start with a space.
|
# extensions here.
|
||||||
# $cfg['idf_extra_upload_ext'] = ' ext1 ext2';
|
# $cfg['idf_extra_upload_ext'] = 'ext1 ext2';
|
||||||
#
|
#
|
||||||
# By default, the size of the downloads is limited to 2MB.
|
# By default, the size of the downloads is limited to 2MB.
|
||||||
# The php.ini upload_max_filesize configuration setting will
|
# The php.ini upload_max_filesize configuration setting will
|
||||||
@ -316,6 +256,13 @@ $cfg['allowed_scm'] = array('git' => 'IDF_Scm_Git',
|
|||||||
'mtn' => 'IDF_Scm_Monotone',
|
'mtn' => 'IDF_Scm_Monotone',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# Set to true when uploaded public keys should not only be validated
|
||||||
|
# syntactically, but also by the specific backend. For SSH public
|
||||||
|
# keys, ssh-keygen(3) must be available and usable in PATH, for
|
||||||
|
# monotone public keys, the monotone binary (as configured above)
|
||||||
|
# is used.
|
||||||
|
# $cfg['idf_strong_key_check'] = false;
|
||||||
|
|
||||||
# If you want to use another memtypes database
|
# If you want to use another memtypes database
|
||||||
# $cfg['idf_mimetypes_db'] = '/etc/mime.types';
|
# $cfg['idf_mimetypes_db'] = '/etc/mime.types';
|
||||||
|
|
||||||
|
@ -74,18 +74,18 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/$#',
|
|||||||
'model' => 'IDF_Views_Project',
|
'model' => 'IDF_Views_Project',
|
||||||
'method' => 'home');
|
'method' => 'home');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/timeline/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/timeline/(\w+)/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Project',
|
'model' => 'IDF_Views_Project',
|
||||||
'method' => 'timeline');
|
'method' => 'timeline');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/(\w+)/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Project',
|
'model' => 'IDF_Views_Project',
|
||||||
'method' => 'timelineFeed',
|
'method' => 'timelineFeed',
|
||||||
'name' => 'idf_project_timeline_feed');
|
'name' => 'idf_project_timeline_feed');
|
||||||
|
|
||||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/token/(.*)/$#',
|
$ctl[] = array('regex' => '#^/p/([\-\w]+)/feed/timeline/(\w+)/token/(.*)/$#',
|
||||||
'base' => $base,
|
'base' => $base,
|
||||||
'model' => 'IDF_Views_Project',
|
'model' => 'IDF_Views_Project',
|
||||||
'method' => 'timelineFeed',
|
'method' => 'timelineFeed',
|
||||||
|
@ -96,7 +96,7 @@ Pluf_Signal::connect('IDF_Key::postSave',
|
|||||||
array('IDF_Plugin_SyncMonotone', 'entry'));
|
array('IDF_Plugin_SyncMonotone', 'entry'));
|
||||||
Pluf_Signal::connect('IDF_Key::preDelete',
|
Pluf_Signal::connect('IDF_Key::preDelete',
|
||||||
array('IDF_Plugin_SyncMonotone', 'entry'));
|
array('IDF_Plugin_SyncMonotone', 'entry'));
|
||||||
Pluf_Signal::connect('phppostpush.php::run',
|
Pluf_Signal::connect('mtnpostpush.php::run',
|
||||||
array('IDF_Plugin_SyncMonotone', 'entry'));
|
array('IDF_Plugin_SyncMonotone', 'entry'));
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -4,6 +4,12 @@
|
|||||||
<form method="post" action=".">
|
<form method="post" action=".">
|
||||||
<table class="form" summary="">
|
<table class="form" summary="">
|
||||||
<tr>
|
<tr>
|
||||||
|
<td colspan="2"><strong>{$form.f.labels_issue_template.labelTag}:</strong><br />
|
||||||
|
{if $form.f.labels_issue_template.errors}{$form.f.labels_issue_template.fieldErrors}{/if}
|
||||||
|
{$form.f.labels_issue_template|unsafe}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td colspan="2"><strong>{$form.f.labels_issue_open.labelTag}:</strong><br />
|
<td colspan="2"><strong>{$form.f.labels_issue_open.labelTag}:</strong><br />
|
||||||
{if $form.f.labels_issue_open.errors}{$form.f.labels_issue_open.fieldErrors}{/if}
|
{if $form.f.labels_issue_open.errors}{$form.f.labels_issue_open.fieldErrors}{/if}
|
||||||
{$form.f.labels_issue_open|unsafe}
|
{$form.f.labels_issue_open|unsafe}
|
||||||
|
@ -29,22 +29,19 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
||||||
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}">
|
<div id="{block docid}doc3{/block}">
|
||||||
<div id="hd">
|
<div id="hd">
|
||||||
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
||||||
<p class="top"><a href="#title" accesskey="2"></a>
|
{include 'idf/main-menu.html'}
|
||||||
{if !$user.isAnonymous()}{aurl 'url', 'idf_dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>{else}<a href="{url 'IDF_Views::login'}">{trans 'Sign in or create your account'}</a>{/if}
|
|
||||||
{if $project} | <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a>{/if}
|
|
||||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
|
||||||
</p>
|
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="main-tabs">
|
<div id="main-tabs">
|
||||||
{if $project}
|
{if $project}
|
||||||
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
||||||
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
||||||
{if $hasWikiAccess} <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}"{block tabwiki}{/block}>{trans 'Documentation'}</a>{/if}
|
{if $hasWikiAccess} <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}"{block tabwiki}{/block}>{trans 'Documentation'}</a>{/if}
|
||||||
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
||||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||||
{if $hasReviewAccess} <a href="{url 'IDF_Views_Review::index', array($project.shortname)}"{block tabreview}{/block}>{trans 'Code Review'}</a>{/if}
|
{if $hasReviewAccess} <a href="{url 'IDF_Views_Review::index', array($project.shortname)}"{block tabreview}{/block}>{trans 'Code Review'}</a>{/if}
|
||||||
@ -54,35 +51,34 @@
|
|||||||
{block subtabs}{if $user.isAnonymous()} | {aurl 'url', 'IDF_Views::login'}{blocktrans}<a href="{$url}">Sign in or create your account</a> to create issues or add comments{/blocktrans}{/if}{/block}
|
{block subtabs}{if $user.isAnonymous()} | {aurl 'url', 'IDF_Views::login'}{blocktrans}<a href="{$url}">Sign in or create your account</a> to create issues or add comments{/blocktrans}{/if}{/block}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="title" id="title">{block titleicon}{/block}{block title}{$page_title}{/block}</h1>
|
<h1 class="title" id="title">{block titleicon}{/block}{block title}{$page_title}{/block}</h1>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="bd">
|
<div id="bd">
|
||||||
<div id="yui-main">
|
<div id="yui-main">
|
||||||
<div class="yui-b">
|
<div class="yui-b">
|
||||||
<div class="yui-g">
|
<div class="yui-g">
|
||||||
{if $user and $user.id}{getmsgs $user}{/if}
|
{if $user and $user.id}{getmsgs $user}{/if}
|
||||||
<div class="content">{block body}{/block}</div>
|
<div class="content">{block body}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
|
||||||
{include 'idf/js-hotkeys.html'}
|
{include 'idf/js-hotkeys.html'}
|
||||||
{block javascript}{/block}
|
{block javascript}{/block}
|
||||||
{if $project}
|
{if $project}
|
||||||
<script type="text/javascript" charset="utf-8">{literal}
|
<script type="text/javascript" charset="utf-8">{literal}
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
var frag = location.hash;
|
var frag = location.hash;
|
||||||
if ($('#preview').length) {
|
if ($('#preview').length) {
|
||||||
location.hash = '#preview';
|
location.hash = '#preview';
|
||||||
}
|
}
|
||||||
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||||
$(frag).addClass("issue-comment-focus");
|
$(frag).addClass("issue-comment-focus");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//]]>{/literal}
|
//]]>{/literal}
|
||||||
</script>{/if}
|
</script>{/if}
|
||||||
|
@ -29,31 +29,27 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
||||||
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||||
<div id="hd">
|
<div id="hd">
|
||||||
<p class="top"><a href="#title" accesskey="2"></a>
|
{include 'idf/main-menu.html'}
|
||||||
{if !$user.isAnonymous()}{aurl 'url', 'idf_dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>{else}<a href="{url 'IDF_Views::login'}">{trans 'Sign in or create your account'}</a>{/if}
|
<h1 id="title" class="title">{block title}{$page_title}{/block}</h1>
|
||||||
| <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a> {if $isAdmin}| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a>{/if}
|
|
||||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
|
||||||
</p>
|
|
||||||
<h1 id="title" class="title">{block title}{$page_title}{/block}</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="bd">
|
<div id="bd">
|
||||||
<div id="yui-main">
|
<div id="yui-main">
|
||||||
<div class="yui-b">
|
<div class="yui-b">
|
||||||
<div class="yui-g">
|
<div class="yui-g">
|
||||||
{if $user and $user.id}{getmsgs $user}{/if}
|
{if $user and $user.id}{getmsgs $user}{/if}
|
||||||
<div class="content">{block body}{/block}</div>
|
<div class="content">{block body}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="yui-b context">{block context}{/block}</div>
|
<div class="yui-b context">{block context}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
|
||||||
{include 'idf/js-hotkeys.html'}
|
{include 'idf/js-hotkeys.html'}
|
||||||
{block javascript}{/block}
|
{block javascript}{/block}
|
||||||
</body>
|
</body>
|
||||||
|
@ -29,23 +29,19 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}{if $project} - {$project.shortdesc}{/if}</title>
|
||||||
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||||
<div id="hd">
|
<div id="hd">
|
||||||
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
{if $project}<h1 class="project-title">{$project}</h1>{/if}
|
||||||
<p class="top"><a href="#title" accesskey="2"></a>
|
{include 'idf/main-menu.html'}
|
||||||
{if !$user.isAnonymous()}{aurl 'url', 'idf_dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>{else}<a href="{url 'IDF_Views::login'}">{trans 'Sign in or create your account'}</a>{/if}
|
|
||||||
{if $project} | <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a>{/if}
|
|
||||||
{if $isAdmin}| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a>{/if}
|
|
||||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
|
||||||
</p>
|
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="main-tabs">
|
<div id="main-tabs">
|
||||||
{if $project}
|
{if $project}
|
||||||
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
||||||
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
||||||
{if $hasWikiAccess} <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}"{block tabwiki}{/block}>{trans 'Documentation'}</a>{/if}
|
{if $hasWikiAccess} <a href="{url 'IDF_Views_Wiki::index', array($project.shortname)}"{block tabwiki}{/block}>{trans 'Documentation'}</a>{/if}
|
||||||
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
||||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||||
{if $hasReviewAccess} <a href="{url 'IDF_Views_Review::index', array($project.shortname)}"{block tabreview}{/block}>{trans 'Code Review'}</a>{/if}
|
{if $hasReviewAccess} <a href="{url 'IDF_Views_Review::index', array($project.shortname)}"{block tabreview}{/block}>{trans 'Code Review'}</a>{/if}
|
||||||
@ -55,36 +51,35 @@
|
|||||||
{block subtabs}{if $user.isAnonymous()} | {aurl 'url', 'IDF_Views::login'}{blocktrans}<a href="{$url}">Sign in or create your account</a> to create issues or add comments{/blocktrans}{/if}{/block}
|
{block subtabs}{if $user.isAnonymous()} | {aurl 'url', 'IDF_Views::login'}{blocktrans}<a href="{$url}">Sign in or create your account</a> to create issues or add comments{/blocktrans}{/if}{/block}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="title" id="title">{block titleicon}{/block}{block title}{$page_title}{/block}</h1>
|
<h1 class="title" id="title">{block titleicon}{/block}{block title}{$page_title}{/block}</h1>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="bd">
|
<div id="bd">
|
||||||
<div id="yui-main">
|
<div id="yui-main">
|
||||||
<div class="yui-b">
|
<div class="yui-b">
|
||||||
<div class="yui-g">
|
<div class="yui-g">
|
||||||
{if $user and $user.id}{getmsgs $user}{/if}
|
{if $user and $user.id}{getmsgs $user}{/if}
|
||||||
<div class="content">{block body}{/block}</div>
|
<div class="content">{block body}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="yui-b context">{block context}{/block}</div>
|
<div class="yui-b context">{block context}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
|
||||||
{include 'idf/js-hotkeys.html'}
|
{include 'idf/js-hotkeys.html'}
|
||||||
{block javascript}{/block}
|
{block javascript}{/block}
|
||||||
{if $project}
|
{if $project}
|
||||||
<script type="text/javascript" charset="utf-8">{literal}
|
<script type="text/javascript" charset="utf-8">{literal}
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
var frag = location.hash;
|
var frag = location.hash;
|
||||||
if ($('#preview').length) {
|
if ($('#preview').length) {
|
||||||
location.hash = '#preview';
|
location.hash = '#preview';
|
||||||
}
|
}
|
||||||
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
else if (frag.length > 3 && frag.substring(0, 3) == '#ic') {
|
||||||
$(frag).addClass("issue-comment-focus");
|
$(frag).addClass("issue-comment-focus");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//]]>{/literal}
|
//]]>{/literal}
|
||||||
</script>{/if}
|
</script>{/if}
|
||||||
|
@ -29,16 +29,12 @@
|
|||||||
<![endif]-->
|
<![endif]-->
|
||||||
{block extraheader}{/block}
|
{block extraheader}{/block}
|
||||||
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
<title>{block pagetitle}{$page_title|strip_tags}{/block}</title>
|
||||||
|
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
<div id="{block docid}doc3{/block}" class="{block docclass}yui-t3{/block}">
|
||||||
<div id="hd">
|
<div id="hd">
|
||||||
<p class="top"><a href="#title" accesskey="2"></a>
|
{include 'idf/main-menu.html'}
|
||||||
{aurl 'url', 'IDF_Views_User::dashboard'}{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans} <a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a>
|
|
||||||
| <a href="{url 'IDF_Views::index'}">{trans 'Project List'}</a>
|
|
||||||
| <a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a>
|
|
||||||
| <a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a>
|
|
||||||
</p>
|
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="main-tabs">
|
<div id="main-tabs">
|
||||||
<a href="{url 'IDF_Views_Admin::projects'}"{block tabprojects}{/block}>{trans 'Projects'}</a>
|
<a href="{url 'IDF_Views_Admin::projects'}"{block tabprojects}{/block}>{trans 'Projects'}</a>
|
||||||
@ -64,7 +60,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="ft">{block foot}{/block}</div>
|
<div id="ft">{block foot}{/block}</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="{media '/idf/js/jquery-1.2.6.min.js'}"></script>
|
|
||||||
{include 'idf/js-hotkeys.html'}
|
{include 'idf/js-hotkeys.html'}
|
||||||
{block javascript}{/block}
|
{block javascript}{/block}
|
||||||
</body>
|
</body>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// <!--
|
// <!--
|
||||||
{hotkey 'Shift+h', 'IDF_Views::faq'}
|
{hotkey 'Shift+h', 'IDF_Views::faq'}
|
||||||
{if $project}
|
{if $project}
|
||||||
{hotkey 'Shift+u', 'IDF_Views_Project::timeline', array($project.shortname)}
|
{hotkey 'Shift+u', 'IDF_Views_Project::timeline', array($project.shortname, 'all')}
|
||||||
{if $hasIssuesAccess}{hotkey 'Shift+a', 'IDF_Views_Issue::create', array($project.shortname)}
|
{if $hasIssuesAccess}{hotkey 'Shift+a', 'IDF_Views_Issue::create', array($project.shortname)}
|
||||||
{hotkey 'Shift+i', 'IDF_Views_Issue::index', array($project.shortname)}{/if}
|
{hotkey 'Shift+i', 'IDF_Views_Issue::index', array($project.shortname)}{/if}
|
||||||
{if $hasDownloadsAccess}{hotkey 'Shift+d', 'IDF_Views_Download::index', array($project.shortname)}{/if}
|
{if $hasDownloadsAccess}{hotkey 'Shift+d', 'IDF_Views_Download::index', array($project.shortname)}{/if}
|
||||||
|
31
src/IDF/templates/idf/main-menu.html
Normal file
31
src/IDF/templates/idf/main-menu.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<a href="#title" accesskey="2"></a>
|
||||||
|
<ul id="main-menu">
|
||||||
|
{if !$user.isAnonymous()}
|
||||||
|
{aurl 'url', 'idf_dashboard'}
|
||||||
|
<li>{blocktrans}Welcome, <strong><a class="userw" href="{$url}">{$user}</a></strong>.{/blocktrans}
|
||||||
|
<a href="{url 'IDF_Views::logout'}">{trans 'Sign Out'}</a></li>{else}<li>
|
||||||
|
<a href="{url 'IDF_Views::login'}">{trans 'Sign in or create your account'}</a></li>
|
||||||
|
{/if}<li id="project-list"><a href="{url 'IDF_Views::index'}">{trans 'Project List'} ▾</a>
|
||||||
|
{if $allProjects.count() != 0}
|
||||||
|
<ul>{foreach $allProjects as $p}
|
||||||
|
<li>{if $p.private}<img style="vertical-align: text-bottom;" src="{media '/idf/img/lock.png'}" alt="{trans 'Private project'}" /> {/if}
|
||||||
|
<a href="{url 'IDF_Views_Project::home', array($p.shortname)}">{$p}</a></li>
|
||||||
|
{/foreach}</ul>
|
||||||
|
{/if}</li>{if $isAdmin}<li><a href="{url 'IDF_Views_Admin::projects'}">{trans 'Forge Management'}</a></li>{/if}<li>
|
||||||
|
<a href="{url 'IDF_Views::faq'}" title="{trans 'Help and accessibility features'}">{trans 'Help'}</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{if $allProjects.count() != 0}
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
{literal}
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#project-list').bind('mouseenter', function(ev) {
|
||||||
|
$(this).find('ul').show();
|
||||||
|
}).bind('mouseleave', function(ev) {
|
||||||
|
$(this).find('ul').hide();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
{/literal}
|
||||||
|
</script>
|
||||||
|
{/if}
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
{block tabhome} class="active"{/block}
|
{block tabhome} class="active"{/block}
|
||||||
{block subtabs}
|
{block subtabs}
|
||||||
<div id="sub-tabs">
|
<div id="sub-tabs">
|
||||||
{trans 'Welcome'} | <strong><a href="{url 'IDF_Views_Project::timeline', array($project.shortname)}">{trans 'Latest Updates'}</a></strong>{superblock}
|
{trans 'Welcome'} | <strong><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, 'all')}">{trans 'Latest Updates'}</a></strong>{superblock}
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
{block body}
|
{block body}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
{block tabhome} class="active"{/block}
|
{block tabhome} class="active"{/block}
|
||||||
{block subtabs}
|
{block subtabs}
|
||||||
<div id="sub-tabs">
|
<div id="sub-tabs">
|
||||||
<a href="{url 'IDF_Views_Project::home', array($project.shortname)}">{trans 'Welcome'}</a> | <strong><a href="{url 'IDF_Views_Project::timeline', array($project.shortname)}" class="active">{trans 'Latest Updates'}</a></strong>{superblock}
|
<a href="{url 'IDF_Views_Project::home', array($project.shortname)}">{trans 'Welcome'}</a> | <strong><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, 'all')}" class="active">{trans 'Latest Updates'}</a></strong>{superblock}
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
@ -13,26 +13,10 @@
|
|||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
{block context}
|
{block context}
|
||||||
{if count($downloads) > 0}
|
<p><strong>{trans 'Filter by type'}</strong><br />
|
||||||
<p><strong>{trans 'Featured Downloads'}</strong><br />
|
{foreach $all_model_filters as $filter_key => $filter_name}
|
||||||
{foreach $downloads as $download}
|
<span class="label{if $filter_key == $model_filter} active{/if}"><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, $filter_key)}">{$filter_name}</a></span><br />
|
||||||
<span class="label"><a href="{url 'IDF_Views_Download::view', array($project.shortname, $download.id)}" title="{$download.summary}">{$download}</a></span><br />
|
|
||||||
{/foreach}
|
{/foreach}
|
||||||
<span class="label"> </span><span class="note"><a href="{url 'IDF_Views_Download::index', array($project.shortname)}">{trans 'show more...'}</a></span>
|
|
||||||
{/if}
|
|
||||||
{assign $ko = 'owners'}
|
|
||||||
{assign $km = 'members'}
|
|
||||||
<p><strong>{trans 'Development Team'}</strong><br />
|
|
||||||
{trans 'Admins'}<br />
|
|
||||||
{foreach $team[$ko] as $owner}{aurl 'url', 'IDF_Views_User::view', array($owner.login)}
|
|
||||||
<span class="label"><a class="label" href="{$url}">{$owner}</a></span><br />
|
|
||||||
{/foreach}
|
|
||||||
{if count($team[$km]) > 0}
|
|
||||||
{trans 'Happy Crew'}<br />
|
|
||||||
{foreach $team[$km] as $member}{aurl 'url', 'IDF_Views_User::view', array($member.login)}
|
|
||||||
<span class="label"><a class="label" href="{$url}">{$member}</a></span><br />
|
|
||||||
{/foreach}
|
|
||||||
{/if}
|
|
||||||
</p>
|
</p>
|
||||||
{/block}
|
{/block}
|
||||||
|
|
||||||
|
@ -19,92 +19,92 @@
|
|||||||
#
|
#
|
||||||
# ***** END LICENSE BLOCK ***** */
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: arial, helvetica, sans-serif;
|
font-family: arial, helvetica, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top {
|
.top {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
color: #00e;
|
color: #00e;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited {
|
a:visited {
|
||||||
color: #551a8b;
|
color: #551a8b;
|
||||||
}
|
|
||||||
|
|
||||||
a:active{
|
|
||||||
color: #f00;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.yui-g {
|
a:active{
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yui-g {
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.a-c {
|
.a-c {
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dellink {
|
.dellink {
|
||||||
float: right;
|
float: right;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dellink a {
|
.dellink a {
|
||||||
color: #a00;
|
color: #a00;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.userw {
|
a.userw {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mono {
|
.mono {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soft {
|
.soft {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soft a {
|
.soft a {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.soft {
|
a.soft {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.soft:visited {
|
a.soft:visited {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.context {
|
div.context {
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form
|
* Form
|
||||||
*/
|
*/
|
||||||
form.star {
|
form.star {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.form th, table.form td {
|
table.form th, table.form td {
|
||||||
border: none;
|
border: none;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
table.form th {
|
table.form th {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.px-message-error {
|
.px-message-error {
|
||||||
padding-left: 37px;
|
padding-left: 37px;
|
||||||
background: url("../img/dialog-error.png");
|
background: url("../img/dialog-error.png");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@ -114,12 +114,12 @@ table.form th {
|
|||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.errorlist {
|
ul.errorlist {
|
||||||
color: #c00;
|
color: #c00;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.user-messages {
|
div.user-messages {
|
||||||
border: 1px solid rgb(229, 225, 169);
|
border: 1px solid rgb(229, 225, 169);
|
||||||
background-color: #fffde3;
|
background-color: #fffde3;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
@ -127,7 +127,7 @@ div.user-messages {
|
|||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.theterms {
|
div.theterms {
|
||||||
border: 1px solid rgb(229, 225, 169);
|
border: 1px solid rgb(229, 225, 169);
|
||||||
background-color: #fffde3;
|
background-color: #fffde3;
|
||||||
padding: 1em 1em 0 1em;
|
padding: 1em 1em 0 1em;
|
||||||
@ -137,92 +137,92 @@ div.theterms {
|
|||||||
/**
|
/**
|
||||||
* Recent issues
|
* Recent issues
|
||||||
*/
|
*/
|
||||||
table.recent-issues {
|
table.recent-issues {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.minsize {
|
table.minsize {
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues tr.log {
|
table.recent-issues tr.log {
|
||||||
border-bottom: 1px solid #e7ebe3;
|
border-bottom: 1px solid #e7ebe3;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues th {
|
table.recent-issues th {
|
||||||
background-color: #e4e8E0;
|
background-color: #e4e8E0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
border-color: #d3d7cf;
|
border-color: #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues tr {
|
table.recent-issues tr {
|
||||||
border-left: 1px solid #d3d7cf;
|
border-left: 1px solid #d3d7cf;
|
||||||
border-right: 1px solid #d3d7cf;
|
border-right: 1px solid #d3d7cf;
|
||||||
border-bottom: 1px solid #d3d7cf;
|
border-bottom: 1px solid #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues td {
|
table.recent-issues td {
|
||||||
border: none;
|
border: none;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues tfoot th {
|
table.recent-issues tfoot th {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues tfoot th a {
|
table.recent-issues tfoot th a {
|
||||||
color: #000;
|
color: #000;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.recent-issues th a.px-current-page {
|
table.recent-issues th a.px-current-page {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.px-sort {
|
span.px-sort {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 70%;
|
font-size: 70%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.px-header-title {
|
span.px-header-title {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.px-header-title a, span.px-header-title a:link, span.px-header-title a:visited, span.px-header-title a:active {
|
span.px-header-title a, span.px-header-title a:link, span.px-header-title a:visited, span.px-header-title a:active {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Issue
|
* Issue
|
||||||
*/
|
*/
|
||||||
a.issue-c {
|
a.issue-c {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre.issue-comment-text {
|
pre.issue-comment-text {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
line-height: 1.2; /* to be nice also with links */
|
line-height: 1.2; /* to be nice also with links */
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-comment {
|
div.issue-comment {
|
||||||
border-left: 3px solid #8ae234;
|
border-left: 3px solid #8ae234;
|
||||||
border-bottom: 1px solid #d3d7cf;
|
border-bottom: 1px solid #d3d7cf;
|
||||||
border-right: 1px solid #d3d7cf;
|
border-right: 1px solid #d3d7cf;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.issue-comment-focus {
|
.issue-comment-focus {
|
||||||
border-right: 3px solid #8ae234 !important;
|
border-right: 3px solid #8ae234 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-comment-first {
|
div.issue-comment-first {
|
||||||
border-top: 1px solid #d3d7cf;
|
border-top: 1px solid #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-comment-signin {
|
div.issue-comment-signin {
|
||||||
-moz-border-radius: 0 0 3px 3px;
|
-moz-border-radius: 0 0 3px 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
-webkit-border-top-left-radius: 0;
|
-webkit-border-top-left-radius: 0;
|
||||||
@ -231,11 +231,11 @@ div.issue-comment-signin {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-comment-signin a {
|
div.issue-comment-signin a {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-changes {
|
div.issue-changes {
|
||||||
background-color: #d3d7cf;
|
background-color: #d3d7cf;
|
||||||
-moz-border-radius: 3px;
|
-moz-border-radius: 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
@ -243,7 +243,7 @@ div.issue-changes {
|
|||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-changes-timeline {
|
div.issue-changes-timeline {
|
||||||
background-color: #eeeeec;
|
background-color: #eeeeec;
|
||||||
-moz-border-radius: 3px;
|
-moz-border-radius: 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
@ -253,7 +253,7 @@ div.issue-changes-timeline {
|
|||||||
color: #888a85;
|
color: #888a85;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-submit-info {
|
div.issue-submit-info {
|
||||||
background-color: #d3d7cf;
|
background-color: #d3d7cf;
|
||||||
-moz-border-radius: 3px;
|
-moz-border-radius: 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
@ -261,47 +261,47 @@ div.issue-submit-info {
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.issue-submit-info h2 {
|
div.issue-submit-info h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.label {
|
span.label {
|
||||||
color: #204a87;
|
color: #204a87;
|
||||||
padding-left: 0.5em;
|
padding-left: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.label {
|
a.label {
|
||||||
color: #204a87;
|
color: #204a87;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
color: #204a87;
|
color: #204a87;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.nobrk {
|
span.nobrk {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr { visibility: hidden; }
|
hr { visibility: hidden; }
|
||||||
|
|
||||||
hr.attach {
|
hr.attach {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: #d3d7cf;
|
background-color: #d3d7cf;
|
||||||
color: #d3d7cf;
|
color: #d3d7cf;
|
||||||
width: 40%;
|
width: 40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1.title {
|
h1.title {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1.project-title {
|
h1.project-title {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
float: right;
|
float: right;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
@ -310,55 +310,55 @@ h1.project-title {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note {
|
.note {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smaller {
|
.smaller {
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.active {
|
span.active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.helptext {
|
.helptext {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: #555753;
|
color: #555753;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.container {
|
div.container {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sep {
|
.sep {
|
||||||
margin: 0 0.3em;
|
margin: 0 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tabs
|
* Tabs
|
||||||
*/
|
*/
|
||||||
#main-tabs {
|
#main-tabs {
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-tabs a {
|
#main-tabs a {
|
||||||
background-color: #d3d7cf;
|
background-color: #d3d7cf;
|
||||||
-moz-border-radius: 3px 3px 0 0;
|
-moz-border-radius: 3px 3px 0 0;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
-webkit-border-bottom-left-radius: 0;
|
-webkit-border-bottom-left-radius: 0;
|
||||||
-webkit-border-bottom-right-radius: 0;
|
-webkit-border-bottom-right-radius: 0;
|
||||||
padding: 4px 4px 0 4px;
|
padding: 4px 4px 0 4px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #2e3436;
|
color: #2e3436;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-tabs a.active {
|
#main-tabs a.active {
|
||||||
background-color: #a5e26a;
|
background-color: #a5e26a;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sub-tabs {
|
#sub-tabs {
|
||||||
background-color: #a5e26a;
|
background-color: #a5e26a;
|
||||||
-moz-border-radius: 0 3px 3px 3px;
|
-moz-border-radius: 0 3px 3px 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
@ -366,63 +366,63 @@ div.container {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sub-tabs a {
|
#sub-tabs a {
|
||||||
color: #2e3436;
|
color: #2e3436;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sub-tabs a.active {
|
#sub-tabs a.active {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Tree list
|
* Tree list
|
||||||
*/
|
*/
|
||||||
table.tree-list {
|
table.tree-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list th {
|
table.tree-list th {
|
||||||
background-color: #e4e8E0;
|
background-color: #e4e8E0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
border-color: #d3d7cf;
|
border-color: #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list tr {
|
table.tree-list tr {
|
||||||
border-left: 1px solid #d3d7cf;
|
border-left: 1px solid #d3d7cf;
|
||||||
border-right: 1px solid #d3d7cf;
|
border-right: 1px solid #d3d7cf;
|
||||||
border-bottom: 1px solid #d3d7cf;
|
border-bottom: 1px solid #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list td {
|
table.tree-list td {
|
||||||
border: none;
|
border: none;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list tfoot th, table.code tfoot th {
|
table.tree-list tfoot th, table.code tfoot th {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list tfoot th a, table.code tfoot th a {
|
table.tree-list tfoot th a, table.code tfoot th a {
|
||||||
color: #000;
|
color: #000;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list tfoot th ul, table.code tfoot th ul {
|
table.tree-list tfoot th ul, table.code tfoot th ul {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list tr.log {
|
table.tree-list tr.log {
|
||||||
border-bottom: 1px solid #e7ebe3;
|
border-bottom: 1px solid #e7ebe3;
|
||||||
/* background-color: #eef2ea !important; */
|
/* background-color: #eef2ea !important; */
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tree-list tr.extra {
|
table.tree-list tr.extra {
|
||||||
/* border-bottom: 1px solid #e7ebe3; */
|
/* border-bottom: 1px solid #e7ebe3; */
|
||||||
/* background-color: #eef2ea !important; */
|
/* background-color: #eef2ea !important; */
|
||||||
}
|
}
|
||||||
|
|
||||||
table td.fileicon {
|
table td.fileicon {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -452,15 +452,15 @@ table td.fileicon {
|
|||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
display: block;
|
display: block;
|
||||||
/*
|
/*
|
||||||
if width will be 100% horizontal scrollbar will apear
|
if width will be 100% horizontal scrollbar will apear
|
||||||
when scroll mode will be used
|
when scroll mode will be used
|
||||||
*/
|
*/
|
||||||
/*width: 100%;*/
|
/*width: 100%;*/
|
||||||
font: menu;
|
font: menu;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
/*
|
/*
|
||||||
it is very important, if line-height not setted or setted
|
it is very important, if line-height not setted or setted
|
||||||
in relative units scroll will be broken in firefox
|
in relative units scroll will be broken in firefox
|
||||||
*/
|
*/
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
@ -480,7 +480,7 @@ table td.fileicon {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.disp th, table.disp td {
|
table.disp th, table.disp td {
|
||||||
border: none;
|
border: none;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
@ -488,48 +488,48 @@ table.disp th, table.disp td {
|
|||||||
/**
|
/**
|
||||||
* Commit
|
* Commit
|
||||||
*/
|
*/
|
||||||
table.commit th, table.commit td {
|
table.commit th, table.commit td {
|
||||||
border: none;
|
border: none;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
table.commit th {
|
table.commit th {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
table.commit td, table.commit th {
|
table.commit td, table.commit th {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* syntax highlighting of diffs
|
* syntax highlighting of diffs
|
||||||
*/
|
*/
|
||||||
table.diff {
|
table.diff {
|
||||||
border-bottom: 1px solid #d3d7cf;
|
border-bottom: 1px solid #d3d7cf;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.diff th {
|
table.diff th {
|
||||||
background-color: #e4e8E0;
|
background-color: #e4e8E0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
border-color: #d3d7cf;
|
border-color: #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table.diff tr {
|
table.diff tr {
|
||||||
border-left: 1px solid #d3d7cf;
|
border-left: 1px solid #d3d7cf;
|
||||||
border-right: 1px solid #d3d7cf;
|
border-right: 1px solid #d3d7cf;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.diff td {
|
table.diff td {
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
border-color: inherit;
|
border-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.diff td.diff-lc {
|
table.diff td.diff-lc {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
border-color: inherit;
|
border-color: inherit;
|
||||||
@ -538,27 +538,27 @@ table.diff td.diff-lc {
|
|||||||
width: 3em;
|
width: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.diff-a {
|
td.diff-a {
|
||||||
background-color: #dfd;
|
background-color: #dfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.diff-r {
|
td.diff-r {
|
||||||
background-color: #fdd;
|
background-color: #fdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.diff-a, td.diff-r, td.diff-c {
|
td.diff-a, td.diff-r, td.diff-c {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.diff tr.diff-next {
|
table.diff tr.diff-next {
|
||||||
background-color: #e4e8E0;
|
background-color: #e4e8E0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
border-color: #d3d7cf;
|
border-color: #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.diff tr.diff-next td {
|
table.diff tr.diff-next td {
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,33 +566,33 @@ table.diff tr.diff-next td {
|
|||||||
/**
|
/**
|
||||||
* view file content
|
* view file content
|
||||||
*/
|
*/
|
||||||
table.code {
|
table.code {
|
||||||
border-bottom: 1px solid #d3d7cf;
|
border-bottom: 1px solid #d3d7cf;
|
||||||
border-top: 1px solid #d3d7cf;
|
border-top: 1px solid #d3d7cf;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.code th {
|
table.code th {
|
||||||
background-color: #e4e8E0;
|
background-color: #e4e8E0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
border-color: #d3d7cf;
|
border-color: #d3d7cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.code tr {
|
table.code tr {
|
||||||
border-left: 1px solid #d3d7cf;
|
border-left: 1px solid #d3d7cf;
|
||||||
border-right: 1px solid #d3d7cf;
|
border-right: 1px solid #d3d7cf;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.code td {
|
table.code td {
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
border-color: inherit;
|
border-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.code td.code {
|
table.code td.code {
|
||||||
border: none;
|
border: none;
|
||||||
/* Whitespace hacking from: http://ln.hixie.ch/ */
|
/* Whitespace hacking from: http://ln.hixie.ch/ */
|
||||||
white-space: pre; /* CSS2 */
|
white-space: pre; /* CSS2 */
|
||||||
@ -601,12 +601,11 @@ table.code td.code {
|
|||||||
white-space: -o-pre-wrap; /* Opera 7 */
|
white-space: -o-pre-wrap; /* Opera 7 */
|
||||||
white-space: -pre-wrap; /* Opera 4-6 */
|
white-space: -pre-wrap; /* Opera 4-6 */
|
||||||
white-space: pre-wrap; /* CSS 2.1 */
|
white-space: pre-wrap; /* CSS 2.1 */
|
||||||
white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
|
word-wrap: break-word; /* IE */
|
||||||
word-wrap: break-word; /* IE */
|
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.code td.code-lc {
|
table.code td.code-lc {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
border-color: inherit;
|
border-color: inherit;
|
||||||
@ -615,7 +614,7 @@ table.code td.code-lc {
|
|||||||
width: 3em;
|
width: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.code td.code-lc a {
|
table.code td.code-lc a {
|
||||||
color: #555753;
|
color: #555753;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@ -623,7 +622,7 @@ table.code td.code-lc a {
|
|||||||
/**
|
/**
|
||||||
* Download
|
* Download
|
||||||
*/
|
*/
|
||||||
div.download-file {
|
div.download-file {
|
||||||
padding: 1em 1em 1em 3em;
|
padding: 1em 1em 1em 3em;
|
||||||
background: url("../img/down-large.png");
|
background: url("../img/down-large.png");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@ -636,14 +635,14 @@ div.download-file {
|
|||||||
-webkit-border-radius: 5px;
|
-webkit-border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.download {
|
table.download {
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wiki
|
* Wiki
|
||||||
*/
|
*/
|
||||||
p.desc {
|
p.desc {
|
||||||
background-color: #eeeeec;
|
background-color: #eeeeec;
|
||||||
-moz-border-radius: 3px;
|
-moz-border-radius: 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
@ -651,7 +650,7 @@ p.desc {
|
|||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.old-rev {
|
div.old-rev {
|
||||||
padding: 1em 1em 0.1em 1em;
|
padding: 1em 1em 0.1em 1em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
background-color: #bbe394;
|
background-color: #bbe394;
|
||||||
@ -660,7 +659,7 @@ div.old-rev {
|
|||||||
-webkit-border-radius: 5px;
|
-webkit-border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.deprecated-page {
|
div.deprecated-page {
|
||||||
padding: 1em 1em 0.1em 3em;
|
padding: 1em 1em 0.1em 3em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
background: url("../img/warning-large.png");
|
background: url("../img/warning-large.png");
|
||||||
@ -674,16 +673,16 @@ div.deprecated-page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.delp {
|
.delp {
|
||||||
float: right;
|
float: right;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delp a {
|
.delp a {
|
||||||
color: #a00;
|
color: #a00;
|
||||||
}
|
}
|
||||||
|
|
||||||
#branding {
|
#branding {
|
||||||
float: right;
|
float: right;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: -10px;
|
margin-right: -10px;
|
||||||
@ -693,7 +692,7 @@ div.deprecated-page {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
background-color: #eeeeec;
|
background-color: #eeeeec;
|
||||||
-moz-border-radius: 3px 0 0 3px;
|
-moz-border-radius: 3px 0 0 3px;
|
||||||
-webkit-border-radius: 3px;
|
-webkit-border-radius: 3px;
|
||||||
-webkit-border-top-right-radius: 0;
|
-webkit-border-top-right-radius: 0;
|
||||||
@ -705,15 +704,102 @@ div.deprecated-page {
|
|||||||
background-position: top right;
|
background-position: top right;
|
||||||
}
|
}
|
||||||
|
|
||||||
#branding a {
|
#branding a {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
#branding a:visited {
|
#branding a:visited {
|
||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ft {
|
#ft {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main menu
|
||||||
|
*/
|
||||||
|
#main-menu {
|
||||||
|
padding: 0;
|
||||||
|
margin: 5px 0 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu > li {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left: 5px;
|
||||||
|
padding-left: 5px;
|
||||||
|
border-left: 1px solid black;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu > li:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* project list popup
|
||||||
|
*/
|
||||||
|
#project-list {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list > a {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
margin-top: -3px;
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list + li {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list ul {
|
||||||
|
display: none;
|
||||||
|
background: #A5E26A;
|
||||||
|
border-top: 0;
|
||||||
|
position: absolute;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
top: 1.1em;
|
||||||
|
-moz-border-radius: 0 0 3px 3px;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
-moz-box-shadow: 0 10px 20px #333;
|
||||||
|
-webkit-box-shadow: 0 10px 20px #333;
|
||||||
|
box-shadow: 0 10px 20px #333;
|
||||||
|
max-height: 400px;
|
||||||
|
min-width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list ul li {
|
||||||
|
margin: 7px;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 0.95em;
|
||||||
|
list-style-type: square;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list ul li:first-child {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list ul li a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list:hover > a {
|
||||||
|
background: #A5E26A;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#project-list:hover a {
|
||||||
|
color: #2E3436;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user