def iterRows(self, **kwargs: Any) -> Iterator[XMLContent]: tokens: Iterator[Tuple[TokenType, str]] = kwargs['tokens'] lineNo = 1 nodes: List[XMLContent] = [] for node in _splitLines(tokens): if node == '\n': yield (xhtml.a(id=f'L{lineNo}'), xhtml.a(href=f'#L{lineNo}')[lineNo]), nodes lineNo += 1 nodes = [] else: nodes.append(node) if nodes: yield lineNo, nodes
def iterOptions(self, **kwargs: object) -> Iterator[Sequence[XMLContent]]: yield EmbeddingPolicy.NONE, 'Never' yield EmbeddingPolicy.SELF, 'Same site only' yield EmbeddingPolicy.CUSTOM, 'Custom: ', ( textInput( name='embedcustom', size=69, # The onchange event handler is there to make sure the right # radio button is activated when text is pasted into the edit # box from the context menu (right mouse button). onchange=f"form['{self.name}'][2].checked=true"), xhtml.br, 'You can enter one or more site filters, ' 'such as ', xhtml.code['https://*.example.com'], xhtml.br, 'This is used as a ', xhtml.code['frame-ancestors'], ' rule ' 'in the ', xhtml.code['Content-Security-Policy'], ' header; ', xhtml.a(href='https://developer.mozilla.org/en-US/docs' '/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors' )['full documentation at MDN'], )
def present(self, **kwargs: object) -> XMLNode: node = xhtml.a(**self._attributes)[ self._presentContents(**kwargs) ] ccURL = cast(Optional[str], kwargs.get('ccURL')) if ccURL is None: return node else: return node(href=ccURL + node.attrs['href'])
def presentContent(self, **kwargs: object) -> XMLContent: yield ResourcesTable.instance.present(**kwargs) yield xhtml.p['For help about resources read this section of the ', docLink('/start/user_manual/#resources')['User Manual'], '.'] yield xhtml.p['Download the ', xhtml.a(href='taskrunner.jar')['Task Runner JAR'], '.']
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(BatchExecute_GET.Processor, kwargs['proc']) for notice in proc.notices: yield xhtml.p(class_='notice')[notice] configs = proc.configs if configs: yield xhtml.h3['Selected configurations:'] yield BatchConfigTable.instance.present(**kwargs) taskSet = proc.taskSet if taskSet is None: yield xhtml.p['Cannot execute because of conflict.'] else: yield makeForm(args=ParentArgs.subset(proc.args))[ BatchInputTable.instance, submitButtons, decoration[ xhtml.hr, ParamTable.instance, # Second set of submit buttons after parameter tables. submitButtons], (hiddenInput(name=f'config.{i:d}', value=cfg.getId()) for i, cfg in enumerate(configs)), ].present( taskSet=taskSet, **kwargs) return else: yield xhtml.h3['No configurations selected'] yield xhtml.p[xhtml.a( href=proc.args.refererURL or parentPage)['Back to Configurations']]
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(ConfigTagsBase.Processor[ArgsT], kwargs['proc']) for notice in proc.notices: yield xhtml.p(class_='notice')[notice] configs = proc.configs if configs: yield xhtml.h3['Selected Configurations:'] yield TagConfigTable.instance.present(**kwargs) yield xhtml.h3['Common Selection Tags:'] tagKeys = proc.project.getTagKeys() commonTags = getCommonTags(tagKeys, (config.tags for config in configs)) yield makeForm(args=ParentArgs.subset(proc.args).override( sel={config.getId() for config in configs} ))[ConfigTagValueEditTable.instance, xhtml.p[actionButtons(Actions)], (hiddenInput(name=f'commontags.{index:d}', value=tagName) for index, tagKey in enumerate(tagKeys) for tagName in commonTags[tagKey])].present( getValues=lambda key: valuesToText(commonTags[key]), **kwargs) else: yield (xhtml.h3['No configurations selected'], xhtml.p[xhtml.a(href=proc.args.refererURL or parentPage) ['Back to Configurations']])
def pageLink( page: str, args: Optional[PageArgs] = None, **kwargs: str ) -> XMLNode: '''Creates a hyperlink to another page. ''' return xhtml.a(href=pageURL(page, args, **kwargs))
def renderTableOfContents(self, arg: str) -> XMLContent: if arg: raise ValueError('"toc" does not take any arguments') yield xhtml.h2['Table of Contents'] yield xhtml.dl(class_='toc')[((xhtml.dt[xhtml.a( href=url)[extracted.title]], extracted.abstract) for url, extracted in self.__toc)]
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(ConfigTags_POST.Processor, kwargs['proc']) if proc.notices: yield super().presentContent(**kwargs) else: yield xhtml.p['The tags have been updated successfully.'] yield xhtml.p[xhtml.a(href=proc.args.refererURL or parentPage) ['Back to Configurations']]
def backToReferer(self, args: ArgsT) -> XMLNode: refererName = args.refererName if refererName is None: # No referer, fall back to page hierarchy. return self.backToParent(args) return xhtml.p[xhtml.a(href=args.refererURL)[ 'Back to ', self.getPageInfo(refererName)['description']]]
def presentSubcommands(ctx: Context, parent: MultiCommand) -> Iterator[XMLContent]: prefix = ''.join(f'{word}-' for word in rootPath(ctx.parent, parent)) yield xhtml.dl[(xhtml.dt[xhtml.code[xhtml.a( href=f'#{prefix}{command.name}')[command.name]]] + xhtml.dd[command.get_short_help_str(limit=1000)] for command in iterCommands(ctx, parent))] for command in iterCommands(ctx, parent): yield from presentCommand(ctx, command)
def formatLocator(product: Product, locator: Optional[str], finishedTask: bool) -> XMLContent: if locator is None: return 'unavailable' if finishedTask else 'not yet' elif product.getType() is ProductType.URL: return xhtml.a(href=locator)[locator] elif product.getType() is ProductType.TOKEN: return 'token was produced' else: return locator
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') scheduleId = record.getScheduledBy() if scheduleId is not None: schedule = scheduleDB.get(scheduleId) if schedule is None: icon = _scheduleIconGray url = None else: icon = _scheduleIcon url = createScheduleDetailsURL(scheduleId) yield xhtml.a(href=url, title=scheduleId, class_='jobicon')[icon.present(**kwargs)]
def createCell(taskName: Optional[str], tasks: Optional[Sequence[Task]], beginTime: int, endTime: int) -> XMLContent: if tasks is None: return '' bar = createStatusBar(tasks, length=0) if taskName is None: return bar url = makeURL(taskName, beginTime, endTime) return cell(onclick=f"document.location='{url}'")[xhtml.a( href=url)[bar]]
def maybeLink(url: Optional[str]) -> XMLSubscriptable: '''Creates a hyperlink if the URL is not None, otherwise returns the label as an XML tree. ''' # Note: Use an "if" statement because mypy doesn't combine the types # in the way we need when a conditional expression is used. # https://github.com/python/mypy/issues/5392 if url is None: return xhtml else: return xhtml.a(href = url)
def presentHeader(self, **kwargs: object) -> XMLContent: proc = cast(ProcT, kwargs['proc']) ccURL = cast(str, kwargs['ccURL']) userName = proc.user.name return xhtml.div(class_='titlebar')[ xhtml.div(class_='title')[self.__title(proc)], xhtml.div(class_='info')[xhtml.a( href=ccURL + self.loginURL(**kwargs))['log in'] if userName is None else (createUserDetailsLink(userName).present( **kwargs), ' \u2013 ', xhtml.a(href=ccURL + logoutURL(proc.req))['log out']), xhtml.br, formatTime(getTime())], xhtml.div( class_='logo' )[xhtml.a(href=ccURL + 'About', title=f'SoftFab {VERSION}')[_logoIcon.present( **kwargs)]]]
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 presentContent(self, **kwargs: object) -> XMLContent: proc = cast(AddUser_POST.Processor, kwargs['proc']) yield xhtml.p[ xhtml.b[ f'User "{proc.args.user}" has been added successfully.' ] ] yield presentSetPasswordURL(proc.args.user, proc.token) yield xhtml.hr yield xhtml.p[ 'You can use the form below to add another user, or ', xhtml.a(href = self.getCancelURL(proc.args))[ 'go back to the users overview page' ], '.' ] yield self.presentForm(RoleArgs(role=UIRoleNames.USER), **kwargs)
def presentCommand(ctx: Context, command: Command) -> Iterator[XMLContent]: options = [] arguments = [] for param in command.params: if isinstance(param, Option): options.append(param) elif isinstance(param, Argument): arguments.append(param) words = rootPath(ctx, command) title: List[XMLContent] = ['softfab'] title += words title += [presentParameter(arg) for arg in arguments] yield xhtml.h3[xhtml.code[xhtml[' '].join(title)], xhtml.a(id='-'.join(words))] yield from presentHelpBlocks(command) yield presentOptions(ctx, options) if isinstance(command, MultiCommand): yield from presentSubcommands(Context(command, ctx), command)
def presentContent(self, **kwargs: object) -> XMLContent: descriptions: Sequence[Tuple[str, str, XMLContent]] = ( ('Project', 'ProjectEdit', 'Change overall settings, such as the project name ' 'and the list of targets.'), ('Design', 'Design', 'Model the build and test process of your project: ' 'define products, frameworks, tasks and resources.'), ('Users', 'UserList', 'Add new users, change user passwords or ' 'change user roles.'), ('Notifications', 'Notifications', 'Configure ways to stay informed of the current status ' 'of your project.'), ('About', 'About', 'Look up version information of your SoftFab installation ' 'and web browser.'), ) return xhtml.dl(class_='toc')[((xhtml.dt[xhtml.a(href=url)[name]], xhtml.dd[descr]) for name, url, descr in descriptions)]
def presentContent(self, **kwargs: object) -> XMLContent: yield xhtml.p['Password set successfully.'] yield xhtml.p['You can now ', xhtml.a(href=self.loginURL(**kwargs))['log in'], ' with your new password.']
def iterRows(self, **kwargs: object) -> Iterator[XMLContent]: proc = cast(TaskMatrix_GET.Processor, kwargs['proc']) configId = proc.args.config beginWeek = proc.beginWeek endWeek = proc.endWeek taskData = proc.taskData tasksByName = proc.tasksByName tasksByDay = proc.tasksByDay allTasks = proc.allTasks # Show names for task runs that were created in the selected week. taskNames = set(tasksByName) # Add names of tasks in the filtered configuration, to make it explicit # when they didn't run. if configId: try: config = proc.configDB[configId] except KeyError: pass else: taskNames.update(config.iterTaskNames()) def makeURL(taskName: str, beginTime: int, endTime: int) -> str: if taskName is None: # TODO: The links which match all tasks are currently disabled, # but are also no longer accepted by ReportTasks. taskName = '*' return pageURL( 'ReportTasks', ReportTaskArgs(task=[taskName], ctabove=beginTime, ctbelow=endTime)) def createCell(taskName: Optional[str], tasks: Optional[Sequence[Task]], beginTime: int, endTime: int) -> XMLContent: if tasks is None: return '' bar = createStatusBar(tasks, length=0) if taskName is None: return bar url = makeURL(taskName, beginTime, endTime) return cell(onclick=f"document.location='{url}'")[xhtml.a( href=url)[bar]] def iterCells( taskName: Optional[str], rowHeader: XMLContent, weekTasks: Iterable[Optional[Sequence[Task]]], totalTasks: Optional[Sequence[Task]]) -> Iterator[XMLContent]: # pylint: disable=stop-iteration-return # https://github.com/PyCQA/pylint/issues/2158 yield rowHeader dayStartGen = iterDays(beginWeek) todayStart = next(dayStartGen) for tasks in weekTasks: tomorrowStart = next(dayStartGen) yield createCell(taskName, tasks, todayStart, tomorrowStart) todayStart = tomorrowStart yield cell(class_='rightalign')[str(len(totalTasks) ) if totalTasks else ''] yield createCell(taskName, totalTasks, beginWeek, endWeek) if len(taskNames) == 0: yield iterCells(None, xhtml.i['No Tasks'], tasksByDay, allTasks) else: for taskName in sorted(taskNames): yield iterCells( taskName, xhtml.a( href=makeURL(taskName, beginWeek, endWeek))[taskName], (taskDict.get(taskName) for taskDict in taskData), tasksByName.get(taskName)) def presentTotals() -> Iterator[XMLContent]: yield xhtml.b['Total'] for tasks in tasksByDay: yield cell( class_='rightalign')[str(len(tasks)) if tasks else ''] yield '' yield '' yield presentTotals() yield iterCells(None, xhtml.b['All Tasks'], tasksByDay, allTasks)
def linkTab(tab: int, text: str) -> XMLNode: return xhtml.td(class_='navother')[xhtml.a(href=pageURL( proc.page.name, proc.args.override(**{tabOffsetField: tab * recordsPerPage})), class_='nav')[text]]
def presentLink( self, # pylint: disable=unused-argument record: DBRecord, **kwargs: object) -> XMLSubscriptable: return xhtml.a(href=self.__urlBase + escapeURL(record.getId()))
def presentContent(self, **kwargs: object) -> XMLContent: return ( xhtml.p[ 'The page you requested was not found on this server.' ], xhtml.p[ xhtml.a(href = 'Home')[ 'Back to Home' ] ] )
def __presentFooter(self, proc: PageProcessor, name: str) -> XMLContent: return xhtml.div(class_='export')['export: ', xhtml[', '].join( xhtml.a( href=proc.subItemRelURL(f'{name}.{fmt.ext}'), title=fmt.description, )[fmt.ext] for fmt in GraphFormat)]
def backToSelf(self) -> XMLNode: url = self.name return xhtml.p[xhtml.a(href=url)['Back to ', self.description]]
def backToParent(self, args: Optional[ArgsT]) -> XMLNode: parentName = self.getPageInfo()['parents'][-1] parentURL = self.getPageURL(parentName, args) return xhtml.p[xhtml.a( href=parentURL)['Back to ', self.getPageInfo(parentName)['description']]]
def docLink(path: str) -> XMLNode: '''Creates a hyperlink to a documentation page. ''' assert path.startswith('/'), path return xhtml.a(href='docs' + path, target='_blank')