class LinkBar(Widget): '''A bar which contains links to other pages. ''' # These icons are referenced from the style sheet. styleRoot.addIcon('IconNew') styleRoot.addIcon('IconEdit') styleRoot.addIcon('IconDelete') __iconModifierStyle = { IconModifier.NEW: 'newicon', IconModifier.EDIT: 'editicon', IconModifier.DELETE: 'delicon', } __levelSep = xhtml.div(class_='level')['\u25B8'] def __presentLinkButton(self, button: LinkBarButton, **kwargs: object) -> XMLNode: iconStyle = ['navicon'] iconModifier = button.modifier if iconModifier is not IconModifier.NONE: iconStyle.append(self.__iconModifierStyle[button.modifier]) return xhtml.div(class_='navthis' if button.active else None)[xhtml.a( href=button.url)[xhtml.span( class_=' '.join(iconStyle))[button.icon.present(**kwargs)], xhtml.span(class_='navlabel')[button.label]]] def __presentButtons(self, **kwargs: object) -> XMLContent: rootButtons = cast(Sequence[LinkBarButton], kwargs['rootButtons']) childButtons = cast(Sequence[LinkBarButton], kwargs['childButtons']) levelSep = self.__levelSep # Root path. for button in rootButtons: presentation = self.__presentLinkButton(button, **kwargs) isParent = not button.active if isParent or childButtons: presentation = presentation.addClass('rootpath') yield presentation if isParent: yield levelSep # Children. if childButtons: yield levelSep for button in childButtons: yield self.__presentLinkButton(button, **kwargs) def present(self, **kwargs: object) -> XMLContent: return xhtml.div(class_='linkbar')[self.__presentButtons(**kwargs)]
def __processPage(cls, name: str, parents: Sequence[str] = ()) -> None: baseModule = cls.__module__.split('.')[:-1] fullName = '.'.join(baseModule + [name]) if fullName not in sys.modules: __import__(fullName) module = sys.modules[fullName] pageClass = getattr(module, name + '_GET') description = pageClass.description linkDescription = pageClass.linkDescription if linkDescription is None: linkDescription = pageClass.description # TODO: Maybe it's easier to just store the class reference? cls.__pageInfo[name] = { 'parents': parents, 'icon': None if pageClass.icon is None else styleRoot.addIcon(pageClass.icon), 'iconModifier': pageClass.iconModifier, 'description': description, 'linkDescription': linkDescription, 'isActive': pageClass.isActive, 'parameters': frozenset(pageClass.Arguments.iterMandatoryArgs()), 'pageClass': pageClass, } parentsInc = tuple(parents) + (name, ) for child in pageClass.children: cls.__processPage(child, parentsInc)
def iterRootButtons(self, args: Optional[Arguments]) -> Iterator[LinkBarButton]: parents: List[LinkBarButton] = [] resource: Optional[DocResource] = self.resource url = '' while resource is not None: parents.append(resource.page.createLinkBarButton(url)) resource = resource.parent url += '../' yield LinkBarButton(label='Home', url=url + 'Home', icon=styleRoot.addIcon('IconHome')) yield from reversed(parents)
def renderIcon(self, arg: str) -> XMLContent: # Parse arguments. iconStyle = ['navicon'] args = arg.split() if len(args) == 1: icon, = args elif len(args) == 2: icon, modifier = args iconStyle.append(modifier + 'icon') else: raise ValueError(arg) # Determine relative URL to style resources. depth = 0 resource: Optional[DocResource] = self.resource while resource is not None: resource = resource.parent depth += 1 styleURL = '../' * depth + styleRoot.relativeURL # Render. yield xhtml.span( class_=' '.join(iconStyle))[styleRoot.addIcon(icon).present( styleURL=styleURL)]
# SPDX-License-Identifier: BSD-3-Clause from traceback import TracebackException from typing import Generic, Iterable, Iterator, Optional, cast from softfab.Page import ProcT, Responder, logPageException from softfab.StyleResources import styleRoot from softfab.pagelinks import createUserDetailsLink, loginURL, logoutURL from softfab.request import Request from softfab.response import Response, ResponseHeaders from softfab.timelib import getTime from softfab.timeview import formatTime from softfab.version import VERSION from softfab.xmlgen import XML, XMLContent, XMLNode, XMLPresentable, xhtml _logoIcon = styleRoot.addIcon('SoftFabLogo') _shortcutIcon = styleRoot.addShortcutIcon('SoftFabIcon') factoryStyleSheet = styleRoot.addStyleSheet('sw-factory') fixedHeadItems: Iterable[XMLPresentable] = ( xhtml.meta(charset='UTF-8'), factoryStyleSheet, xhtml.meta(name='viewport', content='width=device-width, initial-scale=1, minimum-scale=1'), _shortcutIcon) class UIResponder(Responder, Generic[ProcT]): def __init__(self, page: 'UIPage[ProcT]', proc: ProcT): super().__init__() self.page = page
for task in tasks: statusFreq[getTaskStatus(task)] += 1 def iterBars() -> Iterator[XMLContent]: for status in statusList: freq = statusFreq[status] if freq != 0: yield xhtml.td( style=f'width:{100 * freq // len(tasks):d}%', class_=status)[str(freq)] return xhtml.table( class_='statusmany')[xhtml.tbody[xhtml.tr[iterBars()]]] _scheduleIcon = styleRoot.addIcon('ScheduleSmall') _scheduleIconGray = styleRoot.addIcon('ScheduleSmallD') class _DescriptionColumn(DataColumn[Job]): keyName = 'description' def presentCell(self, record: Job, **kwargs: object) -> XMLContent: table = cast(JobsTable, kwargs['table']) if table.descriptionLink: yield xhtml.a(href=createJobURL( record.getId()), )[record.getDescription()] else: yield record.getDescription() scheduleDB: ScheduleDB = getattr(kwargs['proc'], 'scheduleDB')
def createLinkBarButton(self, url: str) -> LinkBarButton: return LinkBarButton(label=self.metadata.button, url=url, icon=styleRoot.addIcon(self.metadata.icon), active=not url)
def presentLabel(label: str) -> str: """Compute a good-looking tab label from the technical label. """ root, ext_ = splitext(label) if root: # Note: Don't use the title() method, since that will capitalize the # first letter in a word even if it is preceded by non-letters. return ' '.join(word[0].upper() + word[1:] for word in reLabelSplit.split(root)) else: return '(empty)' openInNewTabIcon = styleRoot.addIcon('OpenInNewTab') class Task_GET(FabPage['Task_GET.Processor', 'Task_GET.Arguments']): icon = 'IconReport' description = 'Task' class Arguments(TaskReportArgs): pass class Processor(TaskProcessorMixin, PageProcessor[Arguments]): frameworkDB: ClassVar[FrameworkDB] taskDefDB: ClassVar[TaskDefDB] taskRunDB: ClassVar[TaskRunDB] userDB: ClassVar[UserDB]