forked from docs/docsportal
269 lines
7.6 KiB
Python
269 lines
7.6 KiB
Python
# 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.
|
|
|
|
import yaml
|
|
|
|
from docutils import nodes
|
|
|
|
from docutils.parsers.rst import Directive
|
|
from docutils.parsers.rst import directives
|
|
from sphinx.util import logging
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class navigator(nodes.General, nodes.Element):
|
|
pass
|
|
|
|
|
|
class service_group(nodes.General, nodes.Element):
|
|
pass
|
|
|
|
|
|
class container_item(nodes.General, nodes.Element):
|
|
pass
|
|
|
|
|
|
YAML_CACHE = {}
|
|
|
|
|
|
class ServiceGroup(Directive):
|
|
node_class = service_group
|
|
option_spec = {
|
|
'class': directives.unchanged,
|
|
'data': directives.unchanged_required,
|
|
'category': directives.unchanged_required
|
|
}
|
|
|
|
has_content = False
|
|
|
|
def _load_data(self, fpath):
|
|
global YAML_CACHE
|
|
if fpath in YAML_CACHE:
|
|
return YAML_CACHE[fpath]
|
|
data = {}
|
|
try:
|
|
with open(fpath, 'r') as stream:
|
|
data = yaml.safe_load(stream)
|
|
except IOError:
|
|
LOG.warning(
|
|
"Parameters file not found, %s", fpath,
|
|
location=(self.state.document.settings.env.docname, None))
|
|
return
|
|
except yaml.YAMLError as exc:
|
|
LOG.exception(
|
|
exc_info=exc,
|
|
msg="Error while parsing file [%s]." % fpath)
|
|
raise
|
|
|
|
YAML_CACHE[fpath] = data
|
|
return data
|
|
|
|
def run(self):
|
|
node = self.node_class()
|
|
_, fpath = self.state.document.settings.env.relfn2path(
|
|
self.options['data'])
|
|
data = self._load_data(fpath)
|
|
node['data'] = data['service_categories'][self.options['category']]
|
|
node['class'] = self.options.get('class', 'navigator-container')
|
|
return [node]
|
|
|
|
|
|
class Navigator(Directive):
|
|
node_class = navigator
|
|
option_spec = {
|
|
'class': directives.unchanged,
|
|
'data': directives.unchanged_required,
|
|
'link_type': directives.unchanged
|
|
}
|
|
|
|
has_content = False
|
|
|
|
def _load_data(self, fpath):
|
|
global YAML_CACHE
|
|
if fpath in YAML_CACHE:
|
|
return YAML_CACHE[fpath]
|
|
data = {}
|
|
try:
|
|
with open(fpath, 'r') as stream:
|
|
data = yaml.safe_load(stream)
|
|
except IOError:
|
|
LOG.warning(
|
|
"Parameters file not found, %s", fpath,
|
|
location=(self.state.document.settings.env.docname, None))
|
|
return
|
|
except yaml.YAMLError as exc:
|
|
LOG.exception(
|
|
exc_info=exc,
|
|
msg="Error while parsing file [%s]." % fpath)
|
|
raise
|
|
|
|
YAML_CACHE[fpath] = data
|
|
return data
|
|
|
|
def run(self):
|
|
node = self.node_class()
|
|
_, fpath = self.state.document.settings.env.relfn2path(
|
|
self.options['data'])
|
|
self.data = self._load_data(fpath)
|
|
node['data'] = self.data
|
|
node['link_type'] = self.options['link_type']
|
|
node['class'] = self.options.get('class', 'navigator-container')
|
|
return [node]
|
|
|
|
|
|
class ContainerItem(Directive):
|
|
node_class = container_item
|
|
option_spec = {
|
|
'title': directives.unchanged
|
|
}
|
|
|
|
has_content = True
|
|
|
|
def run(self):
|
|
doctree_node = container_item()
|
|
doctree_node['title'] = self.options['title']
|
|
services = []
|
|
for ent in self.content:
|
|
_srv = ent.strip('- ')
|
|
# Split on first ":"
|
|
srv_parts = _srv.split(':', 1)
|
|
key = srv_parts[0]
|
|
data_parts = srv_parts[1].split("|")
|
|
title = data_parts[0]
|
|
href = data_parts[1] if len(data_parts) > 1 else key
|
|
services.append(
|
|
dict(
|
|
key=key,
|
|
title=title,
|
|
href=href
|
|
)
|
|
)
|
|
doctree_node['services'] = services
|
|
return [doctree_node]
|
|
|
|
|
|
def container_item_html(self, node):
|
|
tmpl = """
|
|
<div class="navigator-item">
|
|
<h3>%(title)s</h3>
|
|
%(data)s
|
|
</div>
|
|
"""
|
|
|
|
node['data'] = (
|
|
"<ul class='service-category'>" +
|
|
"".join([('<li><a href="%(href)s">'
|
|
'<div class="row">'
|
|
'<div class="col-md-2">'
|
|
'<img src="_static/images/%(key)s.svg">'
|
|
'</div>'
|
|
'<div class="col-md-10">%(title)s</div>'
|
|
'</div></a></li>'
|
|
% x)
|
|
for x in node['services']]) +
|
|
"</ul>")
|
|
self.body.append(tmpl % node)
|
|
raise nodes.SkipNode
|
|
|
|
|
|
def navigator_html(self, node):
|
|
data = f'<div class="{node["class"]}">'
|
|
for k, v in node['data']['service_categories'].items():
|
|
data += (
|
|
f'<div class="navigator-item">'
|
|
f"<h3>{v['title']}</h3><ul class='service-category'>"
|
|
)
|
|
for srv_k, srv_v in v['services'].items():
|
|
link = srv_v.get(node["link_type"], srv_k)
|
|
img = srv_k
|
|
title = srv_v["title"]
|
|
data += (
|
|
f'<li><a href="{link}">'
|
|
f'<div class="row">'
|
|
f'<div class="col-md-2 col-sm-2 col-xs-2">'
|
|
f'<img src="_static/images/services/{img}.svg">'
|
|
f'</div>'
|
|
f'<div class="col-md-10 col-sm-10 col-xs-10">{title}</div>'
|
|
f'</div></a></li>'
|
|
)
|
|
data += '</ul></div>'
|
|
|
|
data += '</div>'
|
|
|
|
self.body.append(data)
|
|
raise nodes.SkipNode
|
|
|
|
|
|
def service_group_html(self, node):
|
|
data = f'<div class={node["class"]}><table class="table table-bordered table-hover">'
|
|
for k, v in node['data']['services'].items():
|
|
img = k
|
|
title = v["title"]
|
|
data += '<tr>'
|
|
# 1st column - title
|
|
data += (
|
|
f'<td><div class="col-sm-2">'
|
|
f'<img src="_static/images/services/{img}.svg">'
|
|
f'</div><div class="col-sm-10">'
|
|
f'{title}</div>'
|
|
f'</td>'
|
|
)
|
|
# 3rd column - API-Ref
|
|
link = v.get("api")
|
|
data += (
|
|
f'<td>'
|
|
f'<a href="{link}">API Reference</a>'
|
|
f'</td>'
|
|
) if link else (
|
|
f'<td></td>'
|
|
)
|
|
# 4th column - UMN
|
|
link = v.get("umn")
|
|
data += (
|
|
f'<td>'
|
|
f'<a href="{link}">User Manual</a>'
|
|
f'</td>'
|
|
) if link else (
|
|
f'<td></td>'
|
|
)
|
|
# all other links
|
|
for link in v.get("links", []):
|
|
data += (
|
|
f'<td>'
|
|
f'<a href="{link["url"]}">{link["title"]}</a>'
|
|
f'</td>'
|
|
)
|
|
# Row end
|
|
data += '</tr>'
|
|
data += "</table></div>"
|
|
self.body.append(data)
|
|
raise nodes.SkipNode
|
|
|
|
|
|
def setup(app):
|
|
app.add_node(container_item,
|
|
html=(container_item_html, None))
|
|
app.add_node(navigator,
|
|
html=(navigator_html, None))
|
|
app.add_node(service_group,
|
|
html=(service_group_html, None))
|
|
app.add_directive("container_item", ContainerItem)
|
|
app.add_directive("navigator", Navigator)
|
|
app.add_directive("service_group", ServiceGroup)
|
|
|
|
return {
|
|
'version': '0.1',
|
|
'parallel_read_safe': True,
|
|
'parallel_write_safe': True,
|
|
}
|