forked from zaclys/searxng
Merge pull request #848 from not-my-profile/help-route
Introduce `/help` route
This commit is contained in:
commit
bf987bb608
|
@ -1,4 +1,4 @@
|
||||||
# About [searxng][url_for:index]
|
# About SearXNG
|
||||||
|
|
||||||
SearXNG is a fork from the well-known [searx] [metasearch engine], aggregating
|
SearXNG is a fork from the well-known [searx] [metasearch engine], aggregating
|
||||||
the results of other [search engines][url_for:preferences] while not storing
|
the results of other [search engines][url_for:preferences] while not storing
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -221,6 +221,16 @@ div.selectable_url {
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.tabs {
|
||||||
|
border-bottom: 1px solid var(--color-toolkit-tabs-section-border);
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -235,7 +245,8 @@ div.selectable_url {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > label {
|
& > label,
|
||||||
|
& > li > a {
|
||||||
order: 1;
|
order: 1;
|
||||||
padding: 0.7em;
|
padding: 0.7em;
|
||||||
margin: 0 0.7em;
|
margin: 0 0.7em;
|
||||||
|
@ -243,13 +254,21 @@ div.selectable_url {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
border: solid var(--color-toolkit-tabs-label-border);
|
border: solid var(--color-toolkit-tabs-label-border);
|
||||||
border-width: 0 0 2px 0;
|
border-width: 0 0 2px 0;
|
||||||
|
color: unset;
|
||||||
|
|
||||||
.disable-user-select();
|
.disable-user-select();
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-bottom: 2px solid var(--color-categories-item-border-selected);
|
||||||
|
background: var(--color-categories-item-selected);
|
||||||
|
color: var(--color-categories-item-selected-font);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& > label:hover {
|
& > label:hover,
|
||||||
|
& > li > a:hover {
|
||||||
border-bottom: 2px solid var(--color-categories-item-border-selected);
|
border-bottom: 2px solid var(--color-categories-item-border-selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% extends "oscar/base.html" %}
|
|
||||||
{% block title %}{{ _('about') }} - {% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{{ help.about | safe }}
|
|
||||||
{% include "__common__/aboutextend.html" ignore missing %}
|
|
||||||
{% endblock %}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "oscar/base.html" %}
|
||||||
|
{% block title %}{{ page.title }} - {% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
{% for name, page in all_pages %}
|
||||||
|
<li {% if name == page_filename %}class="active"{% endif %}>
|
||||||
|
<a href="{{name}}">{{page.title}}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{{ page.content | safe }}
|
||||||
|
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
||||||
<a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}}
|
<a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}}
|
||||||
</span>{{- "" -}}
|
</span>{{- "" -}}
|
||||||
<span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}}
|
<span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}}
|
||||||
<a href="{{ url_for('about') }}">{{ _('about') }}</a>{{- "" -}}
|
<a href="{{ url_for('help_page', pagename='about') }}">{{ _('about') }}</a>{{- "" -}}
|
||||||
<a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}}
|
<a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}}
|
||||||
</span>{{- "" -}}
|
</span>{{- "" -}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{% extends 'simple/page_with_header.html' %}
|
|
||||||
{% block content %}
|
|
||||||
{{ help.about | safe }}
|
|
||||||
{% include "__common__/aboutextend.html" ignore missing %}
|
|
||||||
{% endblock %}
|
|
|
@ -58,7 +58,7 @@
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p>
|
<p>
|
||||||
{{ _('Powered by') }} <a href="{{ url_for('about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, hackable metasearch engine') }}<br/>
|
{{ _('Powered by') }} <a href="{{ url_for('help_page', pagename='about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, hackable metasearch engine') }}<br/>
|
||||||
<a href="{{ searx_git_url }}">{{ _('Source code') }}</a> |
|
<a href="{{ searx_git_url }}">{{ _('Source code') }}</a> |
|
||||||
<a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a> |
|
<a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a> |
|
||||||
<a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a> |
|
<a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a> |
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends 'simple/page_with_header.html' %}
|
||||||
|
{% block title %}{{ page.title }} - {% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<ul class="tabs">
|
||||||
|
{% for name, page in all_pages %}
|
||||||
|
<li>
|
||||||
|
<a href="{{name}}" {% if name == page_filename %}class="active"{% endif %}>{{page.title}}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{{ page.content | safe }}
|
||||||
|
{% endblock %}
|
|
@ -1,5 +1,5 @@
|
||||||
from typing import Dict
|
# pyright: basic
|
||||||
import os.path
|
from typing import Dict, NamedTuple
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
@ -9,8 +9,17 @@ import mistletoe
|
||||||
from . import get_setting
|
from . import get_setting
|
||||||
from .version import GIT_URL
|
from .version import GIT_URL
|
||||||
|
|
||||||
HELP: Dict[str, str] = {}
|
|
||||||
""" Maps a filename under help/ without the file extension to the rendered HTML. """
|
class HelpPage(NamedTuple):
|
||||||
|
title: str
|
||||||
|
content: str
|
||||||
|
|
||||||
|
|
||||||
|
# Whenever a new .md file is added to help/ it needs to be added here
|
||||||
|
_TOC = ('about',)
|
||||||
|
|
||||||
|
PAGES: Dict[str, HelpPage] = {}
|
||||||
|
""" Maps a filename under help/ without the file extension to the rendered page. """
|
||||||
|
|
||||||
|
|
||||||
def render(app: flask.Flask):
|
def render(app: flask.Flask):
|
||||||
|
@ -37,12 +46,16 @@ def render(app: flask.Flask):
|
||||||
|
|
||||||
define_link_targets = ''.join(f'[{name}]: {url}\n' for name, url in link_targets.items())
|
define_link_targets = ''.join(f'[{name}]: {url}\n' for name, url in link_targets.items())
|
||||||
|
|
||||||
for filename in pkg_resources.resource_listdir(__name__, 'help'):
|
for pagename in _TOC:
|
||||||
rootname, ext = os.path.splitext(filename)
|
file_content = pkg_resources.resource_string(__name__, 'help/' + pagename + '.md').decode()
|
||||||
|
markdown = define_link_targets + file_content
|
||||||
|
assert file_content.startswith('# ')
|
||||||
|
title = file_content.split('\n', maxsplit=1)[0].strip('# ')
|
||||||
|
content: str = mistletoe.markdown(markdown)
|
||||||
|
|
||||||
if ext != '.md':
|
if pagename == 'about':
|
||||||
continue
|
try:
|
||||||
|
content += pkg_resources.resource_string(__name__, 'templates/__common__/aboutextend.html').decode()
|
||||||
markdown = pkg_resources.resource_string(__name__, 'help/' + filename).decode()
|
except FileNotFoundError:
|
||||||
markdown = define_link_targets + markdown
|
pass
|
||||||
HELP[rootname] = mistletoe.markdown(markdown)
|
PAGES[pagename] = HelpPage(title=title, content=content)
|
||||||
|
|
|
@ -877,8 +877,21 @@ def __get_translated_errors(unresponsive_engines: Iterable[UnresponsiveEngine]):
|
||||||
|
|
||||||
@app.route('/about', methods=['GET'])
|
@app.route('/about', methods=['GET'])
|
||||||
def about():
|
def about():
|
||||||
"""Render about page"""
|
"""Redirect to about page"""
|
||||||
return render('about.html', help=user_help.HELP)
|
return redirect(url_for('help_page', pagename='about'))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/help/en/<pagename>', methods=['GET'])
|
||||||
|
def help_page(pagename):
|
||||||
|
"""Render help page"""
|
||||||
|
page = user_help.PAGES.get(pagename)
|
||||||
|
|
||||||
|
if page is None:
|
||||||
|
flask.abort(404)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
'help.html', page=user_help.PAGES[pagename], all_pages=user_help.PAGES.items(), page_filename=pagename
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/autocompleter', methods=['GET', 'POST'])
|
@app.route('/autocompleter', methods=['GET', 'POST'])
|
||||||
|
|
|
@ -174,9 +174,9 @@ class ViewsTestCase(SearxTestCase):
|
||||||
self.assertIn(b'<description>first test content</description>', result.data)
|
self.assertIn(b'<description>first test content</description>', result.data)
|
||||||
|
|
||||||
def test_about(self):
|
def test_about(self):
|
||||||
result = self.app.get('/about')
|
result = self.app.get('/help/en/about')
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
self.assertIn(b'<h1>About <a href="/">searxng</a></h1>', result.data)
|
self.assertIn(b'<h1>About SearXNG</h1>', result.data)
|
||||||
|
|
||||||
def test_health(self):
|
def test_health(self):
|
||||||
result = self.app.get('/healthz')
|
result = self.app.get('/healthz')
|
||||||
|
|
Loading…
Reference in New Issue