Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
836fa47812 | ||
|
|
77b3650580 | ||
|
|
67ee6857ad | ||
|
|
5ab15c0a14 | ||
|
|
96a3f2c301 | ||
|
|
85707264c4 | ||
|
|
ed05422ea8 | ||
|
|
8f10c8051e | ||
|
|
41fff399b5 | ||
|
|
9e237647b0 | ||
|
|
1be53c6746 | ||
|
|
f2368b03c0 | ||
|
|
95284c0b36 | ||
|
|
f1e21a93fb | ||
|
|
689811f659 | ||
|
|
33ccb4e98c | ||
|
|
29f6e98f9c | ||
|
|
775c8cc064 | ||
|
|
9a974d047c | ||
|
|
3fd252d2db | ||
|
|
43edb034c8 | ||
|
|
e629ca391e | ||
|
|
0db7eba3f2 | ||
|
|
a472abc88e | ||
|
|
861c619c19 | ||
|
|
124f331963 | ||
|
|
76fcd44191 | ||
|
|
2124c0b88c | ||
|
|
2f5ab8e3b9 | ||
|
|
32c8b6914b | ||
|
|
7e9d940f64 | ||
|
|
59e826b630 | ||
|
|
88f3ee4b13 | ||
|
|
b7380a084e | ||
|
|
cb65e790ae | ||
|
|
573eabee93 | ||
|
|
f0d4c6546a | ||
|
|
b0943c87c8 | ||
|
|
4f1208ea98 | ||
|
|
02f16639ea | ||
|
|
cd5e28c0b8 | ||
|
|
6f7579f8d9 | ||
|
|
f1d2a71b49 | ||
|
|
fd4fe0dc0d | ||
|
|
3d5e4a4225 | ||
|
|
10ffb452d0 | ||
|
|
3218bddbdc | ||
|
|
59f78dcbcb | ||
|
|
0fe062a02f | ||
|
|
869eaf8cfd | ||
|
|
5b445c9736 | ||
|
|
6f3f3eaa99 | ||
|
|
a23ce92676 | ||
|
|
ad55d5199d | ||
|
|
bd05895761 | ||
|
|
c68dd6c891 | ||
|
|
daae9ae1e7 | ||
|
|
33dde75ae1 | ||
|
|
b2e1e1796d | ||
|
|
1ff68111b4 | ||
|
|
dff816324d | ||
|
|
a33e2c6e36 | ||
|
|
75ef82d18a | ||
|
|
eb3c522122 | ||
|
|
6c8bcfc62e |
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
*.class
|
||||
*.log
|
||||
.ensime
|
||||
.ensime_cache
|
||||
|
||||
# sbt specific
|
||||
dist/*
|
||||
|
||||
@@ -81,6 +81,12 @@ Run the following commands in `Terminal` to
|
||||
|
||||
Release Notes
|
||||
--------
|
||||
### 3.5 - 1 Aug 2015
|
||||
- Octicons has been applied
|
||||
- Global header has been enhanced. Now it's further similar to GitHub.
|
||||
- Default compare / pull request target has been changed to the parent repository
|
||||
- A lot of updates for [gitbucket-gist-plugin](https://github.com/takezoe/gitbucket-gist-plugin)
|
||||
|
||||
### 3.4 - 27 Jun 2015
|
||||
- Declarative style plug-in definition
|
||||
- New extension point to add markup render
|
||||
|
||||
@@ -16,6 +16,8 @@ for Developers
|
||||
--------
|
||||
If you want to modify source code and confirm it, you can run GitBucket in auto reloading mode as following:
|
||||
|
||||
Windows:
|
||||
|
||||
```
|
||||
C:\gitbucket> sbt
|
||||
...
|
||||
@@ -24,15 +26,38 @@ C:\gitbucket> sbt
|
||||
> ~ ;copy-resources;aux-compile
|
||||
```
|
||||
|
||||
Linux:
|
||||
|
||||
```
|
||||
~/gitbucket$ ./sbt.sh
|
||||
...
|
||||
> container:start
|
||||
...
|
||||
> ~ ;copy-resources;aux-compile
|
||||
```
|
||||
|
||||
Build war file
|
||||
--------
|
||||
|
||||
To build war file, run the following command:
|
||||
|
||||
Windows:
|
||||
|
||||
```
|
||||
C:\gitbucket> sbt package
|
||||
```
|
||||
|
||||
Linux:
|
||||
|
||||
```
|
||||
~/gitbucket$ ./sbt.sh package
|
||||
```
|
||||
|
||||
`gitbucket_2.11-x.x.x.war` is generated into `target/scala-2.11`.
|
||||
|
||||
To build executable war file, run Ant at the top of the source tree. It generates executable `gitbucket.war` into `target/scala-2.11`. We release this war file as release artifact. Please note the current build.xml works on Windows only. Replace `sbt.bat` with `sbt.sh` in build.xml if you want to run it on Linux.
|
||||
To build executable war file, run
|
||||
|
||||
* Windows: Not available
|
||||
* Linux: `./release/make-release-war.sh`
|
||||
|
||||
at the top of the source tree. It generates executable `gitbucket.war` into `target/scala-2.11`. We release this war file as release artifact.
|
||||
|
||||
@@ -379,21 +379,21 @@
|
||||
<path d="M588.909,926.673 L560.094,910.545 L564.713,935.73 L588.909,926.673 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="1.313" stroke-linecap="round"/>
|
||||
</g>
|
||||
<g id="rect3075-11">
|
||||
<path d="M779.562,898.094 C779.396,912.75 779.229,927.406 779.062,942.062 C781.26,942.084 783.458,942.104 785.656,942.125 C784.104,943.688 782.552,945.25 781,946.813 C801.708,967.521 822.417,988.229 843.125,1008.938 C858.531,993.531 873.938,978.125 889.344,962.719 C868.635,942 847.927,921.281 827.219,900.563 C825.49,902.302 823.76,904.042 822.031,905.781 C822.052,903.386 822.073,900.99 822.094,898.594 C807.917,898.427 793.74,898.261 779.563,898.094 z" fill="#FFFFFF"/>
|
||||
<path d="M779.562,898.094 C779.396,912.75 779.229,927.406 779.062,942.062 C781.26,942.084 783.458,942.104 785.656,942.125 C784.104,943.688 782.552,945.25 781,946.813 C801.708,967.521 822.417,988.229 843.125,1008.938 C858.531,993.531 873.938,978.125 889.344,962.719 C868.635,942 847.927,921.281 827.219,900.563 C825.49,902.302 823.76,904.042 822.031,905.781 C822.052,903.386 822.073,900.99 822.094,898.594 C807.917,898.427 793.74,898.261 779.563,898.094 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="9" stroke-linecap="round"/>
|
||||
<path d="M1389.845,733.625 C1389.679,748.281 1389.512,762.937 1389.345,777.593 C1391.543,777.615 1393.741,777.635 1395.939,777.656 C1394.387,779.219 1392.835,780.781 1391.283,782.344 C1411.991,803.052 1432.7,823.76 1453.408,844.469 C1468.814,829.062 1484.221,813.656 1499.627,798.25 C1478.918,777.531 1458.21,756.812 1437.502,736.094 C1435.773,737.833 1434.043,739.573 1432.314,741.312 C1432.335,738.917 1432.356,736.521 1432.377,734.125 C1418.2,733.958 1404.023,733.792 1389.846,733.625 z" fill="#FFFFFF"/>
|
||||
<path d="M1389.845,733.625 C1389.679,748.281 1389.512,762.937 1389.345,777.593 C1391.543,777.615 1393.741,777.635 1395.939,777.656 C1394.387,779.219 1392.835,780.781 1391.283,782.344 C1411.991,803.052 1432.7,823.76 1453.408,844.469 C1468.814,829.062 1484.221,813.656 1499.627,798.25 C1478.918,777.531 1458.21,756.812 1437.502,736.094 C1435.773,737.833 1434.043,739.573 1432.314,741.312 C1432.335,738.917 1432.356,736.521 1432.377,734.125 C1418.2,733.958 1404.023,733.792 1389.846,733.625 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="9" stroke-linecap="round"/>
|
||||
</g>
|
||||
<path d="M606.483,964.91 L606.483,951.243 L672.089,951.243 L672.089,964.91 z" fill="#B3B3B3" id="rect2995-0-2-8-6"/>
|
||||
<g id="rect3075-11-7">
|
||||
<path d="M786.383,905.075 C786.256,916.229 786.129,927.383 786.003,938.537 C787.675,938.553 789.348,938.568 791.021,938.584 C789.839,939.773 788.658,940.963 787.477,942.152 C803.237,957.911 818.997,973.671 834.756,989.431 C846.481,977.706 858.206,965.982 869.93,954.257 C854.171,938.489 838.411,922.722 822.651,906.954 C821.335,908.278 820.019,909.602 818.703,910.926 C818.719,909.102 818.734,907.279 818.751,905.456 C807.961,905.329 797.172,905.202 786.383,905.075 z" fill="#FFFFFF"/>
|
||||
<path d="M786.383,905.075 C786.256,916.229 786.129,927.383 786.003,938.537 C787.675,938.553 789.348,938.568 791.021,938.584 C789.839,939.773 788.658,940.963 787.477,942.152 C803.237,957.911 818.997,973.671 834.756,989.431 C846.481,977.706 858.206,965.982 869.93,954.257 C854.171,938.489 838.411,922.722 822.651,906.954 C821.335,908.278 820.019,909.602 818.703,910.926 C818.719,909.102 818.734,907.279 818.751,905.456 C807.961,905.329 797.172,905.202 786.383,905.075 z" fill-opacity="0" stroke="#FFFFFF" stroke-width="6.849" stroke-linecap="round"/>
|
||||
<path d="M1396.666,740.606 C1396.539,751.76 1396.412,762.914 1396.286,774.068 C1397.958,774.084 1399.631,774.099 1401.304,774.115 C1400.122,775.304 1398.941,776.494 1397.76,777.683 C1413.52,793.442 1429.28,809.202 1445.039,824.962 C1456.764,813.237 1468.489,801.513 1480.213,789.788 C1464.454,774.02 1448.694,758.253 1432.934,742.485 C1431.618,743.809 1430.302,745.133 1428.986,746.457 C1429.002,744.633 1429.017,742.81 1429.034,740.987 C1418.244,740.86 1407.455,740.733 1396.666,740.606 z" fill="#FFFFFF"/>
|
||||
<path d="M1396.666,740.606 C1396.539,751.76 1396.412,762.914 1396.286,774.068 C1397.958,774.084 1399.631,774.099 1401.304,774.115 C1400.122,775.304 1398.941,776.494 1397.76,777.683 C1413.52,793.442 1429.28,809.202 1445.039,824.962 C1456.764,813.237 1468.489,801.513 1480.213,789.788 C1464.454,774.02 1448.694,758.253 1432.934,742.485 C1431.618,743.809 1430.302,745.133 1428.986,746.457 C1429.002,744.633 1429.017,742.81 1429.034,740.987 C1418.244,740.86 1407.455,740.733 1396.666,740.606 z" fill-opacity="0" stroke="#FFFFFF" stroke-width="6.849" stroke-linecap="round"/>
|
||||
</g>
|
||||
<g id="path3100-2">
|
||||
<path d="M813.748,916.688 C818.255,921.195 818.255,928.501 813.748,933.008 C809.242,937.514 801.935,937.514 797.429,933.008 C792.922,928.501 792.922,921.195 797.429,916.688 C801.935,912.182 809.242,912.182 813.748,916.688 z" fill="#FFFFFF"/>
|
||||
<path d="M813.748,916.688 C818.255,921.195 818.255,928.501 813.748,933.008 C809.242,937.514 801.935,937.514 797.429,933.008 C792.922,928.501 792.922,921.195 797.429,916.688 C801.935,912.182 809.242,912.182 813.748,916.688 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="7.585" stroke-linecap="round"/>
|
||||
<path d="M1424.031,752.219 C1428.538,756.726 1428.538,764.032 1424.031,768.539 C1419.525,773.045 1412.218,773.045 1407.712,768.539 C1403.205,764.032 1403.205,756.726 1407.712,752.219 C1412.218,747.713 1419.525,747.713 1424.031,752.219 z" fill="#FFFFFF"/>
|
||||
<path d="M1424.031,752.219 C1428.538,756.726 1428.538,764.032 1424.031,768.539 C1419.525,773.045 1412.218,773.045 1407.712,768.539 C1403.205,764.032 1403.205,756.726 1407.712,752.219 C1412.218,747.713 1419.525,747.713 1424.031,752.219 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="7.585" stroke-linecap="round"/>
|
||||
</g>
|
||||
<g id="rect4114">
|
||||
<path d="M813.845,955.107 L834.888,934.064 L864.012,963.188 L842.969,984.231 z" fill="#FFFFFF"/>
|
||||
<path d="M813.845,955.107 L834.888,934.064 L864.012,963.188 L842.969,984.231 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="7.133"/>
|
||||
<path d="M1424.128,790.638 L1445.171,769.595 L1474.295,798.719 L1453.252,819.762 z" fill="#FFFFFF"/>
|
||||
<path d="M1424.128,790.638 L1445.171,769.595 L1474.295,798.719 L1453.252,819.762 z" fill-opacity="0" stroke="#B3B3B3" stroke-width="7.133"/>
|
||||
</g>
|
||||
<g id="path2991-7-6">
|
||||
<path d="M969.889,84.636 C969.889,122.652 939.072,153.469 901.056,153.469 C863.04,153.469 832.223,122.652 832.223,84.636 C832.223,46.62 863.04,15.803 901.056,15.803 C939.072,15.803 969.889,46.62 969.889,84.636 z" fill="#A0A0A0"/>
|
||||
@@ -750,5 +750,45 @@
|
||||
</g>
|
||||
<path d="M1396.792,592.168 C1426.908,592.168 1450.613,610.989 1450.613,639.54" fill-opacity="0" stroke="#A0A0A0" stroke-width="20" stroke-linecap="round"/>
|
||||
<path d="M1397.792,545.653 C1453.613,544.493 1499.627,588.735 1499.627,636.54" fill-opacity="0" stroke="#A0A0A0" stroke-width="20" stroke-linecap="round"/>
|
||||
<path d="M871.125,1039.025 C871.125,1039.025 873.794,1016.889 908.043,1011.524 C919.748,1009.691 945.861,1005.107 945.861,978.522" fill-opacity="0" stroke="#A0A0A0" stroke-width="17.059" id="path3207"/>
|
||||
<g id="rect3818-4-8-4">
|
||||
<path d="M869.474,950.497 L871.997,950.497 L871.997,1031.308 L869.474,1031.308 z" fill="#A0A0A0"/>
|
||||
<g>
|
||||
<path d="M869.474,950.497 L871.997,950.497 L871.997,1031.308 L869.474,1031.308 z" fill="#A0A0A0"/>
|
||||
<path d="M869.474,950.497 L871.997,950.497 L871.997,1031.308 L869.474,1031.308 z" fill-opacity="0" stroke="#A0A0A0" stroke-width="15"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="path3795-4-8-7-8">
|
||||
<path d="M888.074,1051.656 C888.074,1060.906 880.5,1068.405 871.159,1068.405 C861.817,1068.405 854.243,1060.906 854.243,1051.656 C854.243,1042.406 861.817,1034.908 871.159,1034.908 C880.5,1034.908 888.074,1042.406 888.074,1051.656 z" fill="#FFFFFF"/>
|
||||
<path d="M888.074,1051.656 C888.074,1060.906 880.5,1068.405 871.159,1068.405 C861.817,1068.405 854.243,1060.906 854.243,1051.656 C854.243,1042.406 861.817,1034.908 871.159,1034.908 C880.5,1034.908 888.074,1042.406 888.074,1051.656 z" fill-opacity="0" stroke="#A0A0A0" stroke-width="7.989"/>
|
||||
</g>
|
||||
<g id="path3795-8-4-8">
|
||||
<path d="M886.883,935.155 C886.883,944.404 879.31,951.903 869.968,951.903 C860.626,951.903 853.054,944.404 853.054,935.155 C853.054,925.904 860.626,918.405 869.968,918.405 C879.31,918.405 886.883,925.904 886.883,935.155 z" fill="#FFFFFF"/>
|
||||
<path d="M886.883,935.155 C886.883,944.404 879.31,951.903 869.968,951.903 C860.626,951.903 853.054,944.404 853.054,935.155 C853.054,925.904 860.626,918.405 869.968,918.405 C879.31,918.405 886.883,925.904 886.883,935.155 z" fill-opacity="0" stroke="#A0A0A0" stroke-width="7.989"/>
|
||||
</g>
|
||||
<g id="path3795-8-4-8-2">
|
||||
<path d="M965.046,971.602 C965.046,980.852 957.472,988.351 948.13,988.351 C938.789,988.351 931.215,980.852 931.215,971.602 C931.215,962.352 938.789,954.854 948.13,954.854 C957.472,954.854 965.046,962.352 965.046,971.602 z" fill="#FFFFFF"/>
|
||||
<path d="M965.046,971.602 C965.046,980.852 957.472,988.351 948.13,988.351 C938.789,988.351 931.215,980.852 931.215,971.602 C931.215,962.352 938.789,954.854 948.13,954.854 C957.472,954.854 965.046,962.352 965.046,971.602 z" fill-opacity="0" stroke="#A0A0A0" stroke-width="7.989"/>
|
||||
</g>
|
||||
<path d="M1114.353,1042.412 C1114.353,1042.412 1117.022,1020.275 1151.271,1014.91 C1162.976,1013.077 1189.089,1008.493 1189.089,981.909" fill-opacity="0" stroke="#000000" stroke-width="17.059" id="path3207"/>
|
||||
<g id="rect3818-4-8-4">
|
||||
<path d="M1112.701,953.884 L1115.225,953.884 L1115.225,1034.695 L1112.701,1034.695 z" fill="#A0A0A0"/>
|
||||
<g>
|
||||
<path d="M1112.701,953.884 L1115.225,953.884 L1115.225,1034.695 L1112.701,1034.695 z" fill="#A0A0A0"/>
|
||||
<path d="M1112.701,953.884 L1115.225,953.884 L1115.225,1034.695 L1112.701,1034.695 z" fill-opacity="0" stroke="#000000" stroke-width="15"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="path3795-4-8-7-8">
|
||||
<path d="M1131.302,1055.043 C1131.302,1064.293 1123.728,1071.791 1114.386,1071.791 C1105.045,1071.791 1097.471,1064.293 1097.471,1055.043 C1097.471,1045.792 1105.045,1038.294 1114.386,1038.294 C1123.728,1038.294 1131.302,1045.792 1131.302,1055.043 z" fill="#FFFFFF"/>
|
||||
<path d="M1131.302,1055.043 C1131.302,1064.293 1123.728,1071.791 1114.386,1071.791 C1105.045,1071.791 1097.471,1064.293 1097.471,1055.043 C1097.471,1045.792 1105.045,1038.294 1114.386,1038.294 C1123.728,1038.294 1131.302,1045.792 1131.302,1055.043 z" fill-opacity="0" stroke="#000000" stroke-width="7.989"/>
|
||||
</g>
|
||||
<g id="path3795-8-4-8">
|
||||
<path d="M1130.111,938.542 C1130.111,947.791 1122.537,955.29 1113.196,955.29 C1103.854,955.29 1096.282,947.791 1096.282,938.542 C1096.282,929.291 1103.854,921.792 1113.196,921.792 C1122.537,921.792 1130.111,929.291 1130.111,938.542 z" fill="#FFFFFF"/>
|
||||
<path d="M1130.111,938.542 C1130.111,947.791 1122.537,955.29 1113.196,955.29 C1103.854,955.29 1096.282,947.791 1096.282,938.542 C1096.282,929.291 1103.854,921.792 1113.196,921.792 C1122.537,921.792 1130.111,929.291 1130.111,938.542 z" fill-opacity="0" stroke="#000000" stroke-width="7.989"/>
|
||||
</g>
|
||||
<g id="path3795-8-4-8-2">
|
||||
<path d="M1208.274,974.989 C1208.274,984.239 1200.7,991.738 1191.358,991.738 C1182.016,991.738 1174.443,984.239 1174.443,974.989 C1174.443,965.739 1182.016,958.241 1191.358,958.241 C1200.7,958.241 1208.274,965.739 1208.274,974.989 z" fill="#FFFFFF"/>
|
||||
<path d="M1208.274,974.989 C1208.274,984.239 1200.7,991.738 1191.358,991.738 C1182.016,991.738 1174.443,984.239 1174.443,974.989 C1174.443,965.739 1182.016,958.241 1191.358,958.241 C1200.7,958.241 1208.274,965.739 1208.274,974.989 z" fill-opacity="0" stroke="#000000" stroke-width="7.989"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 82 KiB |
@@ -6,6 +6,17 @@ Update version number
|
||||
|
||||
Note to update version number in files below:
|
||||
|
||||
### project/build.scala
|
||||
|
||||
```scala
|
||||
object MyBuild extends Build {
|
||||
val Organization = "gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val Version = "3.3.0" // <---- update version!!
|
||||
val ScalaVersion = "2.11.6"
|
||||
val ScalatraVersion = "2.3.1"
|
||||
```
|
||||
|
||||
### src/main/scala/gitbucket/core/servlet/AutoUpdate.scala
|
||||
|
||||
```scala
|
||||
@@ -19,13 +30,6 @@ object AutoUpdate {
|
||||
new Version(3, 2),
|
||||
```
|
||||
|
||||
### env.sh
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
export GITBUCKET_VERSION=3.3.0 # <---- update here!!
|
||||
```
|
||||
|
||||
Generate release files
|
||||
--------
|
||||
|
||||
|
||||
3
env.sh
@@ -1,2 +1,3 @@
|
||||
#!/bin/sh
|
||||
export GITBUCKET_VERSION=3.4.0
|
||||
export GITBUCKET_VERSION=`cat project/build.scala | grep 'val Version' | cut -d \" -f 2`
|
||||
echo "GITBUCKET_VERSION: $GITBUCKET_VERSION"
|
||||
|
||||
@@ -10,7 +10,7 @@ import sbtassembly.AssemblyKeys._
|
||||
object MyBuild extends Build {
|
||||
val Organization = "gitbucket"
|
||||
val Name = "gitbucket"
|
||||
val Version = System.getenv("GITBUCKET_VERSION")
|
||||
val Version = "3.5.0"
|
||||
val ScalaVersion = "2.11.6"
|
||||
val ScalatraVersion = "2.3.1"
|
||||
|
||||
@@ -50,7 +50,7 @@ object MyBuild extends Build {
|
||||
"org.json4s" %% "json4s-jackson" % "3.2.11",
|
||||
"jp.sf.amateras" %% "scalatra-forms" % "0.1.0",
|
||||
"commons-io" % "commons-io" % "2.4",
|
||||
"org.pegdown" % "pegdown" % "1.4.1", // 1.4.2 has incompatible APi changes
|
||||
"org.pegdown" % "pegdown" % "1.5.0",
|
||||
"org.apache.commons" % "commons-compress" % "1.9",
|
||||
"org.apache.commons" % "commons-email" % "1.3.3",
|
||||
"org.apache.httpcomponents" % "httpclient" % "4.3.6",
|
||||
@@ -64,9 +64,8 @@ object MyBuild extends Build {
|
||||
"junit" % "junit" % "4.12" % "test",
|
||||
"com.mchange" % "c3p0" % "0.9.5",
|
||||
"com.typesafe" % "config" % "1.2.1",
|
||||
"com.typesafe.play" %% "twirl-compiler" % "1.0.4",
|
||||
"com.typesafe.akka" %% "akka-actor" % "2.3.10",
|
||||
"com.enragedginger" %% "akka-quartz-scheduler" % "1.3.0-akka-2.3.x"
|
||||
"com.enragedginger" %% "akka-quartz-scheduler" % "1.3.0-akka-2.3.x" exclude("c3p0","c3p0")
|
||||
),
|
||||
play.twirl.sbt.Import.TwirlKeys.templateImports += "gitbucket.core._",
|
||||
EclipseKeys.withSource := true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
source ../env.sh
|
||||
. ../env.sh
|
||||
|
||||
cd ../
|
||||
./sbt.sh clean assembly
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
#!/bin/sh
|
||||
source ../env.sh
|
||||
ant -f build.xml all
|
||||
D="$(dirname "$0")"
|
||||
D="$(cd "${D}"; pwd)"
|
||||
DD="$(dirname "${D}")"
|
||||
(
|
||||
for f in "${DD}/env.sh" "${D}/build.xml"; do
|
||||
if [ ! -s "${f}" ]; then
|
||||
echo >&2 "$0: Unable to access file '${f}'"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
cd "${DD}"
|
||||
. "${DD}/env.sh"
|
||||
ant -f "${D}/build.xml" all
|
||||
)
|
||||
|
||||
17
release/pom.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>jp.sf.amateras</groupId>
|
||||
<artifactId>gitbucket-assembly</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<build>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-ssh</artifactId>
|
||||
<version>1.0-beta-6</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
</build>
|
||||
</project>
|
||||
1
sbt.sh
@@ -1,3 +1,2 @@
|
||||
#!/bin/sh
|
||||
source ./env.sh
|
||||
java -Dsbt.log.noformat=true -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -jar `dirname $0`/sbt-launch-0.13.8.jar "$@"
|
||||
|
||||
@@ -91,7 +91,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
val newRepositoryForm = mapping(
|
||||
"owner" -> trim(label("Owner" , text(required, maxlength(40), identifier, existsAccount))),
|
||||
"name" -> trim(label("Repository name", text(required, maxlength(40), identifier, uniqueRepository))),
|
||||
"name" -> trim(label("Repository name", text(required, maxlength(40), repository, uniqueRepository))),
|
||||
"description" -> trim(label("Description" , optional(text()))),
|
||||
"isPrivate" -> trim(label("Repository Type", boolean())),
|
||||
"createReadme" -> trim(label("Create README" , boolean()))
|
||||
@@ -467,6 +467,14 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
parentUserName = Some(repository.owner)
|
||||
)
|
||||
|
||||
// Add collaborators for group repository
|
||||
val ownerAccount = getAccountByUserName(accountName).get
|
||||
if(ownerAccount.isGroupAccount){
|
||||
getGroupMembers(accountName).foreach { member =>
|
||||
addCollaborator(accountName, repository.name, member.userName)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert default labels
|
||||
insertDefaultLabels(accountName, repository.name)
|
||||
|
||||
|
||||
@@ -436,10 +436,16 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
* Displays branches.
|
||||
*/
|
||||
get("/:owner/:repository/branches")(referrersOnly { repository =>
|
||||
val branches = JGitUtil.getBranches(repository.owner, repository.name, repository.repository.defaultBranch)
|
||||
.sortBy(br => (br.mergeInfo.isEmpty, br.commitTime))
|
||||
.map(br => br -> getPullRequestByRequestCommit(repository.owner, repository.name, repository.repository.defaultBranch, br.name, br.commitId))
|
||||
.reverse
|
||||
val branches = JGitUtil.getBranches(
|
||||
owner = repository.owner,
|
||||
name = repository.name,
|
||||
defaultBranch = repository.repository.defaultBranch,
|
||||
origin = repository.repository.originUserName.isEmpty
|
||||
)
|
||||
.sortBy(br => (br.mergeInfo.isEmpty, br.commitTime))
|
||||
.map(br => br -> getPullRequestByRequestCommit(repository.owner, repository.name, repository.repository.defaultBranch, br.name, br.commitId))
|
||||
.reverse
|
||||
|
||||
html.branches(branches, hasWritePermission(repository.owner, repository.name, context.loginAccount), repository)
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package gitbucket.core.plugin
|
||||
|
||||
import gitbucket.core.model.Session
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
|
||||
/**
|
||||
* Define the Git repository routing.
|
||||
*
|
||||
* @param urlPattern the regular expression which matches the repository path (e.g. "gist/(.+?)/(.+?)\\.git")
|
||||
* @param localPath the string to assemble local file path of repository (e.g. "gist/$1/$2")
|
||||
* @param filter the filter for request to the Git repository which is defined by this routing
|
||||
*/
|
||||
case class GitRepositoryRouting(urlPattern: String, localPath: String, filter: GitRepositoryFilter){
|
||||
|
||||
def this(urlPattern: String, localPath: String) = {
|
||||
this(urlPattern, localPath, new GitRepositoryFilter(){
|
||||
def filter(repositoryName: String, userName: Option[String], settings: SystemSettings, isUpdating: Boolean)
|
||||
(implicit session: Session): Boolean = true
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters request to plug-in served repository. This is used to provide authentication mainly.
|
||||
*/
|
||||
trait GitRepositoryFilter {
|
||||
|
||||
/**
|
||||
* Filters request to Git repository. If this method returns true then request is accepted.
|
||||
*
|
||||
* @param path the repository path which starts with '/'
|
||||
* @param userName the authenticated user name or None
|
||||
* @param settings the system settings
|
||||
* @param isUpdating true if update request, otherwise false
|
||||
* @param session the database session
|
||||
* @return true if allow accessing to repository, otherwise false.
|
||||
*/
|
||||
def filter(path: String, userName: Option[String], settings: SystemSettings, isUpdating: Boolean)
|
||||
(implicit session: Session): Boolean
|
||||
|
||||
}
|
||||
@@ -22,38 +22,71 @@ trait Plugin {
|
||||
*/
|
||||
val images: Seq[(String, Array[Byte])] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides images.
|
||||
*/
|
||||
def images(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(String, Array[Byte])] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides controllers.
|
||||
*/
|
||||
val controllers: Seq[(String, ControllerBase)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides controllers.
|
||||
*/
|
||||
def controllers(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(String, ControllerBase)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides JavaScript.
|
||||
*/
|
||||
val javaScripts: Seq[(String, String)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides JavaScript.
|
||||
*/
|
||||
def javaScripts(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(String, String)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides renderers.
|
||||
*/
|
||||
val renderers: Seq[(String, Renderer)] = Nil
|
||||
|
||||
/**
|
||||
* Override to declare this plug-in provides renderers.
|
||||
*/
|
||||
def renderers(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(String, Renderer)] = Nil
|
||||
|
||||
/**
|
||||
* Override to add git repository routings.
|
||||
*/
|
||||
val repositoryRoutings: Seq[GitRepositoryRouting] = Nil
|
||||
|
||||
/**
|
||||
* Override to add git repository routings.
|
||||
*/
|
||||
def repositoryRoutings(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[GitRepositoryRouting] = Nil
|
||||
|
||||
/**
|
||||
* This method is invoked in initialization of plugin system.
|
||||
* Register plugin functionality to PluginRegistry.
|
||||
*/
|
||||
def initialize(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit = {
|
||||
images.foreach { case (id, in) =>
|
||||
(images ++ images(registry, context, settings)).foreach { case (id, in) =>
|
||||
registry.addImage(id, in)
|
||||
}
|
||||
controllers.foreach { case (path, controller) =>
|
||||
(controllers ++ controllers(registry, context, settings)).foreach { case (path, controller) =>
|
||||
registry.addController(path, controller)
|
||||
}
|
||||
javaScripts.foreach { case (path, script) =>
|
||||
(javaScripts ++ javaScripts(registry, context, settings)).foreach { case (path, script) =>
|
||||
registry.addJavaScript(path, script)
|
||||
}
|
||||
renderers.foreach { case (extension, renderer) =>
|
||||
(renderers ++ renderers(registry, context, settings)).foreach { case (extension, renderer) =>
|
||||
registry.addRenderer(extension, renderer)
|
||||
}
|
||||
(repositoryRoutings ++ repositoryRoutings(registry, context, settings)).foreach { routing =>
|
||||
registry.addRepositoryRouting(routing)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ class PluginRegistry {
|
||||
renderers ++= Seq(
|
||||
"md" -> MarkdownRenderer, "markdown" -> MarkdownRenderer
|
||||
)
|
||||
private val repositoryRoutings = new ListBuffer[GitRepositoryRouting]
|
||||
|
||||
def addPlugin(pluginInfo: PluginInfo): Unit = {
|
||||
plugins += pluginInfo
|
||||
@@ -61,7 +62,7 @@ class PluginRegistry {
|
||||
addController(path, controller)
|
||||
}
|
||||
|
||||
def getControllers(): List[(ControllerBase, String)] = controllers.toList
|
||||
def getControllers(): Seq[(ControllerBase, String)] = controllers.toSeq
|
||||
|
||||
def addJavaScript(path: String, script: String): Unit = {
|
||||
javaScripts += ((path, script))
|
||||
@@ -81,6 +82,22 @@ class PluginRegistry {
|
||||
|
||||
def renderableExtensions: Seq[String] = renderers.keys.toSeq
|
||||
|
||||
def addRepositoryRouting(routing: GitRepositoryRouting): Unit = {
|
||||
repositoryRoutings += routing
|
||||
}
|
||||
|
||||
def getRepositoryRoutings(): Seq[GitRepositoryRouting] = {
|
||||
repositoryRoutings.toSeq
|
||||
}
|
||||
|
||||
def getRepositoryRouting(repositoryPath: String): Option[GitRepositoryRouting] = {
|
||||
PluginRegistry().getRepositoryRoutings().find {
|
||||
case GitRepositoryRouting(urlPath, _, _) => {
|
||||
repositoryPath.matches("/" + urlPath + "(/.*)?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private case class GlobalAction(
|
||||
method: String,
|
||||
path: String,
|
||||
|
||||
@@ -20,7 +20,7 @@ trait Renderer {
|
||||
object MarkdownRenderer extends Renderer {
|
||||
override def render(request: RenderRequest): Html = {
|
||||
import request._
|
||||
Html(Markdown.toHtml(fileContent, repository, enableWikiLink, enableRefsLink)(context))
|
||||
Html(Markdown.toHtml(fileContent, repository, enableWikiLink, enableRefsLink, enableAnchor)(context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,5 @@ case class RenderRequest(filePath: List[String],
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
enableWikiLink: Boolean,
|
||||
enableRefsLink: Boolean,
|
||||
enableAnchor: Boolean,
|
||||
context: Context)
|
||||
@@ -33,7 +33,7 @@ class AccessTokenAuthenticationFilter extends Filter with AccessTokenService {
|
||||
case None => chain.doFilter(req, res)
|
||||
case Some(Left(_)) => {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
response.setContentType("Content-Type: application/json; charset=utf-8")
|
||||
response.setContentType("application/json; charset=utf-8")
|
||||
val w = response.getWriter()
|
||||
w.print("""{ "message": "Bad credentials" }""")
|
||||
w.close()
|
||||
|
||||
@@ -21,6 +21,7 @@ object AutoUpdate {
|
||||
* The history of versions. A head of this sequence is the current BitBucket version.
|
||||
*/
|
||||
val versions = Seq(
|
||||
new Version(3, 5),
|
||||
new Version(3, 4),
|
||||
new Version(3, 3),
|
||||
new Version(3, 2),
|
||||
@@ -166,4 +167,4 @@ object AutoUpdate {
|
||||
} else Version(0, 0)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package gitbucket.core.servlet
|
||||
|
||||
import javax.servlet._
|
||||
import javax.servlet.http._
|
||||
import gitbucket.core.plugin.{GitRepositoryFilter, GitRepositoryRouting, PluginRegistry}
|
||||
import gitbucket.core.service.SystemSettingsService.SystemSettings
|
||||
import gitbucket.core.service.{RepositoryService, AccountService, SystemSettingsService}
|
||||
import gitbucket.core.util.{ControlUtil, Keys, Implicits}
|
||||
import gitbucket.core.util.{Keys, Implicits}
|
||||
import org.slf4j.LoggerFactory
|
||||
import Implicits._
|
||||
import ControlUtil._
|
||||
|
||||
/**
|
||||
* Provides BASIC Authentication for [[GitRepositoryServlet]].
|
||||
@@ -20,7 +21,7 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou
|
||||
def destroy(): Unit = {}
|
||||
|
||||
def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
|
||||
implicit val request = req.asInstanceOf[HttpServletRequest]
|
||||
val request = req.asInstanceOf[HttpServletRequest]
|
||||
val response = res.asInstanceOf[HttpServletResponse]
|
||||
|
||||
val wrappedResponse = new HttpServletResponseWrapper(response){
|
||||
@@ -31,47 +32,13 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou
|
||||
val settings = loadSystemSettings()
|
||||
|
||||
try {
|
||||
defining(request.paths){
|
||||
case Array(_, repositoryOwner, repositoryName, _*) =>
|
||||
getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match {
|
||||
case Some(repository) => {
|
||||
if(!isUpdating && !repository.repository.isPrivate && settings.allowAnonymousAccess){
|
||||
chain.doFilter(req, wrappedResponse)
|
||||
} else {
|
||||
request.getHeader("Authorization") match {
|
||||
case null => requireAuth(response)
|
||||
case auth => decodeAuthHeader(auth).split(":", 2) match {
|
||||
case Array(username, password) => {
|
||||
authenticate(settings, username, password) match {
|
||||
case Some(account) => {
|
||||
if (isUpdating || repository.repository.isPrivate) {
|
||||
if(hasWritePermission(repository.owner, repository.name, Some(account))){
|
||||
request.setAttribute(Keys.Request.UserName, account.userName)
|
||||
chain.doFilter(req, wrappedResponse)
|
||||
} else {
|
||||
requireAuth(response)
|
||||
}
|
||||
} else {
|
||||
chain.doFilter(req, wrappedResponse)
|
||||
}
|
||||
}
|
||||
case _ => requireAuth(response)
|
||||
}
|
||||
}
|
||||
case _ => requireAuth(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case None => {
|
||||
logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
case _ => {
|
||||
logger.debug(s"Not enough path arguments: ${request.paths}")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
PluginRegistry().getRepositoryRouting(request.gitRepositoryPath).map { case GitRepositoryRouting(_, _, filter) =>
|
||||
// served by plug-ins
|
||||
pluginRepository(request, wrappedResponse, chain, settings, isUpdating, filter)
|
||||
|
||||
}.getOrElse {
|
||||
// default repositories
|
||||
defaultRepository(request, wrappedResponse, chain, settings, isUpdating)
|
||||
}
|
||||
} catch {
|
||||
case ex: Exception => {
|
||||
@@ -81,6 +48,67 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou
|
||||
}
|
||||
}
|
||||
|
||||
private def pluginRepository(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain,
|
||||
settings: SystemSettings, isUpdating: Boolean, filter: GitRepositoryFilter): Unit = {
|
||||
implicit val r = request
|
||||
|
||||
val account = for {
|
||||
auth <- Option(request.getHeader("Authorization"))
|
||||
Array(username, password) = decodeAuthHeader(auth).split(":", 2)
|
||||
account <- authenticate(settings, username, password)
|
||||
} yield {
|
||||
request.setAttribute(Keys.Request.UserName, account.userName)
|
||||
account
|
||||
}
|
||||
|
||||
if(filter.filter(request.gitRepositoryPath, account.map(_.userName), settings, isUpdating)){
|
||||
chain.doFilter(request, response)
|
||||
} else {
|
||||
requireAuth(response)
|
||||
}
|
||||
}
|
||||
|
||||
private def defaultRepository(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain,
|
||||
settings: SystemSettings, isUpdating: Boolean): Unit = {
|
||||
implicit val r = request
|
||||
|
||||
request.paths match {
|
||||
case Array(_, repositoryOwner, repositoryName, _*) =>
|
||||
getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match {
|
||||
case Some(repository) => {
|
||||
if(!isUpdating && !repository.repository.isPrivate && settings.allowAnonymousAccess){
|
||||
chain.doFilter(request, response)
|
||||
} else {
|
||||
val passed = for {
|
||||
auth <- Option(request.getHeader("Authorization"))
|
||||
Array(username, password) = decodeAuthHeader(auth).split(":", 2)
|
||||
account <- authenticate(settings, username, password)
|
||||
} yield if(isUpdating || repository.repository.isPrivate){
|
||||
if(hasWritePermission(repository.owner, repository.name, Some(account))){
|
||||
request.setAttribute(Keys.Request.UserName, account.userName)
|
||||
true
|
||||
} else false
|
||||
} else true
|
||||
|
||||
if(passed.getOrElse(false)){
|
||||
chain.doFilter(request, response)
|
||||
} else {
|
||||
requireAuth(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
case None => {
|
||||
logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
case _ => {
|
||||
logger.debug(s"Not enough path arguments: ${request.paths}")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def requireAuth(response: HttpServletResponse): Unit = {
|
||||
response.setHeader("WWW-Authenticate", "BASIC realm=\"GitBucket\"")
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package gitbucket.core.servlet
|
||||
|
||||
import java.io.File
|
||||
|
||||
import gitbucket.core.api
|
||||
import gitbucket.core.model.Session
|
||||
import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry}
|
||||
import gitbucket.core.service.IssuesService.IssueSearchCondition
|
||||
import gitbucket.core.service.WebHookService._
|
||||
import gitbucket.core.service._
|
||||
@@ -18,7 +21,6 @@ import org.eclipse.jgit.transport.resolver._
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import javax.servlet.ServletConfig
|
||||
import javax.servlet.ServletContext
|
||||
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
|
||||
|
||||
|
||||
@@ -35,20 +37,8 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
override def init(config: ServletConfig): Unit = {
|
||||
setReceivePackFactory(new GitBucketReceivePackFactory())
|
||||
|
||||
// TODO are there any other ways...?
|
||||
super.init(new ServletConfig(){
|
||||
def getInitParameter(name: String): String = name match {
|
||||
case "base-path" => Directory.RepositoryHome
|
||||
case "export-all" => "true"
|
||||
case name => config.getInitParameter(name)
|
||||
}
|
||||
def getInitParameterNames(): java.util.Enumeration[String] = {
|
||||
config.getInitParameterNames
|
||||
}
|
||||
|
||||
def getServletContext(): ServletContext = config.getServletContext
|
||||
def getServletName(): String = config.getServletName
|
||||
})
|
||||
val root: File = new File(Directory.RepositoryHome)
|
||||
setRepositoryResolver(new GitBucketRepositoryResolver(new FileResolver[HttpServletRequest](root, true)))
|
||||
|
||||
super.init(config)
|
||||
}
|
||||
@@ -67,32 +57,52 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
}
|
||||
}
|
||||
|
||||
class GitBucketRepositoryResolver(parent: FileResolver[HttpServletRequest]) extends RepositoryResolver[HttpServletRequest] {
|
||||
|
||||
private val resolver = new FileResolver[HttpServletRequest](new File(Directory.GitBucketHome), true)
|
||||
|
||||
override def open(req: HttpServletRequest, name: String): Repository = {
|
||||
// Rewrite repository path if routing is marched
|
||||
PluginRegistry().getRepositoryRouting("/" + name).map { case GitRepositoryRouting(urlPattern, localPath, _) =>
|
||||
val path = urlPattern.r.replaceFirstIn(name, localPath)
|
||||
resolver.open(req, path)
|
||||
}.getOrElse {
|
||||
parent.open(req, name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GitBucketReceivePackFactory extends ReceivePackFactory[HttpServletRequest] with SystemSettingsService {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[GitBucketReceivePackFactory])
|
||||
|
||||
override def create(request: HttpServletRequest, db: Repository): ReceivePack = {
|
||||
val receivePack = new ReceivePack(db)
|
||||
val pusher = request.getAttribute(Keys.Request.UserName).asInstanceOf[String]
|
||||
|
||||
logger.debug("requestURI: " + request.getRequestURI)
|
||||
logger.debug("pusher:" + pusher)
|
||||
if(PluginRegistry().getRepositoryRouting(request.gitRepositoryPath).isEmpty){
|
||||
val pusher = request.getAttribute(Keys.Request.UserName).asInstanceOf[String]
|
||||
|
||||
defining(request.paths){ paths =>
|
||||
val owner = paths(1)
|
||||
val repository = paths(2).stripSuffix(".git")
|
||||
logger.debug("requestURI: " + request.getRequestURI)
|
||||
logger.debug("pusher:" + pusher)
|
||||
|
||||
logger.debug("repository:" + owner + "/" + repository)
|
||||
defining(request.paths){ paths =>
|
||||
val owner = paths(1)
|
||||
val repository = paths(2).stripSuffix(".git")
|
||||
|
||||
if(!repository.endsWith(".wiki")){
|
||||
defining(request) { implicit r =>
|
||||
val hook = new CommitLogHook(owner, repository, pusher, baseUrl)
|
||||
receivePack.setPreReceiveHook(hook)
|
||||
receivePack.setPostReceiveHook(hook)
|
||||
logger.debug("repository:" + owner + "/" + repository)
|
||||
|
||||
if(!repository.endsWith(".wiki")){
|
||||
defining(request) { implicit r =>
|
||||
val hook = new CommitLogHook(owner, repository, pusher, baseUrl)
|
||||
receivePack.setPreReceiveHook(hook)
|
||||
receivePack.setPostReceiveHook(hook)
|
||||
}
|
||||
}
|
||||
}
|
||||
receivePack
|
||||
}
|
||||
|
||||
receivePack
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package gitbucket.core.ssh
|
||||
|
||||
import gitbucket.core.model.Session
|
||||
import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry}
|
||||
import gitbucket.core.service.{RepositoryService, AccountService, SystemSettingsService}
|
||||
import gitbucket.core.servlet.{Database, CommitLogHook}
|
||||
import gitbucket.core.util.{Directory, ControlUtil}
|
||||
import org.apache.sshd.server.{CommandFactory, Environment, ExitCallback, Command}
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.{InputStream, OutputStream}
|
||||
import java.io.{File, InputStream, OutputStream}
|
||||
import ControlUtil._
|
||||
import org.eclipse.jgit.api.Git
|
||||
import Directory._
|
||||
@@ -15,11 +16,11 @@ import org.apache.sshd.server.command.UnknownCommand
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException
|
||||
|
||||
object GitCommand {
|
||||
val CommandRegex = """\Agit-(upload|receive)-pack '/([a-zA-Z0-9\-_.]+)/([a-zA-Z0-9\-_.]+).git'\Z""".r
|
||||
val DefaultCommandRegex = """\Agit-(upload|receive)-pack '/([a-zA-Z0-9\-_.]+)/([a-zA-Z0-9\-_.]+).git'\Z""".r
|
||||
val SimpleCommandRegex = """\Agit-(upload|receive)-pack '/(.+\.git)'\Z""".r
|
||||
}
|
||||
|
||||
abstract class GitCommand(val owner: String, val repoName: String) extends Command {
|
||||
self: RepositoryService with AccountService =>
|
||||
abstract class GitCommand() extends Command {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[GitCommand])
|
||||
protected var err: OutputStream = null
|
||||
@@ -71,6 +72,11 @@ abstract class GitCommand(val owner: String, val repoName: String) extends Comma
|
||||
this.in = in
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class DefaultGitCommand(val owner: String, val repoName: String) extends GitCommand {
|
||||
self: RepositoryService with AccountService =>
|
||||
|
||||
protected def isWritableUser(username: String, repositoryInfo: RepositoryService.RepositoryInfo)
|
||||
(implicit session: Session): Boolean =
|
||||
getAccountByUserName(username) match {
|
||||
@@ -80,7 +86,8 @@ abstract class GitCommand(val owner: String, val repoName: String) extends Comma
|
||||
|
||||
}
|
||||
|
||||
class GitUploadPack(owner: String, repoName: String, baseUrl: String) extends GitCommand(owner, repoName)
|
||||
|
||||
class DefaultGitUploadPack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName)
|
||||
with RepositoryService with AccountService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
@@ -94,11 +101,10 @@ class GitUploadPack(owner: String, repoName: String, baseUrl: String) extends Gi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GitReceivePack(owner: String, repoName: String, baseUrl: String) extends GitCommand(owner, repoName)
|
||||
with SystemSettingsService with RepositoryService with AccountService {
|
||||
class DefaultGitReceivePack(owner: String, repoName: String, baseUrl: String) extends DefaultGitCommand(owner, repoName)
|
||||
with RepositoryService with AccountService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
getRepository(owner, repoName.replaceFirst("\\.wiki\\Z", ""), baseUrl).foreach { repositoryInfo =>
|
||||
@@ -116,18 +122,56 @@ class GitReceivePack(owner: String, repoName: String, baseUrl: String) extends G
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PluginGitUploadPack(repoName: String, baseUrl: String, routing: GitRepositoryRouting) extends GitCommand
|
||||
with SystemSettingsService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
if(routing.filter.filter("/" + repoName, Some(user), loadSystemSettings(), false)){
|
||||
val path = routing.urlPattern.r.replaceFirstIn(repoName, routing.localPath)
|
||||
using(Git.open(new File(Directory.GitBucketHome, path))){ git =>
|
||||
val repository = git.getRepository
|
||||
val upload = new UploadPack(repository)
|
||||
upload.upload(in, out, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PluginGitReceivePack(repoName: String, baseUrl: String, routing: GitRepositoryRouting) extends GitCommand
|
||||
with SystemSettingsService {
|
||||
|
||||
override protected def runTask(user: String)(implicit session: Session): Unit = {
|
||||
if(routing.filter.filter("/" + repoName, Some(user), loadSystemSettings(), true)){
|
||||
val path = routing.urlPattern.r.replaceFirstIn(repoName, routing.localPath)
|
||||
using(Git.open(new File(Directory.GitBucketHome, path))){ git =>
|
||||
val repository = git.getRepository
|
||||
val receive = new ReceivePack(repository)
|
||||
receive.receive(in, out, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class GitCommandFactory(baseUrl: String) extends CommandFactory {
|
||||
private val logger = LoggerFactory.getLogger(classOf[GitCommandFactory])
|
||||
|
||||
override def createCommand(command: String): Command = {
|
||||
import GitCommand._
|
||||
logger.debug(s"command: $command")
|
||||
|
||||
command match {
|
||||
case GitCommand.CommandRegex("upload", owner, repoName) => new GitUploadPack(owner, repoName, baseUrl)
|
||||
case GitCommand.CommandRegex("receive", owner, repoName) => new GitReceivePack(owner, repoName, baseUrl)
|
||||
case SimpleCommandRegex ("upload" , repoName) if(pluginRepository(repoName)) => new PluginGitUploadPack (repoName, baseUrl, routing(repoName))
|
||||
case SimpleCommandRegex ("receive", repoName) if(pluginRepository(repoName)) => new PluginGitReceivePack(repoName, baseUrl, routing(repoName))
|
||||
case DefaultCommandRegex("upload" , owner, repoName) => new DefaultGitUploadPack (owner, repoName, baseUrl)
|
||||
case DefaultCommandRegex("receive", owner, repoName) => new DefaultGitReceivePack(owner, repoName, baseUrl)
|
||||
case _ => new UnknownCommand(command)
|
||||
}
|
||||
}
|
||||
|
||||
private def pluginRepository(repoName: String): Boolean = PluginRegistry().getRepositoryRouting("/" + repoName).isDefined
|
||||
private def routing(repoName: String): GitRepositoryRouting = PluginRegistry().getRepositoryRouting("/" + repoName).get
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ object Implicits {
|
||||
|
||||
def hasAttribute(name: String): Boolean = request.getAttribute(name) != null
|
||||
|
||||
def gitRepositoryPath: String = request.getRequestURI.replaceFirst("^/git/", "/")
|
||||
|
||||
}
|
||||
|
||||
implicit class RichSession(session: HttpSession){
|
||||
|
||||
@@ -791,7 +791,7 @@ object JGitUtil {
|
||||
return git.log.add(startCommit).addPath(path).setMaxCount(1).call.iterator.next
|
||||
}
|
||||
|
||||
def getBranches(owner: String, name: String, defaultBranch: String): Seq[BranchInfo] = {
|
||||
def getBranches(owner: String, name: String, defaultBranch: String, origin: Boolean): Seq[BranchInfo] = {
|
||||
using(Git.open(getRepositoryDir(owner, name))){ git =>
|
||||
val repo = git.getRepository
|
||||
val defaultObject = if (repo.getAllRefs.keySet().contains(defaultBranch)) {
|
||||
@@ -802,20 +802,20 @@ object JGitUtil {
|
||||
|
||||
git.branchList.call.asScala.map { ref =>
|
||||
val walk = new RevWalk(repo)
|
||||
try{
|
||||
try {
|
||||
val defaultCommit = walk.parseCommit(defaultObject)
|
||||
val branchName = ref.getName.stripPrefix("refs/heads/")
|
||||
val branchCommit = if(branchName == defaultBranch){
|
||||
defaultCommit
|
||||
}else{
|
||||
} else {
|
||||
walk.parseCommit(ref.getObjectId)
|
||||
}
|
||||
val when = branchCommit.getCommitterIdent.getWhen
|
||||
val committer = branchCommit.getCommitterIdent.getName
|
||||
val committerEmail = branchCommit.getCommitterIdent.getEmailAddress
|
||||
val mergeInfo = if(branchName==defaultBranch){
|
||||
val mergeInfo = if(origin && branchName == defaultBranch){
|
||||
None
|
||||
}else{
|
||||
} else {
|
||||
walk.reset()
|
||||
walk.setRevFilter( RevFilter.MERGE_BASE )
|
||||
walk.markStart(branchCommit)
|
||||
|
||||
@@ -75,7 +75,7 @@ class Mailer(private val smtp: Smtp) extends Notifier {
|
||||
database withSession { implicit session =>
|
||||
defining(
|
||||
s"[${r.name}] ${issue.title} (#${issue.issueId})" ->
|
||||
msg(Markdown.toHtml(content, r, false, true))) { case (subject, msg) =>
|
||||
msg(Markdown.toHtml(content, r, false, true, false))) { case (subject, msg) =>
|
||||
recipients(issue) { to =>
|
||||
val email = new HtmlEmail
|
||||
email.setHostName(smtp.host)
|
||||
@@ -87,7 +87,7 @@ class Mailer(private val smtp: Smtp) extends Notifier {
|
||||
email.setSSLOnConnect(ssl)
|
||||
}
|
||||
smtp.fromAddress
|
||||
.map (_ -> smtp.fromName.orNull)
|
||||
.map (_ -> smtp.fromName.getOrElse(context.loginAccount.get.userName))
|
||||
.orElse (Some("notifications@gitbucket.com" -> context.loginAccount.get.userName))
|
||||
.foreach { case (address, name) =>
|
||||
email.setFrom(address, name)
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.scalatra.i18n.Messages
|
||||
trait Validations {
|
||||
|
||||
/**
|
||||
* Constraint for the identifier such as user name, repository name or page name.
|
||||
* Constraint for the identifier such as user name or page name.
|
||||
*/
|
||||
def identifier: Constraint = new Constraint(){
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
@@ -19,6 +19,23 @@ trait Validations {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constraint for the repository identifier.
|
||||
*/
|
||||
def repository: Constraint = new Constraint(){
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||
if(!value.matches("[a-zA-Z0-9\\-\\+_.]+")){
|
||||
Some(s"${name} contains invalid character.")
|
||||
} else if(value.startsWith("_") || value.startsWith("-")){
|
||||
Some(s"${name} starts with invalid character.")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constraint for the color pattern.
|
||||
*/
|
||||
def color = pattern("#[0-9a-fA-F]{6}")
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,11 +18,20 @@ object Markdown {
|
||||
|
||||
/**
|
||||
* Converts Markdown of Wiki pages to HTML.
|
||||
*
|
||||
* @param repository the repository which contains the markdown
|
||||
* @param enableWikiLink if true then wiki style link is available in markdown
|
||||
* @param enableRefsLink if true then issue reference (e.g. #123) is rendered as link
|
||||
* @param enableAnchor if true then anchor for headline is generated
|
||||
* @param enableTaskList if true then task list syntax is available
|
||||
* @param hasWritePermission
|
||||
* @param pages the list of existing Wiki pages
|
||||
*/
|
||||
def toHtml(markdown: String,
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
enableWikiLink: Boolean,
|
||||
enableRefsLink: Boolean,
|
||||
enableAnchor: Boolean,
|
||||
enableTaskList: Boolean = false,
|
||||
hasWritePermission: Boolean = false,
|
||||
pages: List[String] = Nil)(implicit context: Context): String = {
|
||||
@@ -38,10 +47,14 @@ object Markdown {
|
||||
} else s
|
||||
|
||||
val rootNode = new PegDownProcessor(
|
||||
Extensions.AUTOLINKS | Extensions.WIKILINKS | Extensions.FENCED_CODE_BLOCKS | Extensions.TABLES | Extensions.HARDWRAPS | Extensions.SUPPRESS_ALL_HTML
|
||||
Extensions.AUTOLINKS | Extensions.WIKILINKS | Extensions.FENCED_CODE_BLOCKS |
|
||||
Extensions.TABLES | Extensions.HARDWRAPS | Extensions.SUPPRESS_ALL_HTML | Extensions.STRIKETHROUGH
|
||||
).parseMarkdown(source.toCharArray)
|
||||
|
||||
new GitBucketHtmlSerializer(markdown, repository, enableWikiLink, enableRefsLink, enableTaskList, hasWritePermission, pages).toHtml(rootNode)
|
||||
new GitBucketHtmlSerializer(
|
||||
markdown, repository, enableWikiLink, enableRefsLink, enableAnchor, enableTaskList,
|
||||
hasWritePermission, pages
|
||||
).toHtml(rootNode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +113,7 @@ class GitBucketHtmlSerializer(
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
enableWikiLink: Boolean,
|
||||
enableRefsLink: Boolean,
|
||||
enableAnchor: Boolean,
|
||||
enableTaskList: Boolean,
|
||||
hasWritePermission: Boolean,
|
||||
pages: List[String]
|
||||
@@ -108,9 +122,9 @@ class GitBucketHtmlSerializer(
|
||||
Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava
|
||||
) with LinkConverter with RequestCache {
|
||||
|
||||
override protected def printImageTag(imageNode: SuperNode, url: String): Unit = {
|
||||
printer.print("<a target=\"_blank\" href=\"").print(fixUrl(url, true)).print("\">")
|
||||
.print("<img src=\"").print(fixUrl(url, true)).print("\" alt=\"").printEncoded(printChildrenToString(imageNode)).print("\"/></a>")
|
||||
override protected def printImageTag(rendering: LinkRenderer.Rendering): Unit = {
|
||||
printer.print("<a target=\"_blank\" href=\"").print(fixUrl(rendering.href, true)).print("\">")
|
||||
.print("<img src=\"").print(fixUrl(rendering.href, true)).print("\" alt=\"").printEncoded(rendering.text).print("\"/></a>")
|
||||
}
|
||||
|
||||
override protected def printLink(rendering: LinkRenderer.Rendering): Unit = {
|
||||
@@ -150,15 +164,34 @@ class GitBucketHtmlSerializer(
|
||||
|
||||
private def printHeaderTag(node: HeaderNode): Unit = {
|
||||
val tag = s"h${node.getLevel}"
|
||||
val headerTextString = printChildrenToString(node)
|
||||
val anchorName = GitBucketHtmlSerializer.generateAnchorName(headerTextString)
|
||||
val child = node.getChildren.asScala.headOption
|
||||
val anchorName = child match {
|
||||
case Some(x: AnchorLinkNode) => x.getName
|
||||
case Some(x: TextNode) => x.getText
|
||||
case _ => GitBucketHtmlSerializer.generateAnchorName(extractText(node)) // TODO
|
||||
}
|
||||
|
||||
printer.print(s"""<$tag class="markdown-head">""")
|
||||
printer.print(s"""<a class="markdown-anchor-link" href="#$anchorName"></a>""")
|
||||
printer.print(s"""<a class="markdown-anchor" name="$anchorName"></a>""")
|
||||
visitChildren(node)
|
||||
if(enableAnchor){
|
||||
printer.print(s"""<a class="markdown-anchor-link" href="#$anchorName"></a>""")
|
||||
printer.print(s"""<a class="markdown-anchor" name="$anchorName"></a>""")
|
||||
}
|
||||
child match {
|
||||
case Some(x: AnchorLinkNode) => printer.print(x.getText)
|
||||
case _ => visitChildren(node)
|
||||
}
|
||||
printer.print(s"</$tag>")
|
||||
}
|
||||
|
||||
private def extractText(node: Node): String = {
|
||||
val sb = new StringBuilder()
|
||||
node.getChildren.asScala.map {
|
||||
case x: TextNode => sb.append(x.getText)
|
||||
case x: Node => sb.append(extractText(x))
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
|
||||
override def visit(node: HeaderNode): Unit = {
|
||||
printHeaderTag(node)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.{Date, Locale, TimeZone}
|
||||
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.CommitState
|
||||
import gitbucket.core.plugin.{RenderRequest, PluginRegistry, Renderer}
|
||||
import gitbucket.core.plugin.{RenderRequest, PluginRegistry}
|
||||
import gitbucket.core.service.{RepositoryService, RequestCache}
|
||||
import gitbucket.core.util.{FileUtil, JGitUtil, StringUtil}
|
||||
|
||||
@@ -91,16 +91,16 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
enableTaskList: Boolean = false,
|
||||
hasWritePermission: Boolean = false,
|
||||
pages: List[String] = Nil)(implicit context: Context): Html =
|
||||
Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink, enableTaskList, hasWritePermission, pages))
|
||||
Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink, enableTaskList, true, hasWritePermission, pages))
|
||||
|
||||
def renderMarkup(filePath: List[String], fileContent: String, branch: String,
|
||||
repository: RepositoryService.RepositoryInfo,
|
||||
enableWikiLink: Boolean, enableRefsLink: Boolean)(implicit context: Context): Html = {
|
||||
enableWikiLink: Boolean, enableRefsLink: Boolean, enableAnchor: Boolean)(implicit context: Context): Html = {
|
||||
|
||||
val fileName = filePath.reverse.head.toLowerCase
|
||||
val extension = FileUtil.getExtension(fileName)
|
||||
val renderer = PluginRegistry().getRenderer(extension)
|
||||
renderer.render(RenderRequest(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, context))
|
||||
renderer.render(RenderRequest(filePath, fileContent, branch, repository, enableWikiLink, enableRefsLink, enableAnchor, context))
|
||||
}
|
||||
|
||||
def isRenderable(fileName: String): Boolean = {
|
||||
@@ -155,6 +155,11 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
.replaceAll("\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]", (m: Match) => s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m.group(2)}@${m.group(3).substring(0, 7)}</a>""")
|
||||
)
|
||||
|
||||
/**
|
||||
* Remove html tags from the given Html instance.
|
||||
*/
|
||||
def removeHtml(html: Html): Html = Html(html.body.replaceAll("<.+?>", ""))
|
||||
|
||||
/**
|
||||
* URL encode except '/'.
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ isCreateRepoOptionPublic: Boolean)(implicit context: gitbucket.core.controller.C
|
||||
<fieldset class="margin">
|
||||
<label class="radio">
|
||||
<input type="radio" name="isPrivate" value="false" @if(isCreateRepoOptionPublic){checked}>
|
||||
<span class="strong"><img src="@assets/common/images/repo_public.png"/> </i> Public</span><br>
|
||||
<span class="strong"><i class="octicon octicon-repo"></i> </i> Public</span><br>
|
||||
<div>
|
||||
<span>All users and guests can read this repository.</span>
|
||||
</div>
|
||||
@@ -40,7 +40,7 @@ isCreateRepoOptionPublic: Boolean)(implicit context: gitbucket.core.controller.C
|
||||
<fieldset>
|
||||
<label class="radio">
|
||||
<input type="radio" name="isPrivate" value="true" @if(!isCreateRepoOptionPublic){checked}>
|
||||
<span class="strong"><img src="@assets/common/images/repo_private.png"/> </i> Private</span><br>
|
||||
<span class="strong"><i class="icon-lock"></i> </i> Private</span><br>
|
||||
<div>
|
||||
<span>Only collaborators can read this repository.</span>
|
||||
</div>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
@import gitbucket.core.view.helpers._
|
||||
<span class="small">
|
||||
<a class="button-link@if(condition.state == "open"){ selected}" href="@condition.copy(state = "open").toURL">
|
||||
<img src="@assets/common/images/status-open@(if(condition.state == "open"){"-active"}).png"/>
|
||||
<i class="octicon octicon-issue-opened @(if(condition.state == "open"){"active"})"></i>
|
||||
@openCount Open
|
||||
</a>
|
||||
<a class="button-link@if(condition.state == "closed"){ selected}" href="@condition.copy(state = "closed").toURL">
|
||||
<img src="@assets/common/images/status-closed@(if(condition.state == "closed"){"-active"}).png"/>
|
||||
<i class="octicon octicon-check @(if(condition.state == "closed"){"active"})"></i>
|
||||
@closedCount Closed
|
||||
</a>
|
||||
</span>
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
<tr>
|
||||
<td style="padding-top: 15px; padding-bottom: 15px;">
|
||||
@if(issue.isPullRequest){
|
||||
<img src="@assets/common/images/pullreq-@(if(issue.closed) "closed" else "open").png"/>
|
||||
<i class="octicon octicon-git-pull-request @(if(issue.closed) "closed" else "open")"></i>
|
||||
} else {
|
||||
<img src="@assets/common/images/issue-@(if(issue.closed) "closed" else "open").png"/>
|
||||
<i class="octicon octicon-issue-@(if(issue.closed) "closed" else "opened")"></i>
|
||||
}
|
||||
<a href="@path/@issue.userName/@issue.repositoryName">@issue.userName/@issue.repositoryName</a> ・
|
||||
@if(issue.isPullRequest){
|
||||
@@ -39,18 +39,19 @@
|
||||
}
|
||||
@if(commentCount > 0){
|
||||
<a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count">
|
||||
<img src="@assets/common/images/comment-active.png"> @commentCount
|
||||
<i class="octicon octicon-comment active"></i> @commentCount
|
||||
</a>
|
||||
} else {
|
||||
<a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count" style="color: silver;">
|
||||
<img src="@assets/common/images/comment.png"> @commentCount
|
||||
<i class="octicon octicon-comment"></i> @commentCount
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
<div class="small muted" style="margin-left: 20px; margin-top: 5px;">
|
||||
#@issue.issueId opened by @user(issue.openedUserName, styleClass="username") @datetime(issue.registeredDate)
|
||||
@milestone.map { milestone =>
|
||||
<span style="margin: 20px;"><a href="@condition.copy(milestone = Some(Some(milestone))).toURL" class="username"><img src="@assets/common/images/milestone.png"> @milestone</a></span>
|
||||
<span style="margin: 20px;"><a href="@condition.copy(milestone = Some(Some(milestone))).toURL" class="username"><i class="octicon octicon-milestone"></i>
|
||||
@milestone</a></span>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
<div class="dashboard-nav">
|
||||
<div class="container">
|
||||
<a href="@path/" @if(active == ""){ class="active"}>
|
||||
<img src="@assets/common/images/menu-feed.png">
|
||||
<i class="octicon octicon-rss"></i>
|
||||
News Feed
|
||||
</a>
|
||||
@if(loginAccount.isDefined){
|
||||
<a href="@path/dashboard/pulls" @if(active == "pulls" ){ class="active"}>
|
||||
<img src="@assets/common/images/menu-pulls.png">
|
||||
<i class="octicon octicon-git-pull-request"></i>
|
||||
Pull Requests
|
||||
</a>
|
||||
<a href="@path/dashboard/issues" @if(active == "issues"){ class="active"}>
|
||||
<img src="@assets/common/images/menu-issues.png">
|
||||
<i class="octicon octicon-issue-opened"></i>
|
||||
Issues
|
||||
</a>
|
||||
}
|
||||
@@ -27,6 +27,8 @@ div.dashboard-nav {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.dashboard-nav a {
|
||||
line-height: 10px;
|
||||
margin-left: 20px;
|
||||
@@ -36,8 +38,17 @@ div.dashboard-nav a {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
div.dashboard-nav a:hover {
|
||||
|
||||
div.dashboard-nav .octicon{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 16px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
div.dashboard-nav a:hover,div.dashboard-nav a:hover .octicon {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
div.dashboard-nav a.active {
|
||||
|
||||
@@ -8,20 +8,20 @@
|
||||
@activities.map { activity =>
|
||||
<div class="block">
|
||||
@(activity.activityType match {
|
||||
case "open_issue" => detailActivity(activity, "activity-issue.png")
|
||||
case "comment_issue" => detailActivity(activity, "activity-comment.png")
|
||||
case "comment_commit" => detailActivity(activity, "activity-comment.png")
|
||||
case "close_issue" => detailActivity(activity, "activity-issue-close.png")
|
||||
case "reopen_issue" => detailActivity(activity, "activity-issue-reopen.png")
|
||||
case "open_pullreq" => detailActivity(activity, "activity-merge.png")
|
||||
case "merge_pullreq" => detailActivity(activity, "activity-merge.png")
|
||||
case "create_repository" => simpleActivity(activity, "activity-create-repository.png")
|
||||
case "create_branch" => simpleActivity(activity, "activity-branch.png")
|
||||
case "delete_branch" => simpleActivity(activity, "activity-delete.png")
|
||||
case "create_tag" => simpleActivity(activity, "activity-tag.png")
|
||||
case "delete_tag" => simpleActivity(activity, "activity-delete.png")
|
||||
case "fork" => simpleActivity(activity, "activity-fork.png")
|
||||
case "push" => customActivity(activity, "activity-commit.png"){
|
||||
case "open_issue" => detailActivity(activity, "issue-opened")
|
||||
case "comment_issue" => detailActivity(activity, "comment-discussion")
|
||||
case "comment_commit" => detailActivity(activity, "comment-discussion")
|
||||
case "close_issue" => detailActivity(activity, "issue-closed")
|
||||
case "reopen_issue" => detailActivity(activity, "issue-reopened")
|
||||
case "open_pullreq" => detailActivity(activity, "git-pull-request")
|
||||
case "merge_pullreq" => detailActivity(activity, "git-merge")
|
||||
case "create_repository" => simpleActivity(activity, "repo")
|
||||
case "create_branch" => simpleActivity(activity, "git-branch")
|
||||
case "delete_branch" => simpleActivity(activity, "circle-slash")
|
||||
case "create_tag" => simpleActivity(activity, "tag")
|
||||
case "delete_tag" => simpleActivity(activity, "circle-slash")
|
||||
case "fork" => simpleActivity(activity, "repo-forked")
|
||||
case "push" => customActivity(activity, "git-commit"){
|
||||
<div class="small activity-message">
|
||||
{activity.additionalInfo.get.split("\n").reverse.take(4).zipWithIndex.map{ case (commit, i) =>
|
||||
if(i == 3){
|
||||
@@ -37,12 +37,12 @@
|
||||
}}
|
||||
</div>
|
||||
}
|
||||
case "create_wiki" => customActivity(activity, "activity-wiki.png"){
|
||||
case "create_wiki" => customActivity(activity, "book"){
|
||||
<div class="small activity-message">
|
||||
Created <a href={s"${path}/${activity.userName}/${activity.repositoryName}/wiki/${activity.additionalInfo.get}"}>{activity.additionalInfo.get}</a>.
|
||||
</div>
|
||||
}
|
||||
case "edit_wiki" => customActivity(activity, "activity-wiki.png"){
|
||||
case "edit_wiki" => customActivity(activity, "book"){
|
||||
activity.additionalInfo.get.split(":") match {
|
||||
case Array(pageName, commitId) =>
|
||||
<div class="small activity-message">
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
@detailActivity(activity: gitbucket.core.model.Activity, image: String) = {
|
||||
<div class="activity-icon-large"><img src="@assets/common/images/@image"/></div>
|
||||
<div class="activity-icon-large"><i class="mega-octicon octicon-@image"></i></div>
|
||||
<div class="activity-content">
|
||||
<div class="muted small">@helper.html.datetimeago(activity.activityDate)</div>
|
||||
<div class="strong">
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
|
||||
@customActivity(activity: gitbucket.core.model.Activity, image: String)(additionalInfo: Any) = {
|
||||
<div class="activity-icon-large"><img src="@assets/common/images/@image"/></div>
|
||||
<div class="activity-icon-large"><i class="mega-octicon octicon-@image"></i></div>
|
||||
<div class="activity-content">
|
||||
<div class="muted small">@helper.html.datetimeago(activity.activityDate)</div>
|
||||
<div class="strong">
|
||||
@@ -87,7 +87,7 @@
|
||||
}
|
||||
|
||||
@simpleActivity(activity: gitbucket.core.model.Activity, image: String) = {
|
||||
<div class="activity-icon-small"><img src="@assets/common/images/@image"/></div>
|
||||
<div class="activity-icon-small"><i class="octicon octicon-@image"></i></div>
|
||||
<div class="activity-content">
|
||||
<div>
|
||||
@avatar(activity.activityUserName, 16)
|
||||
|
||||
@@ -25,16 +25,16 @@
|
||||
<span class="pull-right diffstat" data-diff-id="@i"></span>
|
||||
<a href="#diff-@i">
|
||||
@if(diff.changeType == ChangeType.COPY || diff.changeType == ChangeType.RENAME){
|
||||
<img src="@assets/common/images/diff_move.png"/> @diff.oldPath -> @diff.newPath
|
||||
<i class="octicon octicon-diff-renamed"></i> @diff.oldPath -> @diff.newPath
|
||||
}
|
||||
@if(diff.changeType == ChangeType.ADD){
|
||||
<img src="@assets/common/images/diff_add.png"/> @diff.newPath
|
||||
<i class="octicon octicon-diff-added"></i> @diff.newPath
|
||||
}
|
||||
@if(diff.changeType == ChangeType.MODIFY){
|
||||
<img src="@assets/common/images/diff_edit.png"/> @diff.newPath
|
||||
<i class="octicon octicon-diff-modified"></i> @diff.newPath
|
||||
}
|
||||
@if(diff.changeType == ChangeType.DELETE){
|
||||
<img src="@assets/common/images/diff_delete.png"/> @diff.oldPath
|
||||
<i class="octicon octicon-diff-removed"></i> @diff.oldPath
|
||||
}
|
||||
</a>
|
||||
</li>
|
||||
@@ -55,7 +55,7 @@
|
||||
</div>
|
||||
}
|
||||
<span class="diffstat">
|
||||
<img src="@assets/common/images/diff_move.png"/>
|
||||
<i class="octicon octicon-diff-renamed"></i>
|
||||
</span> @diff.oldPath -> @diff.newPath
|
||||
}
|
||||
@if(diff.changeType == ChangeType.ADD || diff.changeType == ChangeType.MODIFY){
|
||||
@@ -68,9 +68,9 @@
|
||||
}
|
||||
<span class="diffstat">
|
||||
@if(diff.changeType == ChangeType.ADD){
|
||||
<img src="@assets/common/images/diff_add.png"/>
|
||||
<i class="octicon octicon-diff-added"></i>
|
||||
}else{
|
||||
<img src="@assets/common/images/diff_edit.png"/>
|
||||
<i class="octicon octicon-diff-modified"></i>
|
||||
}
|
||||
</span>
|
||||
@diff.newPath
|
||||
@@ -83,7 +83,7 @@
|
||||
</div>
|
||||
}
|
||||
<span class="diffstat">
|
||||
<img src="@assets/common/images/diff_delete.png"/>
|
||||
<i class="octicon octicon-diff-removed"></i>
|
||||
</span> @diff.oldPath
|
||||
}
|
||||
</th>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<published>@datetimeRFC3339(activity.activityDate)</published>
|
||||
<updated>@datetimeRFC3339(activity.activityDate)</updated>
|
||||
<link type="text/html" rel="alternate" href="@context.baseUrl/@activity.userName/@activity.repositoryName" />
|
||||
<title type="html">@activity.activityType</title>
|
||||
<title type="html">@removeHtml(activityMessage(activity.message))</title>
|
||||
<author>
|
||||
<name>@activity.activityUserName</name>
|
||||
<uri>@url(activity.activityUserName)</uri>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
enableTaskList: Boolean,
|
||||
hasWritePermission: Boolean,
|
||||
style: String = "",
|
||||
styleClass: String = "",
|
||||
placeholder: String = "Leave a comment",
|
||||
elastic: Boolean = false,
|
||||
uid: Long = new java.util.Date().getTime())(implicit context: gitbucket.core.controller.Context)
|
||||
@@ -20,7 +21,9 @@
|
||||
<div class="tab-pane active" id="tab@uid">
|
||||
<span id="error-content" class="error"></span>
|
||||
@textarea = {
|
||||
<textarea id="content@uid" name="content"@if(style.nonEmpty){ style="@style"} placeholder="@placeholder">@content</textarea>
|
||||
<textarea id="content@uid" name="content" placeholder="@placeholder"
|
||||
@if(style.nonEmpty){ style="@style"}
|
||||
@if(styleClass.nonEmpty){ class="@styleClass" }>@content</textarea>
|
||||
}
|
||||
@if(enableWikiLink){
|
||||
@textarea
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
@if(repository.repository.isPrivate){
|
||||
<img src="@assets/common/images/repo_private@{if(large){"_lg"}}.png"/>
|
||||
<i class="@{if(large){"mega-"}}octicon octicon-lock"></i>
|
||||
} else {
|
||||
@if(repository.repository.originUserName.isDefined){
|
||||
<img src="@assets/common/images/repo_fork@{if(large){"_lg"}}.png"/>
|
||||
<i class="@{if(large){"mega-"}}octicon octicon-repo-forked"></i>
|
||||
} else {
|
||||
<img src="@assets/common/images/repo_public@{if(large){"_lg"}}.png"/>
|
||||
<i class="@{if(large){"mega-"}}octicon octicon-repo"></i>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,16 @@
|
||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||
<div class="box issue-comment-box">
|
||||
<div class="box-content">
|
||||
@helper.html.preview(repository, "", false, true, true, hasWritePermission, "width: 635px; height: 100px; max-height: 150px;", elastic = true)
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission,
|
||||
style = "width: 635px; height: 100px; max-height: 150px;",
|
||||
elastic = true
|
||||
)
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="small" style="padding-left: 20px;">
|
||||
@milestone.dueDate.map { dueDate =>
|
||||
@if(isPast(dueDate)){
|
||||
<img src="@assets/common/images/alert.png"/><span class="milestone-alert">Due by @date(dueDate)</span>
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="milestone-alert">Due by @date(dueDate)</span>
|
||||
} else {
|
||||
<span class="muted">Due by @date(dueDate)</span>
|
||||
}
|
||||
@@ -57,7 +57,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@helper.html.preview(repository, "", false, true, true, hasWritePermission, "width: 565px; height: 200px; max-height: 250px;", elastic = true)
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission,
|
||||
style = "width: 565px; height: 200px; max-height: 250px;",
|
||||
elastic = true
|
||||
)
|
||||
</div>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<div class="small" style="padding-left: 20px;">
|
||||
@milestone.dueDate.map { dueDate =>
|
||||
@if(isPast(dueDate)){
|
||||
<img src="@assets/common/images/alert.png"/><span class="milestone-alert">Due by @date(dueDate)</span>
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="milestone-alert">Due by @date(dueDate)</span>
|
||||
} else {
|
||||
<span class="muted">Due by @date(dueDate)</span>
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div style="margin-top: 6px">
|
||||
<a href="@url(repository)/issues?labels=@urlEncode(label.labelName)" id="label-row-content-@label.labelId">
|
||||
<span style="background-color: #@label.color; color: #@label.fontColor; padding: 8px; font-size: 120%; border-radius: 4px;">
|
||||
<img src="@assets/common/images/label_@(if(label.fontColor == "ffffff") "white" else "black").png" style="width: 12px;"/>
|
||||
<i class="octicon octicon-tag" style="color: #@label.fontColor;"></i>
|
||||
@label.labelName
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
@if(condition.nonEmpty){
|
||||
<div>
|
||||
<a href="@gitbucket.core.service.IssuesService.IssueSearchCondition().toURL" class="header-link">
|
||||
<img src="@assets/common/images/clear.png" class="header-icon"/>
|
||||
<img src="@assets/common/images/clear_hover.png" class="header-icon-hover" style="display: none;"/>
|
||||
<i class="octicon octicon-x" ></i>
|
||||
<span class="strong">Clear current search query, filters, and sorts</span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -28,11 +27,11 @@
|
||||
<input type="checkbox"/>
|
||||
<span class="small">
|
||||
<a class="button-link@if(condition.state == "open"){ selected}" href="@condition.copy(state = "open").toURL">
|
||||
<img src="@assets/common/images/status-open@(if(condition.state == "open"){"-active"}).png"/>
|
||||
<i class="octicon octicon-issue-opened @(if(condition.state == "open"){"active"})"></i>
|
||||
@openCount Open
|
||||
</a>
|
||||
<a class="button-link@if(condition.state == "closed"){ selected}" href="@condition.copy(state = "closed").toURL">
|
||||
<img src="@assets/common/images/status-closed@(if(condition.state == "closed"){"-active"}).png"/>
|
||||
<i class="octicon octicon-check @(if(condition.state == "closed"){"active"})"></i>
|
||||
@closedCount Closed
|
||||
</a>
|
||||
</span>
|
||||
@@ -176,7 +175,7 @@
|
||||
@if(hasWritePermission){
|
||||
<input type="checkbox" value="@issue.issueId"/>
|
||||
}
|
||||
<img src="@assets/common/images/issue-@(if(issue.closed) "closed" else "open").png" style="margin-right: 20px;"/>
|
||||
<i class="octicon octicon-issue-@(if(issue.closed) "closed" else "opened")" style="margin-right: 3px;"></i>
|
||||
@if(repository.isEmpty){
|
||||
<a href="@path/@issue.userName/@issue.repositoryName">@issue.repositoryName</a> ・
|
||||
}
|
||||
@@ -195,18 +194,19 @@
|
||||
}
|
||||
@if(commentCount > 0){
|
||||
<a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count">
|
||||
<img src="@assets/common/images/comment-active.png"> @commentCount
|
||||
<i class="octicon octicon-comment active"></i> @commentCount
|
||||
</a>
|
||||
} else {
|
||||
<a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count" style="color: silver;">
|
||||
<img src="@assets/common/images/comment.png"> @commentCount
|
||||
<i class="octicon octicon-comment"></i> @commentCount
|
||||
</a>
|
||||
}
|
||||
</span>
|
||||
<div class="small muted" style="margin-left: 40px; margin-top: 5px;">
|
||||
#@issue.issueId opened @helper.html.datetimeago(issue.registeredDate) by @user(issue.openedUserName, styleClass="username")
|
||||
@milestone.map { milestone =>
|
||||
<span style="margin: 20px;"><a href="@condition.copy(milestone = Some(Some(milestone))).toURL" class="username"><img src="@assets/common/images/milestone.png"> @milestone</a></span>
|
||||
<span style="margin: 20px;"><a href="@condition.copy(milestone = Some(Some(milestone))).toURL" class="username"><i class="octicon octicon-milestone"></i>
|
||||
@milestone</a></span>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
@@ -216,4 +216,3 @@
|
||||
<div class="pull-right">
|
||||
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), gitbucket.core.service.IssuesService.IssueLimit, 10, condition.toURL)
|
||||
</div>
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
<th style="background-color: #eee;">
|
||||
<span class="small">
|
||||
<a class="button-link@if(state == "open"){ selected}" href="?state=open">
|
||||
<img src="@assets/common/images/milestone@(if(state == "open"){"-active"}).png"/>
|
||||
<i class="octicon octicon-milestone @(if(state == "open"){"active"})"></i>
|
||||
@milestones.count(_._1.closedDate.isEmpty) Open
|
||||
</a>
|
||||
<a class="button-link@if(state == "closed"){ selected}" href="?state=closed">
|
||||
<img src="@assets/common/images/milestone@(if(state == "closed"){"-active"}).png"/>
|
||||
<i class="octicon octicon-milestone @(if(state == "closed"){"active"})"></i>
|
||||
@milestones.count(_._1.closedDate.isDefined) Closed
|
||||
</a>
|
||||
</span>
|
||||
@@ -38,7 +38,7 @@
|
||||
} else {
|
||||
@milestone.dueDate.map { dueDate =>
|
||||
@if(isPast(dueDate)){
|
||||
<img src="@assets/common/images/alert.png"/><span class="muted milestone-alert">Due by @date(dueDate)</span>
|
||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="muted milestone-alert">Due by @date(dueDate)</span>
|
||||
} else {
|
||||
<span class="muted">Due by @date(dueDate)</span>
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="@assets/vendors/bootstrap/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="@assets/vendors/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="@assets/vendors/octicons/octicons.css" rel="stylesheet">
|
||||
<link href="@assets/vendors/datepicker/css/datepicker.css" rel="stylesheet">
|
||||
<link href="@assets/vendors/colorpicker/css/bootstrap-colorpicker.css" rel="stylesheet">
|
||||
<link href="@assets/vendors/google-code-prettify/prettify.css" type="text/css" rel="stylesheet"/>
|
||||
@@ -40,7 +41,7 @@
|
||||
<form id="search" action="@path/search" method="POST">
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<div class="container" style="width: 920px;">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@@ -51,27 +52,38 @@
|
||||
@defining(AutoUpdate.getCurrentVersion){ version =>
|
||||
<span class="header-version">@version.majorVersion.@version.minorVersion</span>
|
||||
}
|
||||
|
||||
</a>
|
||||
@repository.map { repository =>
|
||||
<input type="text" name="query" style="width: 200px; margin-top: 5px; margin-bottom: 0px;" placeholder="Search this repository"/>
|
||||
<input type="hidden" name="owner" value="@repository.owner"/>
|
||||
<input type="hidden" name="repository" value="@repository.name"/>
|
||||
}
|
||||
@if(loginAccount.isDefined){
|
||||
<a href="@path/dashboard/pulls" class="global-header-menu">Pull requests</a>
|
||||
<a href="@path/dashboard/issues" class="global-header-menu">Issues</a>
|
||||
}
|
||||
<div class="nav-collapse collapse pull-right header-menu">
|
||||
@repository.map { repository =>
|
||||
<input type="text" name="query" style="width: 300px; margin-bottom: 0px;" placeholder="Search this repository"/>
|
||||
<input type="hidden" name="owner" value="@repository.owner"/>
|
||||
<input type="hidden" name="repository" value="@repository.name"/>
|
||||
}
|
||||
@if(loginAccount.isDefined){
|
||||
<a href="@url(loginAccount.get.userName)" class="username menu">@avatar(loginAccount.get.userName, 20) @loginAccount.get.userName</a>
|
||||
<a class="dropdown-toggle menu" data-toggle="dropdown" href="#"><i class="icon-plus"></i><span class="caret" style="vertical-align: middle;"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="@path/new">New repository</a></li>
|
||||
<li><a href="@path/groups/new">New group</a></li>
|
||||
</ul>
|
||||
<a href="@url(loginAccount.get.userName)/_edit" class="menu" data-toggle="tooltip" data-placement="bottom" title="Account settings"><i class="icon-user" aria-label="Account settings"></i></a>
|
||||
@if(loginAccount.get.isAdmin){
|
||||
<a href="@path/admin/users" class="menu" data-toggle="tooltip" data-placement="bottom" title="Administration"><i class="icon-wrench" aria-label="Administration"></i></a>
|
||||
}
|
||||
<a href="@path/signout" class="menu-last" data-toggle="tooltip" data-placement="bottom" title="Sign out"><i class="icon-share-alt" aria-label="Sign out"></i></a>
|
||||
<div class="btn-group" style="margin-top: 0px;">
|
||||
<a class="dropdown-toggle menu" data-toggle="dropdown" href="#"><i class="octicon octicon-plus" style="font-size: 20px; vertical-align: top; margin-top: 10px;"></i><span class="caret" style="vertical-align: middle;"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="@path/new">New repository</a></li>
|
||||
<li><a href="@path/groups/new">New group</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group" style="margin-top: 0px;">
|
||||
<a class="dropdown-toggle menu" data-toggle="dropdown" href="#" data-toggle="tooltip" data-placement="bottom" title="Signed is as @loginAccount.get.userName">@avatar(loginAccount.get.userName, 16)<span class="caret" style="vertical-align: middle;"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="@url(loginAccount.get.userName)/_edit">Account settings</a></li>
|
||||
@if(loginAccount.get.isAdmin){
|
||||
<li><a href="@path/admin/users">System administration</a></li>
|
||||
}
|
||||
<li><a href="@path/signout">Sign out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
} else {
|
||||
<a href="@path/signin?redirect=@urlEncode(currentPath)" class="btn btn-last" id="signin">Sign in</a>
|
||||
<a href="@path/signin?redirect=@urlEncode(currentPath)" class="btn" id="signin">Sign in</a>
|
||||
}
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
@@ -9,16 +9,11 @@
|
||||
@import context._
|
||||
@import gitbucket.core.view.helpers._
|
||||
|
||||
@sidemenu(path: String, name: String, label: String, count: Int = 0) = {
|
||||
@sidemenu(path: String, name: String, icon: String, label: String, count: Int = 0) = {
|
||||
<li @if(active == name){class="active"} @if(!expand){data-toggle="tooltip" data-placement="left" data-original-title="@label"}>
|
||||
<div class="@if(active == name){margin} else {gradient} pull-left"></div>
|
||||
<a href="@url(repository)@path">
|
||||
@if(active == name){
|
||||
<img src="@assets/common/images/menu-@{name}-active.png">
|
||||
} else {
|
||||
<img src="@assets/common/images/menu-@{name}-active.png" class="menu-icon-active" style="display:none;">
|
||||
<img src="@assets/common/images/menu-@{name}.png" class="menu-icon">
|
||||
}
|
||||
<i class="menu-icon @if(active == name){menu-icon-active} octicon octicon-@{icon} "></i>
|
||||
@if(expand){ @label}
|
||||
@if(expand && count > 0){
|
||||
<div class="pull-right"><span class="label">@count</span></div>
|
||||
@@ -27,13 +22,6 @@
|
||||
</li>
|
||||
}
|
||||
|
||||
@sidemenuPlugin(path: String, name: String, label: String, icon: String) = {
|
||||
<li @if(active == name){class="active"}>
|
||||
<div class="@if(active == name){margin} else {gradient} pull-left"></div>
|
||||
<a href="@url(repository)@path"><img src="@icon"/>@if(expand){ @label}</a>
|
||||
</li>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
@helper.html.information(info)
|
||||
@helper.html.error(error)
|
||||
@@ -41,7 +29,7 @@
|
||||
<div class="pull-right">
|
||||
<div class="input-prepend">
|
||||
@if(loginAccount.isEmpty){
|
||||
<a title="You must be signed in to fork a repository" href="@path/signin" class="btn btn-small" style="margin-bottom: 10px;">Fork</a>
|
||||
<a title="You must be signed in to fork a repository" href="@path/signin?redirect=@urlEncode(s"${path}/${repository.owner}/${repository.name}")" class="btn btn-small" style="margin-bottom: 10px;">Fork</a>
|
||||
} else {
|
||||
@if(isNoGroup) {
|
||||
<a id="fork-link" href="javascript:void(0);" class="btn btn-small" style="margin-bottom: 10px;">Fork</a>
|
||||
@@ -51,12 +39,12 @@
|
||||
}
|
||||
<span class="add-on count"><a href="@url(repository)/network/members">@repository.forkedCount</a></span>
|
||||
</div>
|
||||
@if(loginAccount.isDefined && isNoGroup){
|
||||
<form id="fork-form" method="post" action="@path/@repository.owner/@repository.name/fork">
|
||||
<input type="hidden" name="account" value="@loginAccount.get.userName"/>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
@if(loginAccount.isDefined && isNoGroup){
|
||||
<form id="fork-form" method="post" action="@path/@repository.owner/@repository.name/fork">
|
||||
<input type="hidden" name="account" value="@loginAccount.get.userName"/>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
<div class="head">
|
||||
@helper.html.repositoryicon(repository, true)
|
||||
@@ -76,12 +64,12 @@
|
||||
<div style="width: @if(expand){170px} else {40px};" class="pull-right">
|
||||
<ul class="sidemenu">
|
||||
<li style="height: 12px"><div class="gradient pull-left" style="height: 12px"></div></li>
|
||||
@sidemenu("" , "code" , "Code")
|
||||
@sidemenu("/issues", "issues", "Issues", repository.issueCount)
|
||||
@sidemenu("/pulls" , "pulls" , "Pull Requests", repository.pullCount)
|
||||
@sidemenu("/wiki" , "wiki" , "Wiki")
|
||||
@sidemenu("" , "code" , "code" , "Code")
|
||||
@sidemenu("/issues", "issues" , "issue-opened" , "Issues", repository.issueCount)
|
||||
@sidemenu("/pulls" , "pulls" , "git-pull-request" , "Pull Requests", repository.pullCount)
|
||||
@sidemenu("/wiki" , "wiki" , "book" , "Wiki")
|
||||
@if(loginAccount.isDefined && (loginAccount.get.isAdmin || repository.managers.contains(loginAccount.get.userName))){
|
||||
@sidemenu("/settings", "settings", "Settings")
|
||||
@sidemenu("/settings" , "settings" , "tools", "Settings")
|
||||
}
|
||||
<li style="height: 12px"><div class="gradient pull-left" style="height: 12px"></div></li>
|
||||
</ul>
|
||||
@@ -99,10 +87,10 @@
|
||||
}
|
||||
@id.map { id =>
|
||||
<div style="margin-top: 10px;">
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(id)}.zip" class="btn btn-small" style="width: 147px;"><i class="icon-download-alt"></i>Download ZIP</a>
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(id)}.zip" class="btn btn-small" style="width: 147px;font-weight: bold;"><i class="octicon octicon-cloud-download"></i>Download ZIP</a>
|
||||
</div>
|
||||
<div style="margin-top: 10px;">
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(id)}.tar.gz" class="btn btn-small" style="width: 147px;"><i class="icon-download-alt"></i>Download TAR.GZ</a>
|
||||
<a href="@{url(repository)}/archive/@{encodeRefName(id)}.tar.gz" class="btn btn-small" style="width: 147px;font-weight: bold;"><i class="octicon octicon-cloud-download"></i>Download TAR.GZ</a>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -117,22 +105,19 @@
|
||||
<tr>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/commits/@encodeRefName(id.getOrElse(""))" class="header-link">
|
||||
<img src="@assets/common/images/header-commits-hover.png" class="header-icon-hover" style="display: none;"/>
|
||||
<img src="@assets/common/images/header-commits.png" class="header-icon"/>
|
||||
<i class="octicon octicon-history"></i>
|
||||
<strong>@repository.commitCount</strong> commits
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/branches" class="header-link" class="header-link">
|
||||
<img src="@assets/common/images/header-branches-hover.png" class="header-icon-hover" style="display: none;"/>
|
||||
<img src="@assets/common/images/header-branches.png" class="header-icon"/>
|
||||
<i class="octicon octicon-git-branch"></i>
|
||||
<strong>@repository.branchList.length</strong> branches
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center;">
|
||||
<a href="@url(repository)/tags" class="header-link" class="header-link">
|
||||
<img src="@assets/common/images/header-tags-hover.png" class="header-icon-hover" style="display: none;"/>
|
||||
<img src="@assets/common/images/header-tags.png" class="header-icon"/>
|
||||
<i class="octicon octicon-tag"></i>
|
||||
<strong>@repository.tags.length</strong> releases
|
||||
</a>
|
||||
</td>
|
||||
@@ -145,44 +130,21 @@
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
$('a.header-link').mouseover(function(e){
|
||||
var target = e.target;
|
||||
if(e.target.tagName != 'A'){
|
||||
target = e.target.parentElement;
|
||||
}
|
||||
$(target).children('strong' ).css('color', '#0088cc');
|
||||
$(target).children('img.header-icon-hover').css('display', 'inline');
|
||||
$(target).children('img.header-icon' ).css('display', 'none');
|
||||
});
|
||||
|
||||
$('a.header-link').mouseout(function(e){
|
||||
var target = e.target;
|
||||
if(e.target.tagName != 'A'){
|
||||
target = e.target.parentElement;
|
||||
}
|
||||
$(target).children('strong' ).css('color', 'black');
|
||||
$(target).children('img.header-icon-hover').css('display', 'none');
|
||||
$(target).children('img.header-icon' ).css('display', 'inline');
|
||||
});
|
||||
|
||||
$('ul.sidemenu a').mouseover(function(e){
|
||||
var target = e.target;
|
||||
if(e.target.tagName == "IMG"){
|
||||
if(e.target.tagName == "I"){
|
||||
target = e.target.parentElement;
|
||||
}
|
||||
$(target).prev ('div.gradient' ).css('border-left', '1px solid silver');
|
||||
$(target).children('img.menu-icon-active').css('display', 'inline');
|
||||
$(target).children('img.menu-icon' ).css('display', 'none');
|
||||
});
|
||||
|
||||
$('ul.sidemenu a').mouseout(function(e){
|
||||
var target = e.target;
|
||||
if(e.target.tagName == "IMG"){
|
||||
if(e.target.tagName == "I"){
|
||||
target = e.target.parentElement;
|
||||
}
|
||||
$(target).prev ('div.gradient' ).css('border-left', '1px solid #eee');
|
||||
$(target).children('img.menu-icon-active').css('display', 'none');
|
||||
$(target).children('img.menu-icon' ).css('display', 'inline');
|
||||
});
|
||||
|
||||
$('a[rel*=facebox]').facebox({
|
||||
|
||||
@@ -59,7 +59,15 @@
|
||||
<div style="width: 600px; border-right: 1px solid #d4d4d4;">
|
||||
<span class="error" id="error-title"></span>
|
||||
<input type="text" name="title" style="width: 580px" placeholder="Title"/>
|
||||
@helper.html.preview(repository, "", false, true, true, hasWritePermission, "width: 580px; height: 200px;")
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission,
|
||||
style = "width: 580px; height: 200px;"
|
||||
)
|
||||
<input type="hidden" name="targetUserName" value="@originRepository.owner"/>
|
||||
<input type="hidden" name="targetBranch" value="@originId"/>
|
||||
<input type="hidden" name="requestUserName" value="@forkedRepository.owner"/>
|
||||
@@ -131,7 +139,7 @@ $(function(){
|
||||
}
|
||||
|
||||
@if(hasWritePermission){
|
||||
function checkConflict(from, to, noConflictHandler, hasConflictHandler){
|
||||
function checkConflict(from, to){
|
||||
$('.check-conflict').show();
|
||||
$.get('@url(repository)/compare/' + from + '...' + to + '/mergecheck',
|
||||
function(data){ $('.check-conflict').html(data); });
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
@defining(isRenderable(pathList.reverse.head)){ isRrenderable =>
|
||||
@if(!isBlame && isRrenderable) {
|
||||
<div class="box-content markdown-body" style="border: none; padding-left: 16px; padding-right: 16px;">
|
||||
@renderMarkup(pathList, content.content.get, branch, repository, false, false)
|
||||
@renderMarkup(pathList, content.content.get, branch, repository, false, false, true)
|
||||
</div>
|
||||
} else {
|
||||
<pre class="prettyprint linenums blob @if(!isRrenderable){ no-renderable } ">@content.content.get</pre>
|
||||
|
||||
@@ -30,9 +30,17 @@
|
||||
}
|
||||
}.getOrElse{
|
||||
@if(context.loginAccount.isDefined){
|
||||
<a href="@url(repository)/compare/@{encodeRefName(repository.repository.defaultBranch)}...@{encodeRefName(branch.name)}?expand=1" class="btn btn-small">New Pull Request</a>
|
||||
<a href="@url(repository)/compare/@{repository.repository.parentUserName.map { parent =>
|
||||
urlEncode(parent) + ":" + encodeRefName(repository.repository.defaultBranch)
|
||||
}.getOrElse {
|
||||
encodeRefName(repository.repository.defaultBranch)
|
||||
}}...@{encodeRefName(branch.name)}?expand=1" class="btn btn-small">New Pull Request</a>
|
||||
}else{
|
||||
<a href="@url(repository)/compare/@{encodeRefName(repository.repository.defaultBranch)}...@{encodeRefName(branch.name)}" class="btn btn-small">Compare</a>
|
||||
<a href="@url(repository)/compare/@{repository.repository.parentUserName.map { parent =>
|
||||
urlEncode(parent) + ":" + encodeRefName(repository.repository.defaultBranch)
|
||||
}.getOrElse {
|
||||
encodeRefName(repository.repository.defaultBranch)
|
||||
}}...@{encodeRefName(branch.name)}" class="btn btn-small">Compare</a>
|
||||
}
|
||||
}
|
||||
@if(hasWritePermission){
|
||||
@@ -75,7 +83,7 @@
|
||||
<script>
|
||||
$(function(){
|
||||
$('.delete-branch').click(function(e){
|
||||
var branchName = $(e.target).data('name');
|
||||
var branchName = $(e.target).closest('a').data('name');
|
||||
return confirm('Are you sure you want to remove the ' + branchName + ' branch?');
|
||||
});
|
||||
$('*[data-toggle=tooltip]').tooltip().css("white-space","nowrap");
|
||||
|
||||
@@ -15,7 +15,16 @@
|
||||
}
|
||||
<div class="box issue-comment-box">
|
||||
<div class="box-content">
|
||||
@helper.html.preview(repository, "", false, true, true, hasWritePermission, "width: 635px; height: 100px; max-height: 150px;", elastic = true)
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission,
|
||||
style = "width: 635px; height: 100px; max-height: 150px;",
|
||||
elastic = true
|
||||
)
|
||||
</div>
|
||||
@if(fileName.isDefined){
|
||||
<div class="pull-right" style="margin-top: 10px;">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="small" style="font-weight: normal;">
|
||||
@if(branches.nonEmpty){
|
||||
<span class="muted">
|
||||
<img src="@assets/common/images/branch.png"/>
|
||||
<i class="octicon octicon-git-branch"></i>
|
||||
@branches.zipWithIndex.map { case (branch, i) =>
|
||||
<a href="@url(repository)/tree/@encodeRefName(branch)" class="branch" id="branch-@i">@branch</a>
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
}
|
||||
@if(tags.nonEmpty){
|
||||
<span class="muted">
|
||||
<img src="@assets/common/images/tag.png"/>
|
||||
<i class="octicon octicon-tag"></i>
|
||||
@tags.zipWithIndex.map { case (tag, i) =>
|
||||
<a href="@url(repository)/tree/@tag" class="tag" id="tag-@i">@tag</a>
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<a href="@url(repository)/tree/@encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
|
||||
}
|
||||
@if(hasWritePermission){
|
||||
<a href="@url(repository)/new/@encodeRefName(branch)/@pathList.mkString("/")"><img src="@assets/common/images/newfile.png"/></a>
|
||||
<a href="@url(repository)/new/@encodeRefName(branch)/@pathList.mkString("/")" title="Create a new file here" style="text-decoration: none;">+</i></a>
|
||||
}
|
||||
</div>
|
||||
<table class="table table-file-list">
|
||||
@@ -88,12 +88,12 @@
|
||||
<td width="16">
|
||||
@if(file.isDirectory){
|
||||
@if(file.linkUrl.isDefined){
|
||||
<img src="@assets/common/images/folder_link.png"/>
|
||||
<i class="octicon octicon-file-symlink-directory"></i>
|
||||
} else {
|
||||
<img src="@assets/common/images/folder.png"/>
|
||||
<i class="octicon octicon-file-directory"></i>
|
||||
}
|
||||
} else {
|
||||
<img src="@assets/common/images/file.png"/>
|
||||
<i class="octicon octicon-file-text"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@@ -128,7 +128,7 @@
|
||||
@readme.map { case(filePath, content) =>
|
||||
<div id="readme">
|
||||
<div class="box-header">@filePath.reverse.head</div>
|
||||
<div class="box-content markdown-body">@renderMarkup(filePath, content, branch, repository, false, false)</div>
|
||||
<div class="box-content markdown-body">@renderMarkup(filePath, content, branch, repository, false, false, true)</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,17 @@
|
||||
<form action="@url(repository)/wiki/@if(page.isEmpty){_new} else {_edit}" method="POST" validate="true">
|
||||
<span id="error-pageName" class="error"></span>
|
||||
<input type="text" name="pageName" value="@pageName" style="width: 850px; font-weight: bold;" placeholder="Input a page name."/>
|
||||
@helper.html.preview(repository, page.map(_.content).getOrElse(""), true, false, false, false, "width: 850px; height: 400px;", "")
|
||||
@helper.html.preview(
|
||||
repository = repository,
|
||||
content = page.map(_.content).getOrElse(""),
|
||||
enableWikiLink = true,
|
||||
enableRefsLink = false,
|
||||
enableTaskList = false,
|
||||
hasWritePermission = false,
|
||||
style = "width: 850px; height: 400px;",
|
||||
styleClass = "monospace",
|
||||
placeholder = ""
|
||||
)
|
||||
<input type="text" name="message" value="" style="width: 850px;" placeholder="Write a small message here explaining this change. (Optional)"/>
|
||||
<input type="hidden" name="currentPageName" value="@pageName"/>
|
||||
<input type="hidden" name="id" value="@page.map(_.id)"/>
|
||||
|
||||
@@ -36,7 +36,30 @@ h6 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.octicon,.mega-octicon{
|
||||
color : #999;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
/*font-size: 14px;*/
|
||||
text-align: center;
|
||||
}
|
||||
.mega-octicon{
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.octicon.active,.mega-octicon.active{
|
||||
color : #333;
|
||||
}
|
||||
|
||||
.octicon-cloud-download{
|
||||
color: #333;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.head .octicon,.head .mega-octicon{
|
||||
color : #BBB;
|
||||
}
|
||||
/* ======================================================================== */
|
||||
/* Global Header */
|
||||
/* ======================================================================== */
|
||||
@@ -55,6 +78,10 @@ div.header-menu {
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
div.header-menu .octicon{
|
||||
color: #333;
|
||||
}
|
||||
|
||||
div.header-menu input,
|
||||
div.header-menu a.btn {
|
||||
margin-top: 0px;
|
||||
@@ -73,6 +100,7 @@ div.nav-collapse a.menu-last {
|
||||
.navbar .brand {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.navbar .brand img {
|
||||
@@ -94,12 +122,23 @@ div.input-prepend span.count {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
a.global-header-menu {
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
font-size: 80%;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
line-height: 3.5;
|
||||
}
|
||||
|
||||
/*
|
||||
img.plugin-global-menu {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
*/
|
||||
|
||||
/* ======================================================================== */
|
||||
/* General Styles */
|
||||
@@ -230,6 +269,7 @@ div.box-header-small {
|
||||
background: #f2f8fa;
|
||||
}
|
||||
|
||||
|
||||
div.box-content {
|
||||
background-color: white;
|
||||
border: 1px solid #d8d8d8;
|
||||
@@ -250,6 +290,10 @@ th.box-header {
|
||||
text-shadow: 0 1px 0 #fff
|
||||
}
|
||||
|
||||
th.box-header .octicon {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
th.metal {
|
||||
background-color: #e0e0e0;
|
||||
background-image: -moz-linear-gradient(#fafafa, #e8e8e8);
|
||||
@@ -326,6 +370,10 @@ span.highlight {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dz-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Side Menu */
|
||||
/****************************************************************************/
|
||||
@@ -333,12 +381,6 @@ ul.sidemenu {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
ul.sidemenu img {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
|
||||
ul.sidemenu a:hover{
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -379,6 +421,9 @@ ul.sidemenu span.badge {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
ul.sidemenu a:hover i.menu-icon, ul.sidemenu i.menu-icon-active {
|
||||
color: #333;
|
||||
}
|
||||
/****************************************************************************/
|
||||
/* Create Repository */
|
||||
/****************************************************************************/
|
||||
@@ -545,6 +590,10 @@ div.activity-content {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
div[class^="activity-icon"] i{
|
||||
color: #BBB;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Repository Viewer */
|
||||
/****************************************************************************/
|
||||
@@ -557,9 +606,8 @@ a.header-link {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
a.header-link img {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
a.header-link i.octicon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
a.header-link strong {
|
||||
@@ -568,10 +616,30 @@ a.header-link strong {
|
||||
}
|
||||
|
||||
a.header-link:hover {
|
||||
color: #0088cc;
|
||||
color: #4183c4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.header-link:hover i.octicon, a.header-link:hover strong{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a.header-link i.octicon-x{
|
||||
opacity: 1;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 3px;
|
||||
color: #FFF;
|
||||
line-height: 20px;
|
||||
background-color: #777;
|
||||
border-radius: 3px;
|
||||
}
|
||||
a.header-link:hover i.octicon-x{
|
||||
background-color: #4183c4;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
|
||||
table.blobview {
|
||||
table-layout: fixed;
|
||||
}
|
||||
@@ -776,6 +844,9 @@ a.button-link {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
a.button-link i {
|
||||
color: inherit;
|
||||
}
|
||||
a.selected {
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
@@ -791,6 +862,14 @@ table.table-issues {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
table.table-issues td .octicon-issue-opened,table.table-issues td .octicon-git-pull-request .open {
|
||||
color: #6CC644;
|
||||
}
|
||||
|
||||
table.table-issues td .octicon-issue-closed,table.table-issues td .octicon-git-pull-request .closed{
|
||||
color : #BD2C00;;
|
||||
}
|
||||
|
||||
a.issue-title {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
@@ -1519,13 +1598,15 @@ div.markdown-body table colgroup + tbody tr:first-child td:last-child {
|
||||
|
||||
a.markdown-anchor-link {
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
width: 32px;
|
||||
height: 16px;
|
||||
background-image: url(../images/link.png);
|
||||
background-repeat: no-repeat;
|
||||
left: -18px;
|
||||
display: none;
|
||||
color: #999;
|
||||
/* From octicon style */
|
||||
font: normal normal normal 16px/1 octicons;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
}
|
||||
a.markdown-anchor-link:before { content: '\f05c'} /* */
|
||||
|
||||
h1 a.markdown-anchor-link {
|
||||
top: 24px;
|
||||
|
||||
|
Before Width: | Height: | Size: 300 B |
|
Before Width: | Height: | Size: 390 B |
|
Before Width: | Height: | Size: 514 B |
|
Before Width: | Height: | Size: 318 B |
|
Before Width: | Height: | Size: 419 B |
|
Before Width: | Height: | Size: 308 B |
|
Before Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 834 B |
|
Before Width: | Height: | Size: 776 B |
|
Before Width: | Height: | Size: 581 B |
|
Before Width: | Height: | Size: 301 B |
|
Before Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 185 B |
|
Before Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 349 B |
|
Before Width: | Height: | Size: 95 B |
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 112 B |
|
Before Width: | Height: | Size: 97 B |
|
Before Width: | Height: | Size: 120 B |
|
Before Width: | Height: | Size: 111 B |
|
Before Width: | Height: | Size: 294 B |
|
Before Width: | Height: | Size: 537 B |
|
Before Width: | Height: | Size: 785 B |
|
Before Width: | Height: | Size: 288 B |
|
Before Width: | Height: | Size: 311 B |
|
Before Width: | Height: | Size: 382 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 342 B |
|
Before Width: | Height: | Size: 371 B |
|
Before Width: | Height: | Size: 452 B |
|
Before Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 147 B |
|
Before Width: | Height: | Size: 343 B |
|
Before Width: | Height: | Size: 290 B |
|
Before Width: | Height: | Size: 262 B |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 485 B |
|
Before Width: | Height: | Size: 404 B |
|
Before Width: | Height: | Size: 356 B |
|
Before Width: | Height: | Size: 315 B |
|
Before Width: | Height: | Size: 418 B |
|
Before Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 419 B |
|
Before Width: | Height: | Size: 367 B |