def get_layout(self): if hasattr(self, "layout") and self.layout is not None: ret = self.layout else: formfields = filter_fieldlist( self.model, [f for f in self.fields if isinstance(f, str)] if self.fields else None, for_form=True, ) ret = hg.BaseElement() for field in self.fields or formfields: if field in formfields: ret.append(breadlayout.forms.FormField(field)) else: ret.append(field) if self.ajax_urlparameter in self.request.GET: return breadlayout.forms.Form(hg.C("form"), ret) # wrap with form will add a submit button return hg.DIV( header(), breadlayout.tile.Tile( breadlayout.forms.Form( hg.C("form"), ret, breadlayout.forms.helpers.Submit() ), _class="theme-white", ), )
class TaskResultBrowseView(BrowseView): columns = [ DataTableColumn( layout.ObjectFieldLabel("task_id", TaskResult), hg.DIV(hg.C("row.task_id"), ), "task_id", ), DataTableColumn( layout.ObjectFieldLabel("task_name", TaskResult), hg.DIV(hg.C("row.task_name"), ), "task_name", ), DataTableColumn( _("Date Created"), hg.DIV(hg.C("row.date_created"), ), "date_created", ), DataTableColumn( _("Date Completed"), hg.DIV(hg.C("row.date_done"), ), "date_done", ), "status", "worker", "content_type", DataTableColumn( _("Metadata"), hg.DIV(hg.C("row.meta"), ), ), ] rowclickaction = BrowseView.gen_rowclickaction("read") title = "Background Jobs"
def get_layout(self): return hg.If( hg.C("validlink"), auth_page( layout.forms.Form( hg.C("form"), layout.forms.FormField( "new_password1", inputelement_attrs={"_class": "field-02-background"}, style="width: 100%", ), layout.forms.FormField( "new_password2", inputelement_attrs={"_class": "field-02-background"}, ), id="authform", ), _("Change password"), ), auth_page( hg.BaseElement( hg.FORM(id="authform", action=reverse("login")), layout.notification.InlineNotification( _("Invalid password reset link"), _( "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." ), kind="error", lowcontrast=True, style="margin-bottom: 4rem", ), ), _("Back to Login"), ), )
def personal_data(): displayed_fields = [ utils.display_field_label_and_value(field) for field in [ "salutation", "title", "name", "first_name", "last_name", "date_of_birth", "profession", ] ] + [ hg.If( hg.C("object.deceased"), display_label_and_value( ObjectFieldLabel("deceased"), hg.If(hg.C("object.deceased"), _("Yes"), _("No")), ), ), hg.If( hg.C("object.deceased"), utils.display_field_label_and_value("decease_date"), ), ] return utils.tile_col_edit_modal_displayed_fields( _("Personal Data"), models.NaturalPerson, "ajax_edit_personal_data", Icon("user--profile"), displayed_fields, )
def person_metadata(model): return tiling_col( # we need this to take exactly as much space as a real header hg.DIV("", style="margin-bottom:3.25rem;"), display_field_label_and_value("personnumber"), display_field_label_and_value("maintype"), display_field_label_and_value("type"), display_label_and_value(_("Status"), active_toggle()), display_label_and_value( _("Changed"), hg.BaseElement( ObjectFieldValue("history.first.history_date.date"), " / ", hg.C("object.history.first.history_user"), ), ), display_label_and_value( _("Created"), hg.BaseElement( ObjectFieldValue("history.last.history_date.date"), " / ", hg.C("object.history.last.history_user"), ), ), open_modal_popup_button( _("Meta data"), model, f"{model._meta.model_name}_ajax_edit_metadata"), style="border-left: none;", )
def get_layout(self): modelclass = self.object.model.model_class() if modelclass is None: return layout.notification.InlineNotification( "Error", f"Model '{self.object.model}' does no longer exist.", kind="error", ) column_helper = layout.get_attribute_description_modal(modelclass) F = layout.forms.FormField fieldstable = layout.forms.FormsetField.as_datatable( "columns", ["header", "column", "sortingname"], formsetfield_kwargs={ "extra": 1, "can_order": True, }, ) fieldstable[0][1].insert( 0, layout.button.Button(_("Help"), buttontype="ghost", **column_helper.openerattributes), ) fieldstable.append(hg.DIV(style="height: 1rem")) ret = hg.BaseElement( views.header(), layout.forms.Form( hg.C("form"), hg.DIV( _("Base model"), ": ", hg.C("object.model"), style="margin: 2rem 0 2rem 0", ), F("name"), F( "filter", inputelement_attrs={"rows": 1}, style="width: 100%", ), fieldstable, layout.tile.ExpandableTile( hg.H4(_("Extended settings")), hg.DIV( F("custom_queryset"), F("pagination"), ), ), layout.forms.helpers.Submit(style="margin-top: 1rem"), column_helper, ), hg.C("object.preview"), ) return ret
def display_sync_persons(sync_status): return hg.Iterator( hg.F(lambda c: c["row"].persons.filter(sync_status=sync_status)), "person", hg.DIV( hg.format( "{} {} <{}>", hg.C("person.first_name"), hg.C("person.last_name"), hg.C("person.email"), )), )
def __init__(self, platform, company, searchbar, actions=(), *args, **kwargs): super().__init__( hg.If( HasBreadCookieValue("sidenav-hidden", "true"), variable_size_header_part(hg.BaseElement(), company, searchbar, "5rem"), variable_size_header_part( hg.SPAN(platform, _class="bx--header__name--prefix"), company, searchbar, "18rem", ), ), hg.DIV( hg.If( hg.F(lambda c: c["request"].user.is_authenticated), hg.A( hg.SPAN( hg.C("request.user.get_username"), _class="bx--header__name--prefix", ), _class="bx--header__name", href=reverse("userprofile"), title=hg.C("request.user.get_username"), style="padding: 0; margin-right: 1rem", ), ), hg.If( hg.F(lambda c: c["request"].user.is_authenticated), hg.BUTTON( Icon( "logout", size=20, _class="bx--navigation-menu-panel-expand-icon", aria_hidden="true", ), Icon( "logout", size=20, _class="bx--navigation-menu-panel-collapse-icon", aria_hidden="true", ), _class="bx--header__menu-trigger bx--header__action", title=_("Logout"), data_navigation_menu_panel_label_expand=_("Logout"), data_navigation_menu_panel_label_collapse=_("Close"), onclick=f"document.location = '{reverse('logout')}'", ), ), _class="bx--header__global", ), _class="bx--header", data_header=True, )
def tags(): return tile_with_icon( Icon("tag--group"), hg.H4(_("Tags")), hg.Iterator(hg.F(lambda c: c["object"].tags.all()), "i", Tag(hg.C("i"))), open_modal_popup_button( _("Edit Tags"), hg.C("object").person_ptr, "ajax_edit_tags", ), )
def management_form(self): # the management form is required for Django formsets return hg.BaseElement( # management forms, for housekeeping of inline forms hg.F(lambda c: Form( c[self.formname][self.fieldname].formset.management_form, *[ FormField( f, no_wrapper=True, no_label=True, no_helptext=True) for f in c[self.formname][self.fieldname].formset. management_form.fields ], standalone=False, )), # Empty form as template for new entries. The script tag works very well # for this since we need a single, raw, unescaped HTML string hg.SCRIPT( Form( hg.C(f"{self.formname}.{self.fieldname}.formset.empty_form" ), hg.WithContext( self.content, **{ DEFAULT_FORMSET_CONTEXTNAME: hg. C(f"{self.formname}.{self.fieldname}.formset.empty_form" ) }, ), standalone=False, ), id=hg.BaseElement( "empty_", hg.C(f"{self.formname}.{self.fieldname}.formset.prefix"), "_form", ), type="text/plain", ), hg.SCRIPT( mark_safe( "document.addEventListener('DOMContentLoaded', e => init_formset('" ), hg.C(f"{self.formname}.{self.fieldname}.formset.prefix"), mark_safe("'));"), ), hg.SPAN(onload=hg.BaseElement( mark_safe("init_formset('"), hg.C(f"{self.formname}.{self.fieldname}.formset.prefix"), mark_safe("');"), ), ), )
def tile_with_datatable(model, queryset, columns, request): modal = layout.modal.Modal.with_ajax_content( _("Add"), ModelHref( model, "add", query=hg.F(lambda c: { "person": c["object"].pk, "asajax": True }), ), submitlabel=_("Save"), ) return tiling_col( layout.datatable.DataTable.from_queryset( queryset, model=model, prevent_automatic_sortingnames=True, columns=columns, rowactions=[ Link( href=ModelHref( model, "edit", kwargs={"pk": hg.C("row.pk")}, query={"next": request.get_full_path()}, ), iconname="edit", label=_("Edit"), ), Link( href=ModelHref( model, "delete", kwargs={"pk": hg.C("row.pk")}, query={"next": request.get_full_path()}, ), iconname="trash-can", label=_("Delete"), ), ], primary_button=layout.button.Button(_("Add"), buttontype="primary", **modal.openerattributes), style="border-top: none;", ), modal, )
def get_layout(self): R = layout.grid.Row C = layout.grid.Col F = layout.forms.FormField return layout.grid.Grid( layout.components.forms.Form( hg.C("form"), R(C(F("salutation"))), R(C(F("title"))), R( C( F("name"), width=10, breakpoint="lg", ), C( F("autogenerate_displayname"), width=6, breakpoint="lg", style="align-self: flex-end;", ), ), R(C(F("first_name"))), R(C(F("last_name"))), R(C(F("date_of_birth"))), R(C(F("profession"))), R(C(F("deceased"))), R(C(F("decease_date"))), ) )
def editperson_head(request): return hg.BaseElement( R( C( hg.H3( hg.SPAN( hg.C("object"), style=hg.If(hg.C("object.deleted"), "text-decoration: line-through"), ), editperson_toolbar(request), ), width=12, ), style="padding-top: 1rem", ), )
def get_layout(self): fields = hg.BaseElement( *[ layout.forms.FormField(f) for f in utils.filter_fieldlist(self.model, ["__all__"], for_form=True) ] ) return hg.BaseElement( hg.H1(self.object, style="margin-bottom: 2rem"), hg.DIV( layout.button.Button( "Edit", **layout.aslink_attributes( layout.objectaction(self.object, "edit") ), ), views.layoutasreadonly( hg.DIV( hg.DIV( layout.forms.Form( hg.C("form"), fields, layout.forms.helpers.Submit() ), style="padding: 1rem", ), hg.DIV( self.object.as_svg(), style="width: 40%; border: 1px solid gray", ), style="display: flex;", ) ), ), )
def get_layout(self): form_fields = [layout.forms.FormField(field) for field in [*self.fields]] + [ hg.If( hg.F( lambda c: c["object"].person.primary_email_address and c["object"].person.primary_email_address.pk != c["object"].pk ), layout.forms.FormField("is_primary"), "", ), hg.If( hg.F( lambda c: apps.is_installed("basxconnect.mailer_integration") and hasattr(c["object"], "subscription") ), layout.forms.FormField("propagate_change_to_mailer"), "", ), ] return layout.grid.Grid( hg.H3(_("Edit Email")), layout.grid.Row( layout.grid.Col( layout.forms.Form( hg.C("form"), hg.DIV(*form_fields), layout.forms.helpers.Submit(), ), width=4, ) ), gutter=False, )
def display_previous_execution(request): return R( C( layout.datatable.DataTable.from_queryset( SynchronizationResult.objects.order_by( "-sync_completed_datetime"), columns=[ "total_synchronized_persons", "sync_completed_datetime", DataTableColumn( _("Newly added to BasxConnect"), display_sync_persons(SynchronizationPerson.NEW), ), ], title=_("Previous Executions"), primary_button="", rowactions=[ Link( href=ModelHref( SynchronizationResult, "delete", kwargs={"pk": hg.C("row.pk")}, query={"next": request.get_full_path()}, ), iconname="trash-can", label=_("Delete"), ) ], ), width=16, ))
def generate_term_datatable(title, vocabulary_slug): """Helper function to display a table for all terms of a certain term, currently always returns to the personsettings view""" # TODO: make the backurl dynamic to return to current view (needs correct handling in the DataTable code) cat = Vocabulary.objects.filter(slug=vocabulary_slug).first() or "" return layout.datatable.DataTable.from_queryset( Term.objects.filter(vocabulary__slug=vocabulary_slug), columns=["term"], title=title, primary_button=layout.button.Button.from_link( Link( href=ModelHref(Term, "add", query={"vocabulary": cat.id}, return_to_current=True), label=_("Add %s") % pretty_modelname(Term), ), icon=layout.icon.Icon("add", size=20), ), prevent_automatic_sortingnames=True, rowclickaction=BrowseView.gen_rowclickaction("edit", return_to_current=True), rowactions=[ Link( label=_("Delete"), href=ModelHref.from_object(hg.C("row"), "delete", return_to_current=True), iconname="trash-can", ) ], backurl=reverse( "basxconnect.core.views.settings_views.personsettings"), )
def get_layout(self): if self.section_name: section_names = [self.section_name] else: section_names = self.form_class.registry.section_objects.keys() section_fields = {} for section in section_names: section_fields[section] = [] for field in self.form_class.registry[section]: section_fields[section].append(f"{section}__{field}") return breadlayout.forms.Form( hg.C("form"), hg.H3(_("Global preferences")), Tabs( *[ Tab( self.form_class.registry.section_objects[section]. verbose_name, hg.BaseElement(*[ breadlayout.forms.FormField(f) for f in section_fields.get(section) ]), ) for section in section_fields.keys() ], tabpanel_attributes={"style": "padding-left:0;"}, ), breadlayout.forms.helpers.Submit(), )
def systeminformation(request): git_status = "" try: git_status = ( subprocess. run( # nosec because we have no user input to subprocess ["git", "log", "-n", "5", "--oneline"], capture_output=True, check=True).stdout.decode()) except subprocess.SubprocessError as e: git_status = hg.BaseElement( "ERROR", hg.BR(), str(e), hg.BR(), getattr(e, "stdout", b"").decode(), hg.BR(), getattr(e, "stderr", b"").decode(), ) return hg.BaseElement( hg.H3(_("System information")), hg.H4("Git log"), hg.PRE(hg.CODE(git_status)), hg.H4("PIP packages", style="margin-top: 2rem"), hg.UL( hg.Iterator( sorted([ "%s==%s" % (i.key, i.version) for i in pkg_resources.working_set ]), "package", hg.LI(hg.C("package")), )), )
def auth_page(content, submitname, show_cancelbutton=False): return hg.DIV( hg.DIV( hg.H3(hg.C("pagetitle")), hg.FORM(id="cancelform", action=reverse("login")), content, hg.DIV( hg.If( show_cancelbutton, layout.button.Button( _("Cancel"), buttontype="ghost", form="cancelform", type="submit", style="width: 50%", ), hg.DIV(style="width: 50%"), ), layout.button.Button( submitname, type="submit", form="authform", style="width: 50%" ), style="margin: 1rem -1rem -1rem -1rem; display: flex; height: 64px", ), style="margin: auto; width: 25rem", _class="bx--tile", ), style="background-image: linear-gradient(#0F62FE, #0008C9); position: absolute; left: 0; top: 0; bottom: 0; right: 0; display: flex; flex-direction: column", )
def get_layout(self): return auth_page( layout.forms.Form( hg.C("form"), hg.A( _("Lost password?"), href=reverse("password_reset"), style="display: block; text-align: right; font-size: 0.75rem", ), layout.forms.FormField( fieldname="username", form="form", inputelement_attrs={"_class": "field-02-background"}, style="width: 100%", ), layout.forms.FormField( fieldname="password", form="form", inputelement_attrs={"_class": "field-02-background"}, style="width: 100%", ), id="authform", ), _("Login"), )
def editperson_toolbar(request): deletebutton = layout.button.Button( _("Delete"), buttontype="ghost", icon="trash-can", notext=True, **layout.aslink_attributes( hg.F(lambda c: layout.objectaction(c["object"], "delete"))), ) restorebutton = layout.button.Button( _("Restore"), buttontype="ghost", icon="undo", notext=True, **layout.aslink_attributes( hg.F(lambda c: layout.objectaction( c["object"], "delete", query={"restore": True}))), ) copybutton = layout.button.Button( _("Copy"), buttontype="ghost", icon="copy", notext=True, **layout.aslink_attributes( hg.F(lambda c: layout.objectaction(c["object"], "copy"))), ) return hg.SPAN( hg.If(hg.C("object.deleted"), restorebutton, deletebutton), copybutton, layout.button.PrintPageButton(buttontype="ghost"), _class="no-print", style="margin-bottom: 1rem; margin-left: 1rem", width=3, )
def profile_field_checkbox(fieldname): return layout.forms.widgets.Checkbox( label=layout.ObjectFieldLabel(fieldname), inputelement_attrs={ "checked": hg.C(f"object.{fieldname}"), "disabled": True }, )
def get_layout(self): if self.ajax_urlparameter in self.request.GET: return layout.forms.Form(hg.C("form"), hg.BaseElement(*formfields)) else: return layout.grid.Grid( hg.H3(_("Add Relationship")), layout.grid.Row( layout.grid.Col( layout.forms.Form( hg.C("form"), hg.DIV(*formfields), ), width=4, ) ), gutter=False, )
def header(): editbutton = breadlayout.button.Button( _("Edit"), buttontype="ghost", icon="edit", notext=True, ).as_href(ModelHref.from_object(hg.C("object"), "edit")) readbutton = breadlayout.button.Button( _("Read"), buttontype="ghost", icon="view", notext=True, ).as_href(ModelHref.from_object(hg.C("object"), "read")) deletebutton = breadlayout.button.Button( _("Delete"), buttontype="tertiary", icon="trash-can", notext=True, style="border-color: red; background-color: inherit", ).as_href(ModelHref.from_object(hg.C("object"), "delete")) deletebutton[1].attributes["style"] = "fill: red; color: red;" copybutton = breadlayout.button.Button( _("Copy"), buttontype="ghost", icon="copy", notext=True, ).as_href(ModelHref.from_object(hg.C("object"), "copy")) return hg.DIV( hg.H3( hg.If( hg.C("object"), hg.BaseElement( hg.SPAN(hg.C("object")), hg.SPAN( hg.If( hg.C("request").resolver_match.url_name.endswith(".read"), editbutton, readbutton, ), copybutton, breadlayout.button.PrintPageButton(buttontype="ghost"), deletebutton, _class="no-print", style="margin-bottom: 1rem; margin-left: 1rem", width=3, ), ), hg.SPAN(hg.format(_("Add {}"), hg.C("view").model._meta.verbose_name)), ), ), style="padding-top: 1rem", )
def deletelink(return_to_current=True): return Link( href=ModelHref.from_object(hg.C("row"), "delete", return_to_current=return_to_current), label=_("Delete"), iconname="delete", )
def relationships_datatable(request, queryset, primary_button, title): return layout.datatable.DataTable.from_queryset( queryset, model=Relationship, title=title, prevent_automatic_sortingnames=True, columns=[ person_in_relationship( "Person A", "person_a", lambda relationship: relationship.person_a, ), "type", person_in_relationship( "Person B", "person_b", lambda relationship: relationship.person_b, ), "start_date", "end_date", ], rowactions=[ Link( href=ModelHref( Relationship, "edit", kwargs={"pk": hg.C("row.pk")}, query={"next": request.get_full_path()}, ), iconname="edit", label=_("Edit"), ), Link( href=ModelHref( Relationship, "delete", kwargs={"pk": hg.C("row.pk")}, query={"next": request.get_full_path()}, ), iconname="trash-can", label=_("Delete"), ), ], primary_button=primary_button, )
def __init__(self, errors): super().__init__( errors, hg.DIV( hg.UL(hg.Iterator(errors or (), "error", hg.LI(hg.C("error")))), _class="bx--form-requirement", ), )
def editlink(return_to_current=True, **attributes): return Link( href=ModelHref.from_object(hg.C("row"), "edit", return_to_current=return_to_current), label=_("Edit"), iconname="edit", attributes=attributes, )
def __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, **attributes, ): inputelement_attrs = inputelement_attrs or {} super().__init__( hg.FIELDSET( label, hg.DIV( hg.Iterator( boundfield.subwidgets, "radiobutton", RadioButton( label=Label(hg.C("radiobutton").data["label"]), inputelement_attrs=_combine_lazy_dict( _combine_lazy_dict( inputelement_attrs, { "name": hg.C("radiobutton").data["name"], "value": hg.C("radiobutton").data["value"], "checked": hg.C("radiobutton").data["selected"], }, ), hg.C("radiobutton").data["attrs"], ), ), ), _class= "bx--radio-button-group bx--radio-button-group--vertical", ), data_invalid=hg.If(getattr(errors, "condition", False), True), ), help_text, errors, **attributes, )