def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(ProductDetails_GET.Processor, kwargs['proc']) productDefId = proc.args.id producers = proc.producers consumers = proc.consumers numProducers = len(producers) numConsumers = len(consumers) deleteProduct = ( 'Delete this product: ' 'not possible, because it is currently being used by ', str(numProducers), ' ', pluralize('producer', numProducers), ' and ', str(numConsumers), ' ', pluralize('consumer', numConsumers), '.' ) if producers or consumers else pageLink( 'ProductDelete', DeleteArgs(id = productDefId) )[ 'Delete this Product' ] yield xhtml.h3[ 'Details of product ', xhtml.b[ productDefId ], ':' ] yield xhtml.div(class_='hgroup wrap')[ DetailsTable.instance, GraphPanel.instance ].present(graph=proc.graph, **kwargs) yield xhtml.p[ pageLink('ProductEdit', proc.args)[ 'Edit this product' ], xhtml.br, deleteProduct ]
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(FastExecute_GET.Processor, kwargs['proc']) configs = proc.configs tagged = proc.args.configId is None if configs: numJobs = sum(len(config.targets) or 1 for config in configs) yield xhtml.p['Create ', xhtml.b[str(numJobs), ' ', pluralize('job', numJobs)], ' from the ', pluralize('configuration', len(configs)), ' listed below?'] yield makeForm(args=PostArgs( # Args used by 'cancel': RefererArgs.subset(proc.args), # Args used by 'execute': confirmedId=(config.getId() for config in configs )))[xhtml.p[actionButtons(Actions)]].present( **kwargs) yield FastConfigTable.instance.present(**kwargs) elif tagged: yield (xhtml.p['No configuration matches' ' tag key ', xhtml.b[proc.args.tagkey], ' and value ', xhtml.b[proc.args.tagvalue], '.'], self.backToReferer(proc.args)) else: yield (xhtml.p['No configuration named ', xhtml.b[proc.args.configId], ' exists.'], self.backToReferer(proc.args))
def iterLinks(self, proc: Processor) -> Iterable[XMLContent]: yield pageLink('FastExecute', proc.args)[ 'Execute this configuration' ], ' (confirmation only)' configId = proc.args.configId yield pageLink('Execute', config=configId)[ 'Load this configuration' ], ' (provide inputs and parameters)' yield pageLink('ReportIndex', desc=configId)[ 'Show history of this configuration' ] yield pageLink('Execute', config=configId, step='edit')[ 'Edit this configuration' ] if proc.scheduleIds: numSchedules = len(proc.scheduleIds) yield ( 'Delete this configuration: not possible, because it is' ' currently being used by ', str(numSchedules), ' ', pluralize('schedule', numSchedules), '.' ) else: yield pageLink('DelJobConfig', DeleteArgs(id=configId))[ 'Delete this configuration' ]
def fetchRecordForDeletion(proc: RecordDeleteProcessor[DeleteArgsT, DBRecord], recordId: str) -> DBRecord: """Tries to fetch the record with the given ID. Raises PresentableError if the record does not exist or can currently not be deleted. """ try: record = proc.db[recordId] except KeyError: raise PresentableError( xhtml.p['Cannot delete ', proc.recordName, ' ', xhtml.b[recordId], ' because it does not exist (anymore).']) try: proc.checkState(record) except RecordInUseError as ex: raise PresentableError( xhtml.p['Cannot delete ', proc.recordName, ' ', xhtml.b[recordId], ' because it is used in the following ', pluralize(ex.refererName, ex.referers), ':'] + unorderedList[(ex.presenter(referer) for referer in sorted(ex.referers))].present()) return record
def presentTaskFilter(self, args: ReportTaskArgs) -> XMLContent: yield 'Showing data from ', execState = args.execState if execState is not ExecutionState.ALL: yield xhtml.b[execState.name.lower()], ' ' taskNames = args.task yield xhtml[', '].join(xhtml.b[name] for name in sorted(taskNames)) yield ' tasks' owners = args.owner if owners: yield ' owned by ' yield xhtml[', '].join(xhtml.b[name] for name in sorted(owners)) targets = args.target if targets: yield ' for ', pluralize('target', len(targets)), ' ' yield xhtml[', '].join(xhtml.b[name] for name in sorted(targets)) ctabove = args.ctabove ctbelow = args.ctbelow if ctabove and ctbelow: yield (' created between ', xhtml.b[formatTime(ctabove)], ' and ', xhtml.b[formatTime(ctbelow)]) elif ctabove: yield ' created after ', xhtml.b[formatTime(ctabove)] elif ctbelow: yield ' created before ', xhtml.b[formatTime(ctbelow)] yield '.'
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(ShowJobs_GET.Processor, kwargs['proc']) if len(proc.jobs) != 0: if proc.req.refererPage in ('BatchExecute', 'Execute', 'FastExecute'): yield xhtml.p['Created the following ', pluralize('job', len(proc.jobs)), ':'] yield ShowJobsTable.instance.present(**kwargs) if len(proc.invalidJobIds) != 0: yield (xhtml.p['The following jobs ', xhtml.b['do not exist'], ': '], unorderedList[proc.invalidJobIds]) if len(proc.jobs) == 0 and len(proc.invalidJobIds) == 0: yield xhtml.p['No job IDs specified.']
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(TaskDetails_GET.Processor, kwargs['proc']) taskDefId = proc.args.id configs = proc.configs yield xhtml.h3['Details of task definition ', xhtml.b[taskDefId], ':'] yield DetailsTable.instance.present(**kwargs) yield xhtml.p[createTaskHistoryLink(taskDefId)] numConfigs = len(configs) yield xhtml.p[ pageLink('TaskEdit', proc.args)['Edit this task definition'], xhtml.br, ('Delete this task definition: not possible, because it is ' 'currently being used by ', str(numConfigs), ' ', pluralize('configuration', numConfigs), '.' ) if configs else pageLink('TaskDelete', DeleteArgs( id=taskDefId))['Delete this task definition']]
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(FrameworkDetails_GET.Processor, kwargs['proc']) frameworkId = proc.args.id children = proc.children numChildren = len(children) deleteFramework = ( 'Delete this framework: not possible, ' 'because it is currently being used by ', str(numChildren), ' ', pluralize('task definition', numChildren), '.' ) if children else pageLink( 'FrameworkDelete', DeleteArgs(id = frameworkId) )[ 'Delete this framework' ] yield xhtml.h3[ 'Details of framework ', xhtml.b[ frameworkId ], ':' ] yield xhtml.div(class_='hgroup wrap')[ DetailsTable.instance, GraphPanel.instance ].present(graph=proc.graph, **kwargs) yield xhtml.p[ pageLink('FrameworkEdit', proc.args)[ 'Edit this framework' ], xhtml.br, deleteFramework ]
def __init__(self, table: 'DataTable[Record]', proc: PageProcessor): super().__init__() columns = tuple(table.iterColumns(proc=proc, data=None)) dbName = table.dbName db: Optional[Database[Any]] = \ None if dbName is None else getattr(proc, dbName) records = table.getRecordsToQuery(proc) if isinstance(records, SizedABC): unfilteredNrRecords: Optional[int] = len(records) elif db is not None: unfilteredNrRecords = len(db) else: # We could store all records in a list or wrap a counting iterator # around it, but so far that has not been necessary. unfilteredNrRecords = None sortField = table.sortField if sortField is None: # We don't know if getRecordsToQuery() has filtered or not. filtered = None if isinstance(records, list): records = cast(List[Record], records) else: records = list(records) else: sortOrder = cast(Sequence[str], getattr(proc.args, sortField)) cleanSortOrder = self.__cleanSortOrder(columns, sortOrder) if sortOrder != cleanSortOrder: if proc.args.isArgument(sortField): raise ArgsCorrected( proc.args.override(**{sortField: cleanSortOrder})) else: setattr(proc.args, sortField, cleanSortOrder) query: List[RecordProcessor] = list(table.iterFilters(proc)) filtered = bool(query) keyMap = _buildKeyMap(columns, proc) sortKeys = (keyMap.get(key, key) for key in cleanSortOrder) # TODO: Maybe we should have a class (RecordCollection?) for # records that are not DBRecords or to keep track of # a subset of a full DB. Then 'uniqueKeys' could be moved # from DataTable to RecordCollection. getRetriever: Callable[[str], Retriever[Record, Comparable]] if db is None: getRetriever = itemgetter uniqueKeys = table.uniqueKeys or () else: getRetriever = db.retrieverFor assert table.uniqueKeys is None, "table's uniqueKeys is ignored" uniqueKeys = db.uniqueKeys retrievers: List[Retriever[Record, Comparable]] = [] for key in sortKeys: if callable(key): retrievers.append(substMissingForNone(key)) else: retrievers.append(substMissingForNone(getRetriever(key))) if key in uniqueKeys: break else: retrievers.append( cast(Callable[[Record], Comparable], lambda record: record)) query.append(KeySorter(retrievers)) records = runQuery(query, records) totalNrRecords = len(records) tabOffsetField = table.tabOffsetField if tabOffsetField is not None: tabOffset: int = getattr(proc.args, tabOffsetField) recordsPerPage = table.recordsPerPage if tabOffset < 0: # User tried to be funny and entered negative offset in URL. # Clip to first tab. newOffset = 0 elif tabOffset >= totalNrRecords: # URL could be manipulated or were are looking at a database # from which records were recently deleted. # Clip to last tab. newOffset = (totalNrRecords // recordsPerPage) * recordsPerPage else: # Make sure the first record on a tab matches the tab label. # Round down to current tab label. newOffset = (tabOffset // recordsPerPage) * recordsPerPage if newOffset != tabOffset: raise ArgsCorrected( proc.args.override(**{tabOffsetField: newOffset})) records = records[tabOffset:tabOffset + table.recordsPerPage] objectName = table.objectName if objectName is None: assert db is not None objectName = pluralize(db.description, 42) self.objectName = objectName self.columns = columns self.records = records self.unfilteredNrRecords = unfilteredNrRecords self.totalNrRecords = totalNrRecords self.filtered = filtered
def __setState(self, result: Optional[ResultCode], newState: str, summary: Optional[str], outputs: Optional[Mapping[str, str]] = None ) -> None: products = self.getProduced() # Check if non-existing output.PRODUCT.locators are set. if outputs: filteredOutputs = dict(outputs) unknownProducts = [ outputName for outputName in outputs.keys() if all(outputName != product.getName() for product in products) ] if unknownProducts: # Remove locators for non-existing products. for productName in unknownProducts: del filteredOutputs[productName] # Overrule result and summary. result = ResultCode.WARNING summary = \ 'Wrapper sets output locator for non-existing %s: %s' % ( pluralize('product', unknownProducts), ', '.join(sorted(unknownProducts)) ) else: filteredOutputs = {} if result is not None: self._properties['result'] = result if summary is not None: self._properties['summary'] = summary self._properties['state'] = newState self._properties['stoptime'] = getTime() if 'abort' in self._properties: del self._properties['abort'] if 'alert' in self._properties: del self._properties['alert'] # Update state of outputs. for product in products: # Store locator. locator = filteredOutputs.get(product.getName()) if locator is not None: product.storeLocator(locator, self.getName()) # Is the product done now? # pylint: disable=protected-access if product.isCombined(): if self.getJob()._isProductFixed(product): product.done() else: # Locator availability determines whether product is available # or not. This new behaviour was introduced in SoftFab 2.10.0, # along with local products. if locator is None: if self.getJob()._isProductFixed(product): self.getJob()._blockProduct(product) else: product.done() # Trigger property cache for task objects in joblib. if self.hasResult(): self.getTask().initCached(resultOnly = False)