Merge "Add docs to about page"
This commit is contained in:
commit
92bf63aa9d
@ -204,6 +204,17 @@ performed to upgrade the database to the latest revision:
|
|||||||
|
|
||||||
Now it should be some revision number other than `None`.
|
Now it should be some revision number other than `None`.
|
||||||
|
|
||||||
|
(Optional) Generate About Page Content
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The RefStack About page is populated with HTML templates generated from
|
||||||
|
our RST documentation files. If you want this information displayed, then
|
||||||
|
run the following command from the root of the project.
|
||||||
|
|
||||||
|
``./tools/convert-docs.py -o ./refstack-ui/app/components/about/templates ./doc/source/*.rst``
|
||||||
|
|
||||||
|
Ignore any unknown directive errors.
|
||||||
|
|
||||||
Start RefStack
|
Start RefStack
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -41,7 +41,9 @@
|
|||||||
}).
|
}).
|
||||||
state('about', {
|
state('about', {
|
||||||
url: '/about',
|
url: '/about',
|
||||||
templateUrl: '/components/about/about.html'
|
templateUrl: '/components/about/about.html',
|
||||||
|
controller: 'AboutController as ctrl'
|
||||||
|
|
||||||
}).
|
}).
|
||||||
state('guidelines', {
|
state('guidelines', {
|
||||||
url: '/guidelines',
|
url: '/guidelines',
|
||||||
|
@ -226,3 +226,26 @@ a.glyphicon {
|
|||||||
.modal-body .row {
|
.modal-body .row {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.about-sidebar {
|
||||||
|
width: 20%;
|
||||||
|
float: left;
|
||||||
|
padding-right: 2px;
|
||||||
|
padding-top: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content {
|
||||||
|
width: 80%;
|
||||||
|
float: left;
|
||||||
|
padding-left: 5%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-option {
|
||||||
|
padding: 5px 5px 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-active {
|
||||||
|
background: #f2f2f2;
|
||||||
|
border-left: 2px solid orange;
|
||||||
|
}
|
@ -1,31 +1,13 @@
|
|||||||
<h1>RefStack Documentation</h1>
|
<hr>
|
||||||
|
<div class="about-sidebar">
|
||||||
<p>RefStack is a source of tools for interoperability testing of OpenStack clouds.</p>
|
<div ng-repeat="(key, data) in ctrl.options | arrayConverter | orderBy: 'order'">
|
||||||
<p>To learn more about RefStack, visit the links below.</p>
|
<a><div class="about-option"
|
||||||
|
ng-click="ctrl.selectOption(data.id)"
|
||||||
<ol>
|
ng-class="{ 'about-active': ctrl.selected === data.id }">
|
||||||
<li>
|
{{data.title}}
|
||||||
<a href="http://github.com/openstack/refstack/blob/master/README.rst#refstack"
|
</div></a>
|
||||||
target="_blank"
|
</div>
|
||||||
</a>
|
</div>
|
||||||
<strong>About RefStack</strong>
|
<div class="about-content">
|
||||||
</li>
|
<div ng-include src="ctrl.template"></div>
|
||||||
<li>
|
</div>
|
||||||
<a href="http://github.com/openstack/refstack/blob/master/doc/source/uploading_private_results.rst#how-to-upload-test-results-to-refstack"
|
|
||||||
target="_blank"
|
|
||||||
</a>
|
|
||||||
<strong>How to upload test results to RefStack</strong>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="http://github.com/openstack/refstack/blob/master/doc/source/vendor_product.rst#vendor-and-product-management"
|
|
||||||
target="_blank"
|
|
||||||
</a>
|
|
||||||
<strong>Vendor and product management</strong>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="http://github.com/openstack/refstack/blob/master/doc/source/test_result_management.rst#test-result-management"
|
|
||||||
target="_blank"
|
|
||||||
</a>
|
|
||||||
<strong>Test result management</strong>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
85
refstack-ui/app/components/about/aboutController.js
Normal file
85
refstack-ui/app/components/about/aboutController.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('refstackApp')
|
||||||
|
.controller('AboutController', AboutController);
|
||||||
|
|
||||||
|
AboutController.$inject = ['$location'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RefStack About Controller
|
||||||
|
* This controller handles the about page and the multiple templates
|
||||||
|
* associated to the page.
|
||||||
|
*/
|
||||||
|
function AboutController($location) {
|
||||||
|
var ctrl = this;
|
||||||
|
|
||||||
|
ctrl.selectOption = selectOption;
|
||||||
|
ctrl.getHash = getHash;
|
||||||
|
|
||||||
|
ctrl.options = {
|
||||||
|
'about' : {
|
||||||
|
'title': 'About RefStack',
|
||||||
|
'template': 'components/about/templates/README.html',
|
||||||
|
'order': 1
|
||||||
|
},
|
||||||
|
'uploading-your-results': {
|
||||||
|
'title': 'Uploading Your Results',
|
||||||
|
'template': 'components/about/templates/' +
|
||||||
|
'uploading_private_results.html',
|
||||||
|
'order': 2
|
||||||
|
},
|
||||||
|
'managing-results': {
|
||||||
|
'title': 'Managing Results',
|
||||||
|
'template': 'components/about/templates/' +
|
||||||
|
'test_result_management.html',
|
||||||
|
'order': 3
|
||||||
|
},
|
||||||
|
'vendors-and-products': {
|
||||||
|
'title': 'Vendors and Products',
|
||||||
|
'template': 'components/about/templates/vendor_product.html',
|
||||||
|
'order': 4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an option key, mark it as selected and set the corresponding
|
||||||
|
* template and URL hash.
|
||||||
|
*/
|
||||||
|
function selectOption(key) {
|
||||||
|
ctrl.selected = key;
|
||||||
|
ctrl.template = ctrl.options[key].template;
|
||||||
|
$location.hash(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hash in the URL and select it if possible.
|
||||||
|
*/
|
||||||
|
function getHash() {
|
||||||
|
var hash = $location.hash();
|
||||||
|
if (hash && hash in ctrl.options) {
|
||||||
|
ctrl.selectOption(hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctrl.selectOption('about');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.getHash();
|
||||||
|
}
|
||||||
|
})();
|
@ -40,6 +40,7 @@
|
|||||||
<script src="shared/header/headerController.js"></script>
|
<script src="shared/header/headerController.js"></script>
|
||||||
<script src="shared/alerts/alertModalFactory.js"></script>
|
<script src="shared/alerts/alertModalFactory.js"></script>
|
||||||
<script src="shared/alerts/confirmModalFactory.js"></script>
|
<script src="shared/alerts/confirmModalFactory.js"></script>
|
||||||
|
<script src="components/about/aboutController.js"></script>
|
||||||
<script src="components/guidelines/guidelinesController.js"></script>
|
<script src="components/guidelines/guidelinesController.js"></script>
|
||||||
<script src="components/results/resultsController.js"></script>
|
<script src="components/results/resultsController.js"></script>
|
||||||
<script src="components/results-report/resultsReportController.js"></script>
|
<script src="components/results-report/resultsReportController.js"></script>
|
||||||
|
@ -58,6 +58,49 @@ describe('Refstack controllers', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('AboutController', function () {
|
||||||
|
var $location, ctrl;
|
||||||
|
|
||||||
|
beforeEach(inject(function ($controller, _$location_) {
|
||||||
|
$location = _$location_;
|
||||||
|
ctrl = $controller('AboutController', {});
|
||||||
|
ctrl.options = {
|
||||||
|
'about' : {
|
||||||
|
'title': 'About RefStack',
|
||||||
|
'template': 'about-template'
|
||||||
|
},
|
||||||
|
'option1' : {
|
||||||
|
'title': 'Option One',
|
||||||
|
'template': 'template-1'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have a function to select an option',
|
||||||
|
function () {
|
||||||
|
ctrl.selectOption('option1');
|
||||||
|
expect(ctrl.selected).toBe('option1');
|
||||||
|
expect(ctrl.template).toBe('template-1');
|
||||||
|
expect($location.hash()).toBe('option1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a function to get the URL hash and select it',
|
||||||
|
function () {
|
||||||
|
// Test existing option.
|
||||||
|
$location.url('/about#option1');
|
||||||
|
ctrl.getHash();
|
||||||
|
expect(ctrl.selected).toBe('option1');
|
||||||
|
expect(ctrl.template).toBe('template-1');
|
||||||
|
|
||||||
|
// Test nonexistent option.
|
||||||
|
$location.url('/about#foobar');
|
||||||
|
ctrl.getHash();
|
||||||
|
expect(ctrl.selected).toBe('about');
|
||||||
|
expect(ctrl.template).toBe('about-template');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('GuidelinesController', function () {
|
describe('GuidelinesController', function () {
|
||||||
var ctrl;
|
var ctrl;
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
SQLAlchemy>=0.8.3
|
SQLAlchemy>=0.8.3
|
||||||
alembic==0.5.0
|
alembic==0.5.0
|
||||||
beaker==1.6.5.post1
|
beaker==1.6.5.post1
|
||||||
|
beautifulsoup4
|
||||||
cryptography>=1.0,!=1.3.0 # BSD/Apache-2.0
|
cryptography>=1.0,!=1.3.0 # BSD/Apache-2.0
|
||||||
|
docutils>=0.11
|
||||||
oslo.config>=1.6.0 # Apache-2.0
|
oslo.config>=1.6.0 # Apache-2.0
|
||||||
oslo.db>=1.4.1 # Apache-2.0
|
oslo.db>=1.4.1 # Apache-2.0
|
||||||
oslo.log>=3.11.0
|
oslo.log>=3.11.0
|
||||||
|
75
tools/convert-docs.py
Executable file
75
tools/convert-docs.py
Executable file
@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2017 IBM, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Convert RST files to basic HTML. The primary use case is to provide a way
|
||||||
|
to display RefStack documentation on the RefStack website.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from docutils.core import publish_file
|
||||||
|
|
||||||
|
|
||||||
|
def extract_body(html):
|
||||||
|
"""Extract the content of the body tags of an HTML string."""
|
||||||
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
|
return ''.join(['%s' % str(a) for a in soup.body.contents])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Convert RST files to basic HTML template files.'
|
||||||
|
)
|
||||||
|
parser.add_argument('files',
|
||||||
|
metavar='file',
|
||||||
|
nargs='+',
|
||||||
|
help='RST file(s) to be converted to HTML templates.')
|
||||||
|
parser.add_argument('-o', '--output_dir',
|
||||||
|
required=False,
|
||||||
|
help='The directory where template files should be '
|
||||||
|
'output to. Defaults to the current directory.')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.output_dir:
|
||||||
|
output_dir = args.output_dir
|
||||||
|
# If the output directory doesn't exist, create it.
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
try:
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
except OSError:
|
||||||
|
if not os.path.isdir(output_dir):
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
output_dir = os.getcwd()
|
||||||
|
|
||||||
|
for path in args.files:
|
||||||
|
for file in glob.glob(path):
|
||||||
|
base_file = os.path.splitext(os.path.basename(file))[0]
|
||||||
|
|
||||||
|
# Calling publish_file will also print to stdout. Destination path
|
||||||
|
# is set to /dev/null to suppress this.
|
||||||
|
html = publish_file(source_path=file,
|
||||||
|
destination_path='/dev/null',
|
||||||
|
writer_name='html',)
|
||||||
|
body = extract_body(html)
|
||||||
|
|
||||||
|
output_file = os.path.join(output_dir, base_file + ".html")
|
||||||
|
with open(output_file, "w") as template_file:
|
||||||
|
template_file.write(body)
|
Loading…
x
Reference in New Issue
Block a user