@@ -616,7 +616,8 @@ def get_pymodule_path(modulename, *joins): | |||||
:param modulename: Python module name. | :param modulename: Python module name. | ||||
:param *joins: Join additional path elements using `os.path.join`.""" | :param *joins: Join additional path elements using `os.path.join`.""" | ||||
joins = [scrub(part) for part in joins] | |||||
if not "public" in joins: | |||||
joins = [scrub(part) for part in joins] | |||||
return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins) | return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins) | ||||
def get_module_list(app_name): | def get_module_list(app_name): | ||||
@@ -350,11 +350,11 @@ def build_website(context): | |||||
finally: | finally: | ||||
frappe.destroy() | frappe.destroy() | ||||
@click.command('build-dev-docs') | |||||
@click.command('make-docs') | |||||
@pass_context | @pass_context | ||||
@click.argument('app') | @click.argument('app') | ||||
@click.argument('docs_version') | @click.argument('docs_version') | ||||
def make_dev_docs(context, app, docs_version): | |||||
def make_docs(context, app, docs_version): | |||||
"Setup docs in target folder of target app" | "Setup docs in target folder of target app" | ||||
from frappe.utils.setup_docs import setup_docs | from frappe.utils.setup_docs import setup_docs | ||||
for site in context.sites: | for site in context.sites: | ||||
@@ -366,24 +366,60 @@ def make_dev_docs(context, app, docs_version): | |||||
finally: | finally: | ||||
frappe.destroy() | frappe.destroy() | ||||
@click.command('make-docs') | |||||
@click.command('sync-docs') | |||||
@pass_context | |||||
@click.argument('app') | |||||
def sync_docs(context, app): | |||||
"Sync docs from /docs folder into the database (Web Page)" | |||||
from frappe.utils.setup_docs import setup_docs | |||||
for site in context.sites: | |||||
try: | |||||
frappe.init(site=site) | |||||
frappe.connect() | |||||
make = setup_docs(app) | |||||
make.sync_docs() | |||||
finally: | |||||
frappe.destroy() | |||||
@click.command('write-docs') | |||||
@pass_context | @pass_context | ||||
@click.argument('app') | @click.argument('app') | ||||
@click.argument('target') | @click.argument('target') | ||||
def setup_docs(context, app, target): | |||||
@click.option('--local', default=False, is_flag=True, help='Run app locally') | |||||
def write_docs(context, app, target, local=False): | |||||
"Setup docs in target folder of target app" | "Setup docs in target folder of target app" | ||||
from frappe.utils.setup_docs import setup_docs | from frappe.utils.setup_docs import setup_docs | ||||
from frappe.website import statics | |||||
for site in context.sites: | for site in context.sites: | ||||
try: | try: | ||||
frappe.init(site=site) | frappe.init(site=site) | ||||
frappe.connect() | frappe.connect() | ||||
make = setup_docs(app) | make = setup_docs(app) | ||||
make.make_docs(target) | |||||
statics.sync_statics(rebuild=True) | |||||
make.make_docs(target, local) | |||||
finally: | finally: | ||||
frappe.destroy() | frappe.destroy() | ||||
@click.command('build-docs') | |||||
@pass_context | |||||
@click.argument('app') | |||||
@click.argument('docs_version') | |||||
@click.argument('target') | |||||
@click.option('--local', default=False, is_flag=True, help='Run app locally') | |||||
def build_docs(context, app, docs_version, target, local=False): | |||||
"Setup docs in target folder of target app" | |||||
from frappe.utils.setup_docs import setup_docs | |||||
for site in context.sites: | |||||
try: | |||||
frappe.init(site=site) | |||||
frappe.connect() | |||||
make = setup_docs(app) | |||||
make.build(docs_version) | |||||
make.sync_docs() | |||||
make.make_docs(target, local) | |||||
finally: | |||||
frappe.destroy() | |||||
@click.command('reset-perms') | @click.command('reset-perms') | ||||
@pass_context | @pass_context | ||||
def reset_perms(context): | def reset_perms(context): | ||||
@@ -945,8 +981,10 @@ commands = [ | |||||
destroy_all_sessions, | destroy_all_sessions, | ||||
sync_www, | sync_www, | ||||
build_website, | build_website, | ||||
make_dev_docs, | |||||
setup_docs, | |||||
make_docs, | |||||
sync_docs, | |||||
write_docs, | |||||
build_docs, | |||||
reset_perms, | reset_perms, | ||||
execute, | execute, | ||||
celery, | celery, | ||||
@@ -29,7 +29,7 @@ to ERPNext. | |||||
app_icon = "octicon octicon-circuit-board" | app_icon = "octicon octicon-circuit-board" | ||||
app_version = "6.6.1" | app_version = "6.6.1" | ||||
app_color = "orange" | app_color = "orange" | ||||
github_link = "https://github.com/frappe/frappe" | |||||
source_link = "https://github.com/frappe/frappe" | |||||
app_email = "info@frappe.io" | app_email = "info@frappe.io" | ||||
@@ -0,0 +1,156 @@ | |||||
html { | |||||
min-height: 100%; | |||||
} | |||||
body { | |||||
height: 100%; | |||||
/* The html and body elements cannot have any padding or margin. */ | |||||
margin: 0px; | |||||
padding: 0px !important; | |||||
} | |||||
html, | |||||
body { | |||||
overflow-x: hidden; | |||||
/* Prevent scroll on narrow devices */ | |||||
} | |||||
.offcanvas-main-section-overlay { | |||||
display: none; | |||||
cursor: pointer; | |||||
opacity: 0.5; | |||||
} | |||||
.sidebar-padding { | |||||
padding: 12px 14px; | |||||
} | |||||
.offcanvas .sidebar .sidebar-menu > li > a, | |||||
.offcanvas .sidebar .dropdown-menu > li > a { | |||||
padding: 12px 14px; | |||||
display: block; | |||||
whitespace: nowrap; | |||||
transition: 0.2s; | |||||
text-decoration: none !important; | |||||
} | |||||
.offcanvas .sidebar .dropdown-menu { | |||||
padding: 0px; | |||||
font-size: inherit; | |||||
} | |||||
.offcanvas .sidebar .dropdown-menu > li > a { | |||||
padding-left: 28px; | |||||
} | |||||
.offcanvas .sidebar .divider { | |||||
height: 1px; | |||||
overflow: hidden; | |||||
background-color: #ebeff2; | |||||
width: 100%; | |||||
margin: 0px; | |||||
} | |||||
.offcanvas .sidebar .badge { | |||||
right: 15px !important; | |||||
top: 11px !important; | |||||
} | |||||
.offcanvas .sidebar .sidebar-menu > li > a:hover, | |||||
.offcanvas .sidebar .dropdown-menu > li > a:hover, | |||||
.offcanvas .sidebar .sidebar-menu > li > a:focus, | |||||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||||
background-color: #f0f4f7; | |||||
} | |||||
.breadcrumb { | |||||
line-height: 1.5em; | |||||
} | |||||
.breadcrumb { | |||||
background-color: transparent; | |||||
padding: 10px 0px; | |||||
} | |||||
.breadcrumb a, | |||||
.breadcrumb a:hover, | |||||
.breadcrumb a:focus, | |||||
.breadcrumb a:visited { | |||||
color: inherit; | |||||
} | |||||
.navbar { | |||||
background-color: transparent; | |||||
border: none; | |||||
padding: 10px 0px; | |||||
border-radius: 0px; | |||||
border-bottom: 1px solid #7575ff; | |||||
} | |||||
.section { | |||||
padding: 30px 0px; | |||||
} | |||||
.docs-footer { | |||||
margin-top: 50px; | |||||
padding: 30px 0px 60px 0px; | |||||
border-top: 1px solid #d1d8dd; | |||||
} | |||||
.docs-footer a { | |||||
color: #8d99a6; | |||||
} | |||||
.docs-footer li { | |||||
display: inline-block; | |||||
margin: 0 15px; | |||||
} | |||||
.jumbotron { | |||||
background-color: transparent; | |||||
padding: 80px 30px; | |||||
text-align: center; | |||||
} | |||||
.jumbotron h1 { | |||||
font-size: 32px; | |||||
font-weight: 400; | |||||
} | |||||
.jumbotron p { | |||||
font-color: #8d99a6 !important; | |||||
} | |||||
.browser-image { | |||||
min-height: 300px; | |||||
border: 1px solid #d1d8dd; | |||||
} | |||||
.fake-browser-frame { | |||||
position: relative; | |||||
margin: 40px auto; | |||||
max-width: 600px; | |||||
} | |||||
.fake-browser-frame::before { | |||||
content: ""; | |||||
height: 24px; | |||||
position: absolute; | |||||
top: -24px; | |||||
left: 0px; | |||||
right: 0px; | |||||
border: 1px solid #d1d8dd; | |||||
border-bottom: none; | |||||
border-top-left-radius: 4px; | |||||
border-top-right-radius: 4px; | |||||
} | |||||
.fake-browser-frame::after { | |||||
content: '\f111 \f111 \f111'; | |||||
position: absolute; | |||||
color: #d1d8dd; | |||||
top: -15px; | |||||
left: 8px; | |||||
/* octicon */ | |||||
font: normal normal; | |||||
font-size: 8px; | |||||
font-family: 'FontAwesome'; | |||||
line-height: 1; | |||||
display: inline-block; | |||||
text-decoration: none; | |||||
-webkit-font-smoothing: antialiased; | |||||
-moz-osx-font-smoothing: grayscale; | |||||
-webkit-user-select: none; | |||||
-moz-user-select: none; | |||||
-ms-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.fake-iphone-frame { | |||||
position: relative; | |||||
padding: 40px 8px; | |||||
border: 1px solid #d1d8dd; | |||||
border-radius: 15px; | |||||
} | |||||
.fake-ipad-frame { | |||||
position: relative; | |||||
padding: 8px 40px; | |||||
border: 1px solid #d1d8dd; | |||||
border-radius: 15px; | |||||
} |
@@ -0,0 +1,13 @@ | |||||
<?xml version="1.0" standalone="no"?> | |||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |||||
<svg width="100%" height="100%" viewBox="0 0 260 260" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> | |||||
<g> | |||||
<g> | |||||
<path d="M65.838,51.703L111.685,97.55" style="fill:rgb(255,120,61);fill-rule:nonzero;"/> | |||||
<path d="M142.07,214.331C140.972,214.331 139.892,213.904 139.083,213.099L63.699,138.15C62.899,137.355 62.45,136.273 62.45,135.145L62.45,51.703C62.45,49.364 64.346,47.468 66.683,47.468C69.023,47.468 70.919,49.364 70.919,51.703L70.919,133.385L137.833,199.913L137.833,149.073C137.833,146.735 139.729,144.839 142.067,144.839C144.407,144.839 146.303,146.735 146.303,149.073L146.303,210.095C146.303,211.806 145.274,213.349 143.694,214.006C143.17,214.225 142.617,214.331 142.07,214.331Z" style="fill:rgb(141,153,166);fill-rule:nonzero;"/> | |||||
<path d="M66.684,93.206L31.109,93.206C29.423,93.206 27.897,92.208 27.225,90.662C26.552,89.115 26.862,87.317 28.01,86.085L53.506,58.723L62.738,48.816C64.333,47.105 67.013,47.009 68.724,48.604C70.435,50.199 70.529,52.878 68.935,54.59L40.844,84.736L66.684,84.736C69.024,84.736 70.92,86.632 70.92,88.972C70.92,91.311 69.023,93.206 66.684,93.206Z" style="fill:rgb(141,153,166);fill-rule:nonzero;"/> | |||||
<path d="M111.685,101.784C110.588,101.784 109.492,101.362 108.663,100.516L63.663,54.669C62.024,52.999 62.05,50.317 63.719,48.68C65.389,47.041 68.07,47.067 69.708,48.736L114.708,94.584C116.347,96.253 116.321,98.934 114.652,100.572C113.826,101.381 112.756,101.784 111.685,101.784Z" style="fill:rgb(141,153,166);fill-rule:nonzero;"/> | |||||
<path d="M108.015,180.274C106.802,180.274 105.599,179.756 104.761,178.752C103.262,176.956 103.504,174.285 105.299,172.787L231.176,67.796L153.873,67.796L69.229,138.397C67.433,139.895 64.762,139.655 63.263,137.857C61.765,136.062 62.007,133.39 63.803,131.892L149.626,60.309C150.388,59.675 151.347,59.327 152.338,59.327L242.863,59.327C244.645,59.327 246.238,60.444 246.844,62.12C247.451,63.796 246.944,65.673 245.574,66.814L110.726,179.292C109.934,179.953 108.971,180.274 108.015,180.274Z" style="fill:rgb(141,153,166);fill-rule:nonzero;"/> | |||||
</g> | |||||
</g> | |||||
</svg> |
@@ -0,0 +1,122 @@ | |||||
@import "variables.less"; | |||||
@import "offcanvas.less"; | |||||
.breadcrumb { | |||||
line-height: 1.5em; | |||||
} | |||||
.breadcrumb { | |||||
background-color: transparent; | |||||
padding: 10px 0px; | |||||
} | |||||
.breadcrumb a, | |||||
.breadcrumb a:hover, | |||||
.breadcrumb a:focus, | |||||
.breadcrumb a:visited { | |||||
color: inherit; | |||||
} | |||||
.navbar { | |||||
background-color: transparent; | |||||
border: none; | |||||
padding: 10px 0px; | |||||
border-radius: 0px; | |||||
border-bottom: 1px solid @erpnext-blue; | |||||
} | |||||
.section { | |||||
padding: 30px 0px; | |||||
} | |||||
.docs-footer { | |||||
margin-top: 50px; | |||||
padding: 30px 0px 60px 0px; | |||||
border-top: 1px solid @border-color; | |||||
a { | |||||
color: @text-muted; | |||||
} | |||||
li { | |||||
display: inline-block; | |||||
margin: 0 15px; | |||||
} | |||||
} | |||||
.jumbotron { | |||||
background-color: transparent; | |||||
padding: 80px 30px; | |||||
text-align: center; | |||||
h1 { | |||||
font-size: 32px; | |||||
font-weight: 400; | |||||
} | |||||
p { | |||||
font-color: @text-muted !important; | |||||
} | |||||
} | |||||
// fake frames | |||||
.browser-image { | |||||
min-height: 300px; | |||||
border: 1px solid #d1d8dd; | |||||
} | |||||
.fake-browser-frame { | |||||
position: relative; | |||||
margin: 40px auto; | |||||
max-width: 600px; | |||||
} | |||||
.fake-browser-frame::before { | |||||
content: ""; | |||||
height: 24px; | |||||
position: absolute; | |||||
top: -24px; | |||||
left: 0px; | |||||
right: 0px; | |||||
border: 1px solid #d1d8dd; | |||||
border-bottom: none; | |||||
border-top-left-radius: 4px; | |||||
border-top-right-radius: 4px; | |||||
} | |||||
.fake-browser-frame::after { | |||||
content: '\f111 \f111 \f111'; | |||||
position: absolute; | |||||
color: #d1d8dd; | |||||
top: -15px; | |||||
left: 8px; | |||||
/* octicon */ | |||||
font: normal normal; | |||||
font-size: 8px; | |||||
font-family: 'FontAwesome'; | |||||
line-height: 1; | |||||
display: inline-block; | |||||
text-decoration: none; | |||||
-webkit-font-smoothing: antialiased; | |||||
-moz-osx-font-smoothing: grayscale; | |||||
-webkit-user-select: none; | |||||
-moz-user-select: none; | |||||
-ms-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.fake-iphone-frame { | |||||
position: relative; | |||||
padding: 40px 8px; | |||||
border: 1px solid #d1d8dd; | |||||
border-radius: 15px; | |||||
} | |||||
.fake-ipad-frame { | |||||
position: relative; | |||||
padding: 8px 40px; | |||||
border: 1px solid #d1d8dd; | |||||
border-radius: 15px; | |||||
} |
@@ -1,4 +1,5 @@ | |||||
@brand-primary: #5E64FF; | @brand-primary: #5E64FF; | ||||
@erpnext-blue: #7575ff; | |||||
@border-color: #d1d8dd; | @border-color: #d1d8dd; | ||||
@light-border-color: #EBEFF2; | @light-border-color: #EBEFF2; | ||||
@text-color: #36414C; | @text-color: #36414C; | ||||
@@ -1,9 +1,9 @@ | |||||
<!-- title: {{ app.title }} API --> | <!-- title: {{ app.title }} API --> | ||||
{% from "templates/autodoc/macros.html" import github_link, version %} | |||||
{% from "templates/autodoc/macros.html" import source_link, version %} | |||||
<p> | <p> | ||||
{{ version(app.name) }} | {{ version(app.name) }} | ||||
{{ github_link(app, app.name, True) }} | |||||
{{ source_link(app, app.name, True) }} | |||||
</p> | </p> | ||||
<h3>Contents</h3> | <h3>Contents</h3> | ||||
@@ -6,12 +6,15 @@ | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
<title>{{ title }}</title> | <title>{{ title }}</title> | ||||
<meta name="generator" content="frappe"> | <meta name="generator" content="frappe"> | ||||
<link type="text/css" rel="stylesheet" href="/assets/css/bootstrap.css"> | |||||
<link type="text/css" rel="stylesheet" href="/assets/css/hljs.css"> | |||||
<link type="text/css" rel="stylesheet" href="{{ docs_base_url }}/assets/css/bootstrap.css"> | |||||
<link type="text/css" rel="stylesheet" href="{{ docs_base_url }}/assets/css/hljs.css"> | |||||
<link type="text/css" rel="stylesheet" href="{{ docs_base_url }}/assets/css/font-awesome.css"> | |||||
<link type="text/css" rel="stylesheet" href="{{ docs_base_url }}/assets/css/octicons/octicons.css"> | |||||
<link type="text/css" rel="stylesheet" href="{{ docs_base_url }}/assets/css/docs.css"> | |||||
<script type="text/javascript" src="{{ github }}/assets/js/jquery.min.js"></script> | |||||
<script type="text/javascript" src="{{ github }}/assets/js/bootstrap.min.js"></script> | |||||
<script type="text/javascript" src="{{ github }}/assets/js/highlight.pack.js"></script> | |||||
<script type="text/javascript" src="{{ docs_base_url }}/assets/js/jquery.min.js"></script> | |||||
<script type="text/javascript" src="{{ docs_base_url }}/assets/js/bootstrap.min.js"></script> | |||||
<script type="text/javascript" src="{{ docs_base_url }}/assets/js/highlight.pack.js"></script> | |||||
{% block favicon %} | {% block favicon %} | ||||
<link rel="shortcut icon" | <link rel="shortcut icon" | ||||
@@ -63,25 +66,42 @@ | |||||
{% include "templates/includes/navbar/navbar.html" %} | {% include "templates/includes/navbar/navbar.html" %} | ||||
{%- endblock -%} | {%- endblock -%} | ||||
<div class="hero-and-content"> | <div class="hero-and-content"> | ||||
{%- block hero -%} | |||||
<div data-html-block="hero"> | |||||
{{ hero or "" }} | |||||
</div> | |||||
{%- endblock -%} | |||||
{% block content %} | {% block content %} | ||||
<div class="container" data-html-block="content"> | |||||
<div class="container"> | |||||
{{ content }} | {{ content }} | ||||
</div> | </div> | ||||
{% endblock %} | {% endblock %} | ||||
</div> | </div> | ||||
<footer class="page-footer"> | |||||
<div class="container" data-html-block="footer"> | |||||
<footer class="docs-footer"> | |||||
<div class="container"> | |||||
{%- if footer is defined -%}{{ footer }}{%- endif -%} | {%- if footer is defined -%}{{ footer }}{%- endif -%} | ||||
<br> | <br> | ||||
<div class="text-center"> | <div class="text-center"> | ||||
<b>A Frappe App</b><br> | |||||
<a href="https://discuss.erpnext.com" | |||||
target="_blank">Discuss this on the forum</a> | |||||
<ul class="list-unstyled"> | |||||
<li> | |||||
<a href="{{ app.source_link }}"> | |||||
Source</a> | |||||
</li> | |||||
<li> | |||||
<a href="{{ app.source_link }}/issues"> | |||||
Issues</a> | |||||
</li> | |||||
<li> | |||||
<a href="{{ docs_base_url }}/license.html"> | |||||
License</a> | |||||
</li> | |||||
<li> | |||||
<a href="https://discuss.erpnext.com"> | |||||
Forum</a> | |||||
</li> | |||||
<li> | |||||
<a href="https://apps.frappe.io"> | |||||
Frappe Apps</a> | |||||
</li> | |||||
</ul> | |||||
</div> | |||||
<div class="built-with-frappe text-center"> | |||||
<img src="{{ docs_base_url }}/assets/img/frappe-bird-grey.svg" style="width: 40px; height: 40px; margin-top: 20px;"> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</footer> | </footer> | ||||
@@ -0,0 +1,47 @@ | |||||
<!-- title: {{ app.title }} Developer Docs --> | |||||
<!-- no-breadcrumbs --> | |||||
{% from "templates/autodoc/macros.html" import source_link, version %} | |||||
<p> | |||||
{{ version(app.name) }} | |||||
{{ source_link(app, app.name, True) }} | |||||
</p> | |||||
<table class="table table-bordered" style="max-width: 500px;"> | |||||
<tr> | |||||
<td style="width: 40%"> | |||||
App Name | |||||
</td> | |||||
<td> | |||||
<code>{{ app.name }}</code> | |||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td> | |||||
Publisher | |||||
</td> | |||||
<td> | |||||
<code>{{ app.publisher }}</code> | |||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td> | |||||
Version | |||||
</td> | |||||
<td> | |||||
<code>{{ app.version }}</code> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
<h3>Contents</h3> | |||||
<ul> | |||||
<li> | |||||
<a href="models">Models (DocTypes)</a> | |||||
</li> | |||||
<li> | |||||
<a href="api">Server-side API</a> | |||||
</li> | |||||
</ul> | |||||
<!-- jinja --><!-- static --> |
@@ -1,53 +1,20 @@ | |||||
<!-- title: {{ app.title }} Documentation --> | <!-- title: {{ app.title }} Documentation --> | ||||
<!-- no-breadcrumbs --> | <!-- no-breadcrumbs --> | ||||
{% from "templates/autodoc/macros.html" import github_link, version %} | |||||
<p> | |||||
{{ version(app.name) }} | |||||
{{ github_link(app, app.name, True) }} | |||||
</p> | |||||
<div class="jumbotron"> | |||||
<h1>{{ app.headline }}</h1> | |||||
<p>{{ app.description }}</p> | |||||
</div> | |||||
<table class="table table-bordered" style="max-width: 500px;"> | |||||
<tr> | |||||
<td style="width: 40%"> | |||||
App Name | |||||
</td> | |||||
<td> | |||||
<code>{{ app.name }}</code> | |||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td> | |||||
Publisher | |||||
</td> | |||||
<td> | |||||
<code>{{ app.publisher }}</code> | |||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td> | |||||
Version | |||||
</td> | |||||
<td> | |||||
<code>{{ app.version }}</code> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
<hr> | |||||
{{ app.description }} | |||||
<hr> | |||||
<div class="section" style="padding-top: 0px;"> | |||||
<div class="fake-browser-frame"> | |||||
<img class="img-responsive browser-image feature-image" | |||||
src="img/desktop.png"> | |||||
</div> | |||||
</div> | |||||
<h3>Contents</h3> | <h3>Contents</h3> | ||||
<ul> | |||||
<li> | |||||
<a href="models">Models (DocTypes)</a> | |||||
</li> | |||||
<li> | |||||
<a href="api">Server-side API</a> | |||||
</li> | |||||
</ul> | |||||
<!-- jinja --><!-- static --> | |||||
{index} | |||||
<!-- jinja --> |
@@ -1,13 +1,13 @@ | |||||
<!-- title: {{ doctype }} --> | <!-- title: {{ doctype }} --> | ||||
{% from "templates/autodoc/macros.html" import automodule, version, | {% from "templates/autodoc/macros.html" import automodule, version, | ||||
github_link, doctype_link %} | |||||
source_link, doctype_link %} | |||||
{% set doc = frappe.get_doc("DocType", doctype) %} | {% set doc = frappe.get_doc("DocType", doctype) %} | ||||
{% set controller = autodoc.get_controller(doctype) %} | {% set controller = autodoc.get_controller(doctype) %} | ||||
<p> | <p> | ||||
{{ version(doctype) }} | {{ version(doctype) }} | ||||
{{ github_link(app, app.name + "/" + scrub(doc.module) | |||||
{{ source_link(app, app.name + "/" + scrub(doc.module) | |||||
+ "/doctype/" + scrub(doctype), True) }} | + "/doctype/" + scrub(doctype), True) }} | ||||
</p> | </p> | ||||
@@ -0,0 +1,5 @@ | |||||
<!-- title: {{ app.title }} License {{ app.license }} --> | |||||
<h1>{{ app.license}}</h1> | |||||
{{ license_text }} |
@@ -50,15 +50,15 @@ | |||||
Version {{ autodoc.get_version(name) }}</a> | Version {{ autodoc.get_version(name) }}</a> | ||||
{% endmacro %} | {% endmacro %} | ||||
{% macro github_link(app, file_path, tree=False) %} | |||||
<a class="btn btn-default btn-sm" href="{{ app.github_link }}/{{ "tree" if tree else "blob" }}/v{{ app.version }}/{{ file_path }}" | |||||
{% macro source_link(app, file_path, tree=False) %} | |||||
<a class="btn btn-default btn-sm" href="{{ app.source_link }}/{{ "tree" if tree else "blob" }}/v{{ app.version }}/{{ file_path }}" | |||||
target="_blank" style="margin-left: 10px; margin-bottom: 10px;"><i class="octicon octicon-mark-github"></i> Source</a> | target="_blank" style="margin-left: 10px; margin-bottom: 10px;"><i class="octicon octicon-mark-github"></i> Source</a> | ||||
{% endmacro %} | {% endmacro %} | ||||
{% macro doctype_link(app, doctype) %} | {% macro doctype_link(app, doctype) %} | ||||
{% set module = frappe.db.get_value("DocType", doctype, "module") %} | {% set module = frappe.db.get_value("DocType", doctype, "module") %} | ||||
{% if doctype and module %} | {% if doctype and module %} | ||||
<a href="{{ app.github }}/{{ app.docs_version }}/models/{{ | |||||
<a href="{{ app.docs_base_url }}/{{ app.docs_version }}/models/{{ | |||||
scrub(module) }}/{{ scrub(doctype) }}">{{ doctype }}</a> | scrub(module) }}/{{ scrub(doctype) }}">{{ doctype }}</a> | ||||
{% endif %} | {% endif %} | ||||
{% endmacro %} | {% endmacro %} |
@@ -1,9 +1,9 @@ | |||||
<!-- title: {{ app.title }} Models (DocTypes) --> | <!-- title: {{ app.title }} Models (DocTypes) --> | ||||
{% from "templates/autodoc/macros.html" import github_link, version %} | |||||
{% from "templates/autodoc/macros.html" import source_link, version %} | |||||
<p> | <p> | ||||
{{ version(app.name) }} | {{ version(app.name) }} | ||||
{{ github_link(app, app.name, True) }} | |||||
{{ source_link(app, app.name, True) }} | |||||
</p> | </p> | ||||
<p>Browse DocTypes by Module</p> | <p>Browse DocTypes by Module</p> | ||||
@@ -1,9 +1,9 @@ | |||||
<!-- title: Module {{ name }} --> | <!-- title: Module {{ name }} --> | ||||
{% from "templates/autodoc/macros.html" import github_link, version %} | |||||
{% from "templates/autodoc/macros.html" import source_link, version %} | |||||
<p> | <p> | ||||
{{ version(app.name) }} | {{ version(app.name) }} | ||||
{{ github_link(app, app.name + "/" + scrub(name), True) }} | |||||
{{ source_link(app, app.name + "/" + scrub(name), True) }} | |||||
</p> | </p> | ||||
<h3>DocTypes for {{ name }}</h3> | <h3>DocTypes for {{ name }}</h3> | ||||
@@ -1,9 +1,9 @@ | |||||
<!-- title: {{ title }} --> | <!-- title: {{ title }} --> | ||||
{% from "templates/autodoc/macros.html" import github_link, version %} | |||||
{% from "templates/autodoc/macros.html" import source_link, version %} | |||||
<p> | <p> | ||||
{{ version(app.name) }} | {{ version(app.name) }} | ||||
{{ github_link(app, title, True) }} | |||||
{{ source_link(app, title, True) }} | |||||
</p> | </p> | ||||
<h3>Package Contents</h3> | <h3>Package Contents</h3> | ||||
@@ -1,10 +1,10 @@ | |||||
<!-- title: {{ name }} --> | <!-- title: {{ name }} --> | ||||
{%- from "templates/autodoc/macros.html" import automodule, github_link, | |||||
{%- from "templates/autodoc/macros.html" import automodule, source_link, | |||||
version -%} | version -%} | ||||
<p> | <p> | ||||
{{ version(app.name) }} | {{ version(app.name) }} | ||||
{{ github_link(app, name.replace(".", "/") + ".py") }} | |||||
{{ source_link(app, name.replace(".", "/") + ".py") }} | |||||
</p> | </p> | ||||
{{ automodule(name) }} | {{ automodule(name) }} |
@@ -9,6 +9,7 @@ Call from command line: | |||||
import os, json, frappe, markdown2, shutil | import os, json, frappe, markdown2, shutil | ||||
import frappe.website.statics | import frappe.website.statics | ||||
from frappe.website.context import get_context | from frappe.website.context import get_context | ||||
from markdown2 import markdown | |||||
class setup_docs(object): | class setup_docs(object): | ||||
def __init__(self, app): | def __init__(self, app): | ||||
@@ -18,10 +19,28 @@ class setup_docs(object): | |||||
self.app = app | self.app = app | ||||
self.hooks = frappe.get_hooks(app_name = self.app) | self.hooks = frappe.get_hooks(app_name = self.app) | ||||
self.app_title = self.hooks.get("app_title")[0] | self.app_title = self.hooks.get("app_title")[0] | ||||
self.setup_app_context() | |||||
def setup_app_context(self): | |||||
self.app_context = { | |||||
"app": { | |||||
"name": self.app, | |||||
"title": self.app_title, | |||||
"description": markdown2.markdown(self.hooks.get("app_description")[0]), | |||||
"version": self.hooks.get("app_version")[0], | |||||
"headline": self.hooks.get("app_headline")[0], | |||||
"publisher": self.hooks.get("app_publisher")[0], | |||||
"source_link": self.hooks.get("source_link")[0], | |||||
"docs_base_url": self.hooks.get("docs_base_url")[0], | |||||
"license": self.hooks.get("app_license")[0] | |||||
} | |||||
} | |||||
def build(self, docs_version): | def build(self, docs_version): | ||||
"""Build templates for docs models and Python API""" | """Build templates for docs models and Python API""" | ||||
self.path = frappe.get_app_path(self.app, "docs", docs_version) | |||||
self.docs_path = frappe.get_app_path(self.app, "docs") | |||||
self.path = os.path.join(self.docs_path, docs_version) | |||||
self.app_context["app"]["docs_version"] = docs_version | |||||
self.app_title = self.hooks.get("app_title")[0] | self.app_title = self.hooks.get("app_title")[0] | ||||
self.app_path = frappe.get_app_path(self.app) | self.app_path = frappe.get_app_path(self.app) | ||||
@@ -30,22 +49,14 @@ class setup_docs(object): | |||||
shutil.rmtree(self.path, ignore_errors = True) | shutil.rmtree(self.path, ignore_errors = True) | ||||
os.makedirs(self.path) | os.makedirs(self.path) | ||||
self.app_context = { | |||||
"app": { | |||||
"name": self.app, | |||||
"title": self.app_title, | |||||
"description": markdown2.markdown(self.hooks.get("app_description")[0]), | |||||
"version": self.hooks.get("app_version")[0], | |||||
"publisher": self.hooks.get("app_publisher")[0], | |||||
"github_link": self.hooks.get("github_link")[0], | |||||
"github": self.hooks.get("github_pages_url")[0], | |||||
"docs_version": docs_version | |||||
} | |||||
} | |||||
# make dev home page | |||||
with open(os.path.join(self.docs_path, "index.html"), "w") as home: | |||||
home.write(frappe.render_template("templates/autodoc/docs_home.html", | |||||
self.app_context)) | |||||
# make home page | |||||
# make dev home page | |||||
with open(os.path.join(self.path, "index.html"), "w") as home: | with open(os.path.join(self.path, "index.html"), "w") as home: | ||||
home.write(frappe.render_template("templates/autodoc/docs_home.html", | |||||
home.write(frappe.render_template("templates/autodoc/dev_home.html", | |||||
self.app_context)) | self.app_context)) | ||||
# make folders | # make folders | ||||
@@ -80,13 +91,34 @@ class setup_docs(object): | |||||
elif self.is_py_module(basepath, folders, files): | elif self.is_py_module(basepath, folders, files): | ||||
self.write_modules(basepath, folders, files) | self.write_modules(basepath, folders, files) | ||||
def make_docs(self, target): | |||||
self.target = target | |||||
self.build_user_docs() | |||||
def build_user_docs(self): | |||||
"""Build templates for user docs pages, if missing.""" | |||||
user_docs_path = os.path.join(self.docs_path, "user") | |||||
with open(os.path.join(self.app_path, "..", "license.txt"), "r") as license_file: | |||||
self.app_context["license_text"] = markdown(license_file.read()) | |||||
html = frappe.render_template("templates/autodoc/license.html", | |||||
context = self.app_context) | |||||
with open(os.path.join(self.docs_path, "license.html"), "w") as license_file: | |||||
license_file.write(html) | |||||
self.update_index_txt(self.docs_path) | |||||
def sync_docs(self): | |||||
"""Sync docs from /docs folder to **Web Page**. | |||||
print "Loadings docs..." | |||||
Called as `bench --site [sitename] sync-docs [appname]` | |||||
""" | |||||
sync = frappe.website.statics.sync() | sync = frappe.website.statics.sync() | ||||
sync.start(path="docs", rebuild=True) | sync.start(path="docs", rebuild=True) | ||||
def make_docs(self, target, local = False): | |||||
self.target = target | |||||
self.local = local | |||||
# write in target path | # write in target path | ||||
self.write_files() | self.write_files() | ||||
@@ -187,7 +219,10 @@ class setup_docs(object): | |||||
def write_files(self): | def write_files(self): | ||||
"""render templates and write files to target folder""" | """render templates and write files to target folder""" | ||||
frappe.local.flags.home_page = "index" | frappe.local.flags.home_page = "index" | ||||
github_pages_url = self.hooks.get("github_pages_url")[0] | |||||
if self.local: | |||||
docs_base_url = "" | |||||
else: | |||||
docs_base_url = self.hooks.get("docs_base_url")[0] | |||||
for page in frappe.db.sql("""select parent_website_route, | for page in frappe.db.sql("""select parent_website_route, | ||||
page_name from `tabWeb Page`""", as_dict=True): | page_name from `tabWeb Page`""", as_dict=True): | ||||
@@ -204,33 +239,35 @@ class setup_docs(object): | |||||
"relative_links": True | "relative_links": True | ||||
}) | }) | ||||
target_filename = os.path.join(self.target, context.template_path.split('/docs/', 1)[1]) | |||||
print "Writing {0}".format(target_filename) | |||||
context.update(self.app_context) | |||||
context.update({ | context.update({ | ||||
"brand_html": self.app_title, | "brand_html": self.app_title, | ||||
"top_bar_items": [ | "top_bar_items": [ | ||||
{"label": "User", "url":"/", "right": 1}, | |||||
{"label": "Developer", "url":"/current", "right": 1}, | |||||
{"label": "About", "url":"/user/about", "right": 1} | |||||
{"label": "User", "url": docs_base_url + "/", "right": 1}, | |||||
{"label": "Developer", "url": docs_base_url + "/current", "right": 1}, | |||||
{"label": "About", "url": docs_base_url + "/user/about", "right": 1} | |||||
], | ], | ||||
"favicon": "/assets/img/favicon.ico", | "favicon": "/assets/img/favicon.ico", | ||||
"only_static": True, | "only_static": True, | ||||
"github_pages_url": github_pages_url, | |||||
"docs_base_url": docs_base_url, | |||||
}) | }) | ||||
html = frappe.get_template("templates/autodoc/base_template.html").render(context) | html = frappe.get_template("templates/autodoc/base_template.html").render(context) | ||||
target_filename = os.path.join(self.target, context.template_path.split('/docs/', 1)[1]) | |||||
if not os.path.exists(os.path.dirname(target_filename)): | if not os.path.exists(os.path.dirname(target_filename)): | ||||
os.makedirs(os.path.dirname(target_filename)) | os.makedirs(os.path.dirname(target_filename)) | ||||
with open(target_filename, "w") as htmlfile: | with open(target_filename, "w") as htmlfile: | ||||
htmlfile.write(html.encode("utf-8")) | htmlfile.write(html.encode("utf-8")) | ||||
print "wrote {0}".format(target_filename) | |||||
def copy_assets(self): | def copy_assets(self): | ||||
"""Copy jquery, bootstrap and other assets to files""" | """Copy jquery, bootstrap and other assets to files""" | ||||
print "Copying assets..." | |||||
assets_path = os.path.join(self.target, "assets") | assets_path = os.path.join(self.target, "assets") | ||||
# copy assets from docs | # copy assets from docs | ||||
@@ -249,10 +286,19 @@ class setup_docs(object): | |||||
"js/lib/bootstrap.min.js": "js/bootstrap.min.js", | "js/lib/bootstrap.min.js": "js/bootstrap.min.js", | ||||
"js/lib/highlight.pack.js": "js/highlight.pack.js", | "js/lib/highlight.pack.js": "js/highlight.pack.js", | ||||
"css/bootstrap.css": "css/bootstrap.css", | "css/bootstrap.css": "css/bootstrap.css", | ||||
"css/hljs.css": "css/hljs.css" | |||||
"css/font-awesome.css": "css/font-awesome.css", | |||||
"css/docs.css": "css/docs.css", | |||||
"css/hljs.css": "css/hljs.css", | |||||
"css/font": "css/font", | |||||
"css/octicons": "css/octicons", | |||||
"images/frappe-bird-grey.svg": "img/frappe-bird-grey.svg" | |||||
} | } | ||||
for source, target in copy_files.iteritems(): | for source, target in copy_files.iteritems(): | ||||
shutil.copy(frappe.get_app_path("frappe", "public", source), | |||||
os.path.join(assets_path, target)) | |||||
source_path = frappe.get_app_path("frappe", "public", source) | |||||
if os.path.isdir(source_path): | |||||
if not os.path.exists(os.path.join(assets_path, target)): | |||||
shutil.copytree(source_path, os.path.join(assets_path, target)) | |||||
else: | |||||
shutil.copy(source_path, os.path.join(assets_path, target)) | |||||
@@ -26,7 +26,8 @@ def get_context(path, args=None): | |||||
if not context: | if not context: | ||||
context = get_route_info(path) | context = get_route_info(path) | ||||
context.update(args) | |||||
if args: | |||||
context.update(args) | |||||
context = build_context(context) | context = build_context(context) | ||||
add_data_path(context) | add_data_path(context) | ||||
@@ -211,13 +211,20 @@ class WebsiteGenerator(Document): | |||||
def get_children_of(self, route): | def get_children_of(self, route): | ||||
"""Return list of children of given route, for generating index in Web Page""" | """Return list of children of given route, for generating index in Web Page""" | ||||
condition = 'parent_website_route = %s' | |||||
if route=="index" or not route: | |||||
condition = 'ifnull(parent_website_route, "") = %s and name != "index"' | |||||
route = "" | |||||
children = frappe.db.sql("""select name, page_name, | children = frappe.db.sql("""select name, page_name, | ||||
parent_website_route, {title_field} as title from `tab{doctype}` | parent_website_route, {title_field} as title from `tab{doctype}` | ||||
where parent_website_route = %s | |||||
where {condition} | |||||
order by {order_by}""".format( | order by {order_by}""".format( | ||||
doctype = self.doctype, | doctype = self.doctype, | ||||
title_field = self.website.page_title_field or "name", | title_field = self.website.page_title_field or "name", | ||||
order_by = self.website.order_by or "idx asc" | |||||
order_by = self.website.order_by or "idx asc", | |||||
condition = condition | |||||
), route, as_dict=True) | ), route, as_dict=True) | ||||
for c in children: | for c in children: | ||||