mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-29 23:22:34 +01:00
Updated build and versioning system
Added versioning file instead of using git tags (Step towards removing git as a dependancy in the future) Updated gulpfile to fit with verisioning system and cleaned up node dependancies. Fixes #108
This commit is contained in:
parent
a6c6c6e300
commit
ab468bac3c
3
.gitignore
vendored
3
.gitignore
vendored
@ -11,4 +11,5 @@ Homestead.yaml
|
||||
/storage/images
|
||||
_ide_helper.php
|
||||
/storage/debugbar
|
||||
.phpstorm.meta.php
|
||||
.phpstorm.meta.php
|
||||
yarn.lock
|
||||
|
@ -17,10 +17,7 @@ class SettingController extends Controller
|
||||
$this->setPageTitle('Settings');
|
||||
|
||||
// Get application version
|
||||
$version = false;
|
||||
if (function_exists('exec')) {
|
||||
$version = exec('git describe --always --tags ');
|
||||
}
|
||||
$version = trim(file_get_contents(base_path('version')));
|
||||
|
||||
return view('settings/index', ['version' => $version]);
|
||||
}
|
||||
|
@ -11,29 +11,20 @@ use BookStack\Ownable;
|
||||
*/
|
||||
function versioned_asset($file = '')
|
||||
{
|
||||
// Don't require css and JS assets for testing
|
||||
if (config('app.env') === 'testing') return '';
|
||||
static $version = null;
|
||||
|
||||
static $manifest = null;
|
||||
$manifestPath = 'build/manifest.json';
|
||||
|
||||
if (is_null($manifest) && file_exists($manifestPath)) {
|
||||
$manifest = json_decode(file_get_contents(public_path($manifestPath)), true);
|
||||
} else if (!file_exists($manifestPath)) {
|
||||
if (config('app.env') !== 'production') {
|
||||
$path = public_path($manifestPath);
|
||||
$error = "No {$path} file found, Ensure you have built the css/js assets using gulp.";
|
||||
} else {
|
||||
$error = "No {$manifestPath} file found, Ensure you are using the release version of BookStack";
|
||||
}
|
||||
throw new \Exception($error);
|
||||
if (is_null($version)) {
|
||||
$versionFile = base_path('version');
|
||||
$version = trim(file_get_contents($versionFile));
|
||||
}
|
||||
|
||||
if (isset($manifest[$file])) {
|
||||
return baseUrl($manifest[$file]);
|
||||
$additional = '';
|
||||
if (config('app.env') === 'development') {
|
||||
$additional = sha1_file(public_path($file));
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
|
||||
$path = $file . '?version=' . urlencode($version) . $additional;
|
||||
return baseUrl($path);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,14 +129,14 @@ function sortUrl($path, $data, $overrideData = [])
|
||||
{
|
||||
$queryStringSections = [];
|
||||
$queryData = array_merge($data, $overrideData);
|
||||
|
||||
|
||||
// Change sorting direction is already sorted on current attribute
|
||||
if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) {
|
||||
$queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc';
|
||||
} else {
|
||||
$queryData['order'] = 'asc';
|
||||
}
|
||||
|
||||
|
||||
foreach ($queryData as $name => $value) {
|
||||
$trimmedVal = trim($value);
|
||||
if ($trimmedVal === '') continue;
|
||||
@ -155,4 +146,4 @@ function sortUrl($path, $data, $overrideData = [])
|
||||
if (count($queryStringSections) === 0) return $path;
|
||||
|
||||
return baseUrl($path . '?' . implode('&', $queryStringSections));
|
||||
}
|
||||
}
|
||||
|
29
gulpfile.js
29
gulpfile.js
@ -1,27 +1,8 @@
|
||||
var elixir = require('laravel-elixir');
|
||||
|
||||
// Custom extensions
|
||||
var gulp = require('gulp');
|
||||
var Task = elixir.Task;
|
||||
var fs = require('fs');
|
||||
|
||||
elixir.extend('queryVersion', function(inputFiles) {
|
||||
new Task('queryVersion', function() {
|
||||
var manifestObject = {};
|
||||
var uidString = Date.now().toString(16).slice(4);
|
||||
for (var i = 0; i < inputFiles.length; i++) {
|
||||
var file = inputFiles[i];
|
||||
manifestObject[file] = file + '?version=' + uidString;
|
||||
}
|
||||
var fileContents = JSON.stringify(manifestObject, null, 1);
|
||||
fs.writeFileSync('public/build/manifest.json', fileContents);
|
||||
}).watch(['./public/css/*.css', './public/js/*.js']);
|
||||
});
|
||||
|
||||
elixir(function(mix) {
|
||||
mix.sass('styles.scss')
|
||||
.sass('print-styles.scss')
|
||||
.sass('export-styles.scss')
|
||||
.browserify('global.js', 'public/js/common.js')
|
||||
.queryVersion(['css/styles.css', 'css/print-styles.css', 'js/common.js']);
|
||||
elixir(mix => {
|
||||
mix.sass('styles.scss');
|
||||
mix.sass('print-styles.scss');
|
||||
mix.sass('export-styles.scss');
|
||||
mix.browserify('global.js', './public/js/common.js');
|
||||
});
|
||||
|
15
package.json
15
package.json
@ -1,18 +1,19 @@
|
||||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.0"
|
||||
"scripts": {
|
||||
"prod": "gulp --production",
|
||||
"dev": "gulp watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"devDependencies": {
|
||||
"angular": "^1.5.5",
|
||||
"angular-animate": "^1.5.5",
|
||||
"angular-resource": "^1.5.5",
|
||||
"angular-sanitize": "^1.5.5",
|
||||
"angular-ui-sortable": "^0.14.0",
|
||||
"babel-runtime": "^5.8.29",
|
||||
"bootstrap-sass": "^3.0.0",
|
||||
"angular-ui-sortable": "^0.15.0",
|
||||
"dropzone": "^4.0.1",
|
||||
"laravel-elixir": "^5.0.0",
|
||||
"gulp": "^3.9.0",
|
||||
"laravel-elixir": "^6.0.0-11",
|
||||
"laravel-elixir-browserify-official": "^0.1.3",
|
||||
"marked": "^0.3.5",
|
||||
"moment": "^2.12.0",
|
||||
"zeroclipboard": "^2.2.0"
|
||||
|
@ -30,6 +30,7 @@
|
||||
<env name="AUTH_METHOD" value="standard"/>
|
||||
<env name="DISABLE_EXTERNAL_SERVICES" value="true"/>
|
||||
<env name="LDAP_VERSION" value="3"/>
|
||||
<env name="STORAGE_TYPE" value="local"/>
|
||||
<env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
|
||||
<env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
|
||||
<env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
|
||||
|
2
public/build/.gitignore
vendored
2
public/build/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
10
readme.md
10
readme.md
@ -2,13 +2,15 @@
|
||||
|
||||
[![GitHub release](https://img.shields.io/github/release/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/releases/latest)
|
||||
[![license](https://img.shields.io/github/license/ssddanbrown/BookStack.svg?maxAge=2592000)](https://github.com/ssddanbrown/BookStack/blob/master/LICENSE)
|
||||
[![Build Status](https://travis-ci.org/ssddanbrown/BookStack.svg)](https://travis-ci.org/ssddanbrown/BookStack)
|
||||
[![Build Status](https://travis-ci.org/BookStackApp/BookStack.svg)](https://travis-ci.org/BookStackApp/BookStack)
|
||||
|
||||
A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/.
|
||||
|
||||
* [Installation Instructions](https://www.bookstackapp.com/docs/admin/installation)
|
||||
* [Documentation](https://www.bookstackapp.com/docs)
|
||||
* [Demo Instance](https://demo.bookstackapp.com) *(Login username: `admin@example.com`. Password: `password`)*
|
||||
* [Demo Instance](https://demo.bookstackapp.com)
|
||||
* *Username: `admin@example.com`*
|
||||
* *Password: `password`*
|
||||
* [BookStack Blog](https://www.bookstackapp.com/blog)
|
||||
|
||||
## Development & Testing
|
||||
@ -29,7 +31,7 @@ php artisan migrate --database=mysql_testing
|
||||
php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
|
||||
```
|
||||
|
||||
Once done you can run `phpunit` (or `./vendor/bin/phpunit` if `phpunit` is not found) in the application root directory to run all tests.
|
||||
Once done you can run `phpunit` in the application root directory to run all tests.
|
||||
|
||||
## License
|
||||
|
||||
@ -51,3 +53,5 @@ These are the great projects used to help build BookStack:
|
||||
* [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html)
|
||||
* [Marked](https://github.com/chjj/marked)
|
||||
* [Moment.js](http://momentjs.com/)
|
||||
|
||||
Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy.
|
||||
|
@ -1,3 +0,0 @@
|
||||
<div class="dropzone-container">
|
||||
<div class="dz-message">Drop files or click here to upload</div>
|
||||
</div>
|
@ -1,15 +0,0 @@
|
||||
|
||||
<div class="image-picker">
|
||||
<div>
|
||||
<img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
|
||||
<img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
|
||||
</div>
|
||||
<button class="button" type="button" ng-click="showImageManager()">Select Image</button>
|
||||
<br>
|
||||
|
||||
<button class="text-button" ng-click="reset()" type="button">Reset</button>
|
||||
<span ng-show="showRemove" class="sep">|</span>
|
||||
<button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
|
||||
|
||||
<input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
|
||||
</div>
|
@ -1,4 +0,0 @@
|
||||
<div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
|
||||
<input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
|
||||
<div class="switch-handle"></div>
|
||||
</div>
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
const moment = require('moment');
|
||||
import moment from 'moment';
|
||||
import 'moment/locale/en-gb';
|
||||
moment.locale('en-gb');
|
||||
|
||||
module.exports = function (ngApp, events) {
|
||||
|
||||
@ -17,7 +19,7 @@ module.exports = function (ngApp, events) {
|
||||
$scope.imageDeleteSuccess = false;
|
||||
$scope.uploadedTo = $attrs.uploadedTo;
|
||||
$scope.view = 'all';
|
||||
|
||||
|
||||
$scope.searching = false;
|
||||
$scope.searchTerm = '';
|
||||
|
||||
@ -48,7 +50,7 @@ module.exports = function (ngApp, events) {
|
||||
$scope.hasMore = preSearchHasMore;
|
||||
}
|
||||
$scope.cancelSearch = cancelSearch;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Runs on image upload, Adds an image to local list of images
|
||||
@ -437,7 +439,7 @@ module.exports = function (ngApp, events) {
|
||||
|
||||
const pageId = Number($attrs.pageId);
|
||||
$scope.tags = [];
|
||||
|
||||
|
||||
$scope.sortOptions = {
|
||||
handle: '.handle',
|
||||
items: '> tr',
|
||||
@ -729,20 +731,3 @@ module.exports = function (ngApp, events) {
|
||||
}]);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -2,10 +2,6 @@
|
||||
const DropZone = require('dropzone');
|
||||
const markdown = require('marked');
|
||||
|
||||
const toggleSwitchTemplate = require('./components/toggle-switch.html');
|
||||
const imagePickerTemplate = require('./components/image-picker.html');
|
||||
const dropZoneTemplate = require('./components/drop-zone.html');
|
||||
|
||||
module.exports = function (ngApp, events) {
|
||||
|
||||
/**
|
||||
@ -16,7 +12,12 @@ module.exports = function (ngApp, events) {
|
||||
ngApp.directive('toggleSwitch', function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
template: toggleSwitchTemplate,
|
||||
template: `
|
||||
<div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
|
||||
<input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
|
||||
<div class="switch-handle"></div>
|
||||
</div>
|
||||
`,
|
||||
scope: true,
|
||||
link: function (scope, element, attrs) {
|
||||
scope.name = attrs.name;
|
||||
@ -77,7 +78,7 @@ module.exports = function (ngApp, events) {
|
||||
});
|
||||
|
||||
element.find('button[type="submit"]').click(submitEvent);
|
||||
|
||||
|
||||
function submitEvent(e) {
|
||||
e.preventDefault()
|
||||
if (attrs.subForm) scope.$eval(attrs.subForm);
|
||||
@ -94,7 +95,22 @@ module.exports = function (ngApp, events) {
|
||||
ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: imagePickerTemplate,
|
||||
template: `
|
||||
<div class="image-picker">
|
||||
<div>
|
||||
<img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
|
||||
<img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
|
||||
</div>
|
||||
<button class="button" type="button" ng-click="showImageManager()">Select Image</button>
|
||||
<br>
|
||||
|
||||
<button class="text-button" ng-click="reset()" type="button">Reset</button>
|
||||
<span ng-show="showRemove" class="sep">|</span>
|
||||
<button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
|
||||
|
||||
<input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
|
||||
</div>
|
||||
`,
|
||||
scope: {
|
||||
name: '@',
|
||||
resizeHeight: '@',
|
||||
@ -161,7 +177,11 @@ module.exports = function (ngApp, events) {
|
||||
ngApp.directive('dropZone', [function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: dropZoneTemplate,
|
||||
template: `
|
||||
<div class="dropzone-container">
|
||||
<div class="dz-message">Drop files or click here to upload</div>
|
||||
</div>
|
||||
`,
|
||||
scope: {
|
||||
uploadUrl: '@',
|
||||
eventSuccess: '=',
|
||||
@ -603,7 +623,7 @@ module.exports = function (ngApp, events) {
|
||||
let val = $input.val();
|
||||
let url = $input.attr('autosuggest');
|
||||
let type = $input.attr('autosuggest-type');
|
||||
|
||||
|
||||
// Add name param to request if for a value
|
||||
if (type.toLowerCase() === 'value') {
|
||||
let $nameInput = $input.closest('tr').find('[autosuggest-type="name"]').first();
|
||||
@ -904,17 +924,3 @@ module.exports = function (ngApp, events) {
|
||||
};
|
||||
}]);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user