introduce breadcrumbs in the web config
This commit is contained in:
parent
1968e15237
commit
e8cf014903
@ -151,4 +151,8 @@ h1 {
|
|||||||
|
|
||||||
.scheduler-static-time-inputs > select {
|
.scheduler-static-time-inputs > select {
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
margin-top: .5rem;
|
||||||
}
|
}
|
@ -10,6 +10,7 @@
|
|||||||
</HEAD><BODY>
|
</HEAD><BODY>
|
||||||
${header}
|
${header}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
${breadcrumb}
|
||||||
<h1>OpenWebRX Feature Report</h1>
|
<h1>OpenWebRX Feature Report</h1>
|
||||||
<table class="features table">
|
<table class="features table">
|
||||||
<tr>
|
<tr>
|
||||||
@ -19,5 +20,6 @@
|
|||||||
<th>Available</th>
|
<th>Available</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
${breadcrumb}
|
||||||
</div>
|
</div>
|
||||||
</BODY></HTML>
|
</BODY></HTML>
|
@ -13,8 +13,7 @@ $(function(){
|
|||||||
});
|
});
|
||||||
$table.append(
|
$table.append(
|
||||||
'<tr>' +
|
'<tr>' +
|
||||||
'<td colspan=2>' + name + '</td>' +
|
'<td colspan=3>' + name + '</td>' +
|
||||||
'<td>' + converter.makeHtml(details.description) + '</td>' +
|
|
||||||
'<td>' + (details.available ? 'YES' : 'NO') + '</td>' +
|
'<td>' + (details.available ? 'YES' : 'NO') + '</td>' +
|
||||||
'</tr>' +
|
'</tr>' +
|
||||||
requirements.join("")
|
requirements.join("")
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<body>
|
<body>
|
||||||
${header}
|
${header}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
${breadcrumb}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col-12">Bookmarks</h1>
|
<h1 class="col-12">Bookmarks</h1>
|
||||||
</div>
|
</div>
|
||||||
@ -24,6 +25,7 @@ ${header}
|
|||||||
<button type="button" class="btn btn-primary bookmark-add">Add a new bookmark</button>
|
<button type="button" class="btn btn-primary bookmark-add">Add a new bookmark</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
${breadcrumb}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal" id="deleteModal" tabindex="-1" role="dialog">
|
<div class="modal" id="deleteModal" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
|
@ -11,10 +11,12 @@
|
|||||||
<body>
|
<body>
|
||||||
${header}
|
${header}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
${breadcrumb}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col-12">${title}</h1>
|
<h1 class="col-12">${title}</h1>
|
||||||
</div>
|
</div>
|
||||||
${content}
|
${content}
|
||||||
|
${breadcrumb}
|
||||||
</div>
|
</div>
|
||||||
${modal}
|
${modal}
|
||||||
</body>
|
</body>
|
42
owrx/breadcrumb.py
Normal file
42
owrx/breadcrumb.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from typing import List
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
|
class BreadcrumbItem(object):
|
||||||
|
def __init__(self, title, href):
|
||||||
|
self.title = title
|
||||||
|
self.href = href
|
||||||
|
|
||||||
|
def render(self, documentRoot):
|
||||||
|
return '<li class="breadcrumb-item"><a href="{documentRoot}{href}">{title}</a></li>'.format(
|
||||||
|
documentRoot=documentRoot, href=self.href, title=self.title
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Breadcrumb(object):
|
||||||
|
def __init__(self, breadcrumbs: List[BreadcrumbItem]):
|
||||||
|
self.items = breadcrumbs
|
||||||
|
|
||||||
|
def render(self, documentRoot):
|
||||||
|
return """
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
{crumbs}
|
||||||
|
</ol>
|
||||||
|
""".format(
|
||||||
|
crumbs="".join(item.render(documentRoot) for item in self.items)
|
||||||
|
)
|
||||||
|
|
||||||
|
def append(self, crumb: BreadcrumbItem):
|
||||||
|
self.items.append(crumb)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class BreadcrumbMixin(ABC):
|
||||||
|
def template_variables(self):
|
||||||
|
variables = super().template_variables()
|
||||||
|
variables["breadcrumb"] = self.get_breadcrumb().render(self.get_document_root())
|
||||||
|
return variables
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
pass
|
11
owrx/controllers/feature.py
Normal file
11
owrx/controllers/feature.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from owrx.controllers.template import WebpageController
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin
|
||||||
|
from owrx.controllers.settings import SettingsBreadcrumb
|
||||||
|
|
||||||
|
|
||||||
|
class FeatureController(BreadcrumbMixin, WebpageController):
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SettingsBreadcrumb().append(BreadcrumbItem("Feature report", "features"))
|
||||||
|
|
||||||
|
def indexAction(self):
|
||||||
|
self.serve_template("features.html", **self.template_variables())
|
@ -2,6 +2,7 @@ from owrx.config import Config
|
|||||||
from owrx.controllers.admin import AuthorizationMixin
|
from owrx.controllers.admin import AuthorizationMixin
|
||||||
from owrx.controllers.template import WebpageController
|
from owrx.controllers.template import WebpageController
|
||||||
from owrx.form.error import FormError
|
from owrx.form.error import FormError
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from urllib.parse import parse_qs
|
from urllib.parse import parse_qs
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ class SettingsController(AuthorizationMixin, WebpageController):
|
|||||||
self.serve_template("settings.html", **self.template_variables())
|
self.serve_template("settings.html", **self.template_variables())
|
||||||
|
|
||||||
|
|
||||||
class SettingsFormController(AuthorizationMixin, WebpageController, metaclass=ABCMeta):
|
class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageController, metaclass=ABCMeta):
|
||||||
def __init__(self, handler, request, options):
|
def __init__(self, handler, request, options):
|
||||||
super().__init__(handler, request, options)
|
super().__init__(handler, request, options)
|
||||||
self.errors = {}
|
self.errors = {}
|
||||||
@ -144,3 +145,9 @@ class SettingsFormController(AuthorizationMixin, WebpageController, metaclass=AB
|
|||||||
|
|
||||||
def buildModal(self):
|
def buildModal(self):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsBreadcrumb(Breadcrumb):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__([])
|
||||||
|
self.append(BreadcrumbItem("Settings", "settings"))
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
from owrx.controllers.settings import SettingsFormController, Section
|
from owrx.controllers.settings import SettingsFormController, Section
|
||||||
from owrx.form import CheckboxInput, ServicesCheckboxInput
|
from owrx.form import CheckboxInput, ServicesCheckboxInput
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem
|
||||||
|
from owrx.controllers.settings import SettingsBreadcrumb
|
||||||
|
|
||||||
|
|
||||||
class BackgroundDecodingController(SettingsFormController):
|
class BackgroundDecodingController(SettingsFormController):
|
||||||
def getTitle(self):
|
def getTitle(self):
|
||||||
return "Background decoding"
|
return "Background decoding"
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SettingsBreadcrumb().append(BreadcrumbItem("Background decoding", "settings/backgrounddecoding"))
|
||||||
|
|
||||||
def getSections(self):
|
def getSections(self):
|
||||||
return [
|
return [
|
||||||
Section(
|
Section(
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
from owrx.controllers.template import WebpageController
|
from owrx.controllers.template import WebpageController
|
||||||
from owrx.controllers.admin import AuthorizationMixin
|
from owrx.controllers.admin import AuthorizationMixin
|
||||||
|
from owrx.controllers.settings import SettingsBreadcrumb
|
||||||
from owrx.bookmarks import Bookmark, Bookmarks
|
from owrx.bookmarks import Bookmark, Bookmarks
|
||||||
from owrx.modes import Modes
|
from owrx.modes import Modes
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@ -10,7 +12,10 @@ import logging
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BookmarksController(AuthorizationMixin, WebpageController):
|
class BookmarksController(AuthorizationMixin, BreadcrumbMixin, WebpageController):
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SettingsBreadcrumb().append(BreadcrumbItem("Bookmark editor", "settings/bookmarks"))
|
||||||
|
|
||||||
def template_variables(self):
|
def template_variables(self):
|
||||||
variables = super().template_variables()
|
variables = super().template_variables()
|
||||||
variables["bookmarks"] = self.render_table()
|
variables["bookmarks"] = self.render_table()
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
from owrx.controllers.settings import SettingsFormController, Section
|
from owrx.controllers.settings import SettingsFormController, Section, SettingsBreadcrumb
|
||||||
from owrx.form import CheckboxInput, NumberInput, DropdownInput, Js8ProfileCheckboxInput, MultiCheckboxInput, Option
|
from owrx.form import CheckboxInput, NumberInput, DropdownInput, Js8ProfileCheckboxInput, MultiCheckboxInput, Option
|
||||||
from owrx.form.wfm import WfmTauValues
|
from owrx.form.wfm import WfmTauValues
|
||||||
from owrx.form.wsjt import Q65ModeMatrix, WsjtDecodingDepthsInput
|
from owrx.form.wsjt import Q65ModeMatrix, WsjtDecodingDepthsInput
|
||||||
from owrx.wsjt import Fst4Profile, Fst4wProfile
|
from owrx.wsjt import Fst4Profile, Fst4wProfile
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem
|
||||||
|
|
||||||
|
|
||||||
class DecodingSettingsController(SettingsFormController):
|
class DecodingSettingsController(SettingsFormController):
|
||||||
def getTitle(self):
|
def getTitle(self):
|
||||||
return "Demodulation and decoding"
|
return "Demodulation and decoding"
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SettingsBreadcrumb().append(BreadcrumbItem("Demodulation and decoding", "settings/decoding"))
|
||||||
|
|
||||||
def getSections(self):
|
def getSections(self):
|
||||||
return [
|
return [
|
||||||
Section(
|
Section(
|
||||||
|
@ -14,6 +14,8 @@ from owrx.form.receiverid import ReceiverKeysConverter
|
|||||||
from owrx.form.gfx import AvatarInput, TopPhotoInput
|
from owrx.form.gfx import AvatarInput, TopPhotoInput
|
||||||
from owrx.form.device import WaterfallLevelsInput, WaterfallAutoLevelsInput
|
from owrx.form.device import WaterfallLevelsInput, WaterfallAutoLevelsInput
|
||||||
from owrx.waterfall import WaterfallOptions
|
from owrx.waterfall import WaterfallOptions
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem
|
||||||
|
from owrx.controllers.settings import SettingsBreadcrumb
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
from glob import glob
|
from glob import glob
|
||||||
@ -27,6 +29,9 @@ class GeneralSettingsController(SettingsFormController):
|
|||||||
def getTitle(self):
|
def getTitle(self):
|
||||||
return "General Settings"
|
return "General Settings"
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SettingsBreadcrumb().append(BreadcrumbItem("General Settings", "settings/general"))
|
||||||
|
|
||||||
def getSections(self):
|
def getSections(self):
|
||||||
return [
|
return [
|
||||||
Section(
|
Section(
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
from owrx.controllers.settings import SettingsFormController, Section
|
from owrx.controllers.settings import SettingsFormController, Section, SettingsBreadcrumb
|
||||||
from owrx.form.converter import OptionalConverter
|
from owrx.form.converter import OptionalConverter
|
||||||
from owrx.form.aprs import AprsBeaconSymbols, AprsAntennaDirections
|
from owrx.form.aprs import AprsBeaconSymbols, AprsAntennaDirections
|
||||||
from owrx.form import TextInput, CheckboxInput, DropdownInput, NumberInput
|
from owrx.form import TextInput, CheckboxInput, DropdownInput, NumberInput
|
||||||
|
from owrx.breadcrumb import Breadcrumb, BreadcrumbItem
|
||||||
|
|
||||||
|
|
||||||
class ReportingController(SettingsFormController):
|
class ReportingController(SettingsFormController):
|
||||||
def getTitle(self):
|
def getTitle(self):
|
||||||
return "Spotting and Reporting"
|
return "Spotting and reporting"
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SettingsBreadcrumb().append(BreadcrumbItem("Spotting and reporting", "settings/reporting"))
|
||||||
|
|
||||||
def getSections(self):
|
def getSections(self):
|
||||||
return [
|
return [
|
||||||
|
@ -4,16 +4,23 @@ from owrx.controllers.settings import SettingsFormController
|
|||||||
from owrx.source import SdrDeviceDescription, SdrDeviceDescriptionMissing, SdrClientClass
|
from owrx.source import SdrDeviceDescription, SdrDeviceDescriptionMissing, SdrClientClass
|
||||||
from owrx.config import Config
|
from owrx.config import Config
|
||||||
from owrx.connection import OpenWebRxReceiverClient
|
from owrx.connection import OpenWebRxReceiverClient
|
||||||
from owrx.controllers.settings import Section
|
from owrx.controllers.settings import Section, SettingsBreadcrumb
|
||||||
from urllib.parse import quote, unquote
|
from urllib.parse import quote, unquote
|
||||||
from owrx.sdr import SdrService
|
from owrx.sdr import SdrService
|
||||||
from owrx.form import TextInput, DropdownInput, Option
|
from owrx.form import TextInput, DropdownInput, Option
|
||||||
from owrx.form.validator import RequiredValidator
|
from owrx.form.validator import RequiredValidator
|
||||||
from owrx.property import PropertyLayer, PropertyStack
|
from owrx.property import PropertyLayer, PropertyStack
|
||||||
|
from owrx.breadcrumb import BreadcrumbMixin, Breadcrumb, BreadcrumbItem
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
class SdrDeviceListController(AuthorizationMixin, WebpageController):
|
class SdrDeviceBreadcrumb(SettingsBreadcrumb):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.append(BreadcrumbItem("SDR device settings", "settings/sdr"))
|
||||||
|
|
||||||
|
|
||||||
|
class SdrDeviceListController(AuthorizationMixin, BreadcrumbMixin, WebpageController):
|
||||||
def template_variables(self):
|
def template_variables(self):
|
||||||
variables = super().template_variables()
|
variables = super().template_variables()
|
||||||
variables["content"] = self.render_devices()
|
variables["content"] = self.render_devices()
|
||||||
@ -21,6 +28,9 @@ class SdrDeviceListController(AuthorizationMixin, WebpageController):
|
|||||||
variables["modal"] = ""
|
variables["modal"] = ""
|
||||||
return variables
|
return variables
|
||||||
|
|
||||||
|
def get_breadcrumb(self):
|
||||||
|
return SdrDeviceBreadcrumb()
|
||||||
|
|
||||||
def render_devices(self):
|
def render_devices(self):
|
||||||
def render_device(device_id, config):
|
def render_device(device_id, config):
|
||||||
sources = SdrService.getAllSources()
|
sources = SdrService.getAllSources()
|
||||||
@ -213,6 +223,11 @@ class SdrFormControllerWithModal(SdrFormController, metaclass=ABCMeta):
|
|||||||
|
|
||||||
|
|
||||||
class SdrDeviceController(SdrFormControllerWithModal):
|
class SdrDeviceController(SdrFormControllerWithModal):
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SdrDeviceBreadcrumb().append(
|
||||||
|
BreadcrumbItem(self.device["name"], "settings/sdr/{}".format(self.device_id))
|
||||||
|
)
|
||||||
|
|
||||||
def getData(self):
|
def getData(self):
|
||||||
return self.device
|
return self.device
|
||||||
|
|
||||||
@ -271,6 +286,9 @@ class NewSdrDeviceController(SettingsFormController):
|
|||||||
self.stack.addLayer(0, id_layer)
|
self.stack.addLayer(0, id_layer)
|
||||||
self.stack.addLayer(1, self.data_layer)
|
self.stack.addLayer(1, self.data_layer)
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return SdrDeviceBreadcrumb().append(BreadcrumbItem("New device", "settings/sdr/newsdr"))
|
||||||
|
|
||||||
def getSections(self):
|
def getSections(self):
|
||||||
return [
|
return [
|
||||||
Section(
|
Section(
|
||||||
@ -313,6 +331,17 @@ class SdrProfileController(SdrFormControllerWithModal):
|
|||||||
super().__init__(handler, request, options)
|
super().__init__(handler, request, options)
|
||||||
self.profile_id, self.profile = self._get_profile()
|
self.profile_id, self.profile = self._get_profile()
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return (
|
||||||
|
SdrDeviceBreadcrumb()
|
||||||
|
.append(BreadcrumbItem(self.device["name"], "settings/sdr/{}".format(self.device_id)))
|
||||||
|
.append(
|
||||||
|
BreadcrumbItem(
|
||||||
|
self.profile["name"], "settings/sdr/{}/profile/{}".format(self.device_id, self.profile_id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def getData(self):
|
def getData(self):
|
||||||
return self.profile
|
return self.profile
|
||||||
|
|
||||||
@ -378,6 +407,13 @@ class NewProfileController(SdrProfileController):
|
|||||||
self.stack.addLayer(1, id_layer)
|
self.stack.addLayer(1, id_layer)
|
||||||
super().__init__(handler, request, options)
|
super().__init__(handler, request, options)
|
||||||
|
|
||||||
|
def get_breadcrumb(self) -> Breadcrumb:
|
||||||
|
return (
|
||||||
|
SdrDeviceBreadcrumb()
|
||||||
|
.append(BreadcrumbItem(self.device["name"], "settings/sdr/{}".format(self.device_id)))
|
||||||
|
.append(BreadcrumbItem("New profile", "settings/sdr/{}/newprofile".format(self.device_id)))
|
||||||
|
)
|
||||||
|
|
||||||
def _get_profile(self):
|
def _get_profile(self):
|
||||||
return "new", self.stack
|
return "new", self.stack
|
||||||
|
|
||||||
|
@ -43,8 +43,3 @@ class MapController(WebpageController):
|
|||||||
def indexAction(self):
|
def indexAction(self):
|
||||||
# TODO check if we have a google maps api key first?
|
# TODO check if we have a google maps api key first?
|
||||||
self.serve_template("map.html", **self.template_variables())
|
self.serve_template("map.html", **self.template_variables())
|
||||||
|
|
||||||
|
|
||||||
class FeatureController(WebpageController):
|
|
||||||
def indexAction(self):
|
|
||||||
self.serve_template("features.html", **self.template_variables())
|
|
||||||
|
@ -99,7 +99,6 @@ class FeatureDetector(object):
|
|||||||
|
|
||||||
def feature_details(name):
|
def feature_details(name):
|
||||||
return {
|
return {
|
||||||
"description": "",
|
|
||||||
"available": self.is_available(name),
|
"available": self.is_available(name),
|
||||||
"requirements": {name: requirement_details(name) for name in self.get_requirements(name)},
|
"requirements": {name: requirement_details(name) for name in self.get_requirements(name)},
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from owrx.controllers.status import StatusController
|
from owrx.controllers.status import StatusController
|
||||||
from owrx.controllers.template import IndexController, MapController, FeatureController
|
from owrx.controllers.template import IndexController, MapController
|
||||||
|
from owrx.controllers.feature import FeatureController
|
||||||
from owrx.controllers.assets import OwrxAssetsController, AprsSymbolsController, CompiledAssetsController
|
from owrx.controllers.assets import OwrxAssetsController, AprsSymbolsController, CompiledAssetsController
|
||||||
from owrx.controllers.websocket import WebSocketController
|
from owrx.controllers.websocket import WebSocketController
|
||||||
from owrx.controllers.api import ApiController
|
from owrx.controllers.api import ApiController
|
||||||
|
Loading…
Reference in New Issue
Block a user