def variable_size_header_part(platform, company, searchbar, searchbar_position): return hg.BaseElement( hg.A( logo(), platform, _class="bx--header__name", style="font-weight: 400", # override carbon design href=hg.F(lambda c: c["request"].META["SCRIPT_NAME"] or "/"), ), hg.If( searchbar, hg.SPAN( searchbar, style=f"position: absolute; left: {searchbar_position}", _class="theme-gray-100", ), "", ), hg.A( hg.SPAN( company, style=hg.format( "position: absolute; left: {}", hg.If(searchbar, "50%", searchbar_position), ), ), _class="bx--header__name", style="font-weight: 400", # override carbon design href=hg.F(lambda c: c["request"].META["SCRIPT_NAME"] or "/"), ), )
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 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 __init__( self, size="xl", placeholder=None, widgetattributes=None, backend=None, resultcontainerid=None, show_result_container=True, resultcontainer_onload_js=None, disabled=False, **kwargs, ): """ :param SearchBackendConfig backend: Where and how to get search results """ kwargs["_class"] = kwargs.get("_class", "") + f" bx--search bx--search--{size}" kwargs["data_search"] = True kwargs["role"] = "search" width = kwargs.get("width", None) if width: kwargs["style"] = kwargs.get("style", "") + f"width:{width};" widgetattributes = { "id": "search__" + hg.html_id(self), "_class": "bx--search-input", "type": "text", "placeholder": placeholder or _("Search"), "autocomplete": "off", **(widgetattributes or {}), } if backend: if resultcontainerid is None: resultcontainerid = f"search-result-{hg.html_id((self, backend.url))}" widgetattributes["hx_get"] = backend.url widgetattributes["hx_trigger"] = "changed, click, keyup changed delay:500ms" widgetattributes["hx_target"] = hg.format("#{}", resultcontainerid) widgetattributes["hx_indicator"] = hg.format( "#{}-indicator", resultcontainerid ) widgetattributes["name"] = backend.query_parameter self.close_button = _close_button(resultcontainerid, widgetattributes) super().__init__( hg.DIV( hg.LABEL(_("Search"), _class="bx--label", _for=widgetattributes["id"]), hg.INPUT(**widgetattributes), _search_icon(), self.close_button, hg.If(backend is not None, _loading_indicator(resultcontainerid)), **kwargs, ), hg.If( backend is not None and show_result_container, _result_container(resultcontainerid, resultcontainer_onload_js, width), ), style=hg.If(disabled, hg.BaseElement("display: none")), )
def __init__(self, content, panelid, tabid, selected): super().__init__( content, id=panelid, aria_labelledby=tabid, role="tabpanel", aria_hidden=hg.If(selected, "false", "true"), hidden=hg.If(selected, False, True), )
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 __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 error_layout( request, status_code: int, status_title: str, description: Union[str, hg.BaseElement], exception_detail: str = None, ): return hg.BaseElement( hg.H1(f"{status_code}: {status_title}", style="margin-bottom: 1rem;"), hg.P( description, style="margin-bottom: 1rem;", ), hg.If( bool(exception_detail), hg.BaseElement( hg.H4("Detail", style="margin-bottom: 1rem;"), hg.DIV( exception_detail, style=( "border: 1px solid grey;" "padding: 1rem;" "font-family: monospace;" "margin-bottom: 1rem;" ), ), ), ), Button.from_link( Link( label=_("Back to homepage"), href=hg.F(lambda c: c["request"].META["SCRIPT_NAME"] or "/"), ) ), )
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 get_input_element(self, inputelement_attrs, errors, **kwargs): return hg.INPUT( type=self.input_type, lazy_attributes=_combine_lazy_dict( _append_classes( inputelement_attrs or {}, self.carbon_input_class, hg.If( getattr(errors, "condition", False), self.carbon_input_error_class, ), ), kwargs, ), data_invalid=hg.If(getattr(errors, "condition", False), True), )
def __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, **attributes, ): inputelement_attrs = inputelement_attrs or {} super().__init__( label, hg.DIV( self.get_input_element(inputelement_attrs, errors), hg.DIV( hg.BUTTON( Icon("caret--up", size=16), _class="bx--number__control-btn up-icon", type="button", ), hg.BUTTON( Icon("caret--down", size=16), _class="bx--number__control-btn down-icon", type="button", ), _class="bx--number__controls", ), _class="bx--number__input-wrapper", ), errors, help_text, data_numberinput=True, data_invalid=hg.If(errors.condition, True), **hg.merge_html_attrs(attributes, {"_class": "bx--number"}), )
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 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 __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, **attributes, ): inputelement_attrs = inputelement_attrs or {} attrs = {} if boundfield: attrs["checked"] = hg.F( lambda c: hg.resolve_lazy(boundfield, c).field.widget. check_test(hg.resolve_lazy(boundfield, c).value())) attrs["value"] = None inputelement_attrs = _combine_lazy_dict(inputelement_attrs, attrs) # labels for checkboxes are treated a bit different, need to use plain value label = hg.F(lambda c, label=label: getattr(hg.resolve_lazy(label, c), "label", label)) required = hg.F( lambda c, label=label: hg.resolve_lazy(label, c) is not None) super().__init__( hg.LABEL( self.get_input_element(inputelement_attrs, errors), label, hg.If(inputelement_attrs.get("required"), hg.If(required, REQUIRED_LABEL)), _class=hg.BaseElement( "bx--checkbox-label", hg.If(inputelement_attrs.get("disabled"), " bx--label--disabled"), ), data_contained_checkbox_state=hg.If( inputelement_attrs.get("checked"), "true", "false", ), data_invalid=hg.If(getattr(errors, "condition", False), True), ), help_text, errors, **hg.merge_html_attrs(attributes, {"_class": "bx--checkbox-wrapper"}), )
def __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, icon=None, **attributes, ): inputelement_attrs = inputelement_attrs or {} super().__init__( label, hg.DIV( hg.If( getattr(errors, "condition", None), Icon( "warning--filled", size=16, _class="bx--text-input__invalid-icon", ), ), self.get_input_element(inputelement_attrs, errors), hg.If( icon, hg.If( hg.F(lambda c: isinstance(icon, str)), Icon( icon, size=16, _class="text-input-icon", ), icon, ), ), _class=("bx--text-input__field-wrapper" + (" text-input-with-icon" if icon is not None else "")), data_invalid=hg.If(getattr(errors, "condition", None), True), ), errors, help_text, **hg.merge_html_attrs(attributes, {"_class": "bx--text-input-wrapper"}), )
def __init__( self, label, offlabel=_("Off"), onlabel=_("On"), help_text=None, errors=None, disabled=None, required=None, widgetattributes={}, **attributes, ): attributes["_class"] = attributes.get("_class", "") + " bx--form-item" widgetattributes["_class"] = (widgetattributes.get("_class", "") + " bx--toggle-input") widgetattributes["type"] = "checkbox" widgetattributes["id"] = widgetattributes.get("id", None) or hg.html_id(self) self.input = hg.INPUT(**widgetattributes) self.label = hg.LABEL( label, hg.If(required, REQUIRED_LABEL), hg.SPAN( hg.SPAN(offlabel, _class="bx--toggle__text--off", aria_hidden="true"), hg.SPAN(onlabel, _class="bx--toggle__text--on", aria_hidden="true"), _class="bx--toggle__switch", ), _class=hg.BaseElement( "bx--label bx--toggle-input__label", hg.If(disabled, " bx--label--disabled"), ), _for=widgetattributes["id"], ) super().__init__( self.input, self.label, HelpText(help_text), ErrorList(errors), **attributes, )
def maintenance_search_reindex(request): class ReindexForm(forms.Form): confirmed = forms.BooleanField( widget=forms.HiddenInput, initial=True, ) form: ReindexForm received_post = False logmsg: str = None if request.method == "POST": form = ReindexForm(request.POST) if form.is_valid() and "confirmed" in form.cleaned_data: received_post = True out = StringIO() management.call_command("rebuild_index", interactive=False, stdout=out) logmsg = out.getvalue().replace("\n", "<br>") # try adding some message here. messages.info(request, _("Rebuilt search index")) if not received_post: form = ReindexForm() reindex_btn = Form( form, FormField("confirmed"), Button( _("Rebuild"), type="submit", style="margin-bottom: 1rem;", ), ) return hg.BaseElement( hg.P( _(("After certain kind of database updates the search index may become outdated. " "You can reindex the search index by clicking the button below. " "This should fix most problems releated to search fields.")), style="margin-bottom: 1rem;", ), reindex_btn, hg.If( logmsg, hg.BaseElement( hg.H6(_("Log from the server"), style="margin-bottom: 0.75rem;"), hg.SAMP(hg.mark_safe(logmsg), style="font-family: monospace;"), ), ), )
def __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, **attributes, ): inputelement_attrs = inputelement_attrs or {} super().__init__( label, hg.DIV( hg.If( getattr(errors, "condition", None), Icon( "warning--filled", size=16, _class="bx--text-area__invalid-icon", ), ), hg.TEXTAREA( boundfield.value() if boundfield else None, lazy_attributes=_combine_lazy_dict( _append_classes( inputelement_attrs or {}, self.carbon_input_class, hg.If( getattr(errors, "condition", None), self.carbon_input_error_class, ), ), {"value": None}, ), ), _class="bx--text-area__wrapper", data_invalid=hg.If(getattr(errors, "condition", None), True), ), help_text, errors, **attributes, )
def __init__(self, helptext, disabled=False): super().__init__( helptext, hg.DIV( helptext, _class=hg.BaseElement( "bx--form__helper-text", hg.If(disabled, " bx--form__helper-text--disabled"), ), ), )
def __init__(self, label, _for=None, required=None, disabled=None, **kwargs): self.label = label super().__init__( label, hg.LABEL( label, hg.If(required, REQUIRED_LABEL), _for=_for, _class=hg.BaseElement( "bx--label", hg.If(disabled, " bx--label--disabled"), ), **kwargs, ), )
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_postal_address and c["object"].person.primary_postal_address.pk != c["object"].pk ), layout.forms.FormField("is_primary"), "", ) ] return hg.DIV(layout.components.forms.Form(hg.C("form"), *form_fields))
def __init__(self, label, tabid, panelid, selected): super().__init__( hg.A( label, tabindex="0", id=tabid, _class="bx--tabs__nav-link", href="javascript:void(0)", aria_controls=panelid, aria_selected=hg.If(selected, "true", "false"), role="tab", ), _class=hg.BaseElement( "bx--tabs__nav-item", hg.If(selected, " bx--tabs__nav-item--selected"), ), data_target="#" + panelid, aria_selected=hg.If(selected, "true", "false"), role="tab", onclick=hg.BaseElement("setBreadCookie('selected-tab', '", tabid, "')"), )
def __init__( self, label=None, help_text=None, errors=None, inputelement_attrs=None, boundfield=None, backend=None, **attributes, ): """ :param SearchBackendConfig backend: Where and how to get search results """ inputelement_attrs = inputelement_attrs or {} # This works inside a formset. Might need to be changed for other usages. widget_id = inputelement_attrs.get("id") resultcontainerid = hg.format("search-result-{}", widget_id) tag_id = hg.format("{}-tag", widget_id) super().__init__( label, Tag( hg.F(lambda c: hg.resolve_lazy(boundfield, c).field.to_python( hg.resolve_lazy(boundfield, c).value())) if boundfield else "", id=tag_id, style=hg.If( inputelement_attrs.get("value"), hg.BaseElement(""), hg.BaseElement("display: none;"), ), onclick="return false;", ), self.get_input_element(inputelement_attrs, errors, type="hidden"), Search( backend=backend, resultcontainerid=resultcontainerid, resultcontainer_onload_js=_resultcontainer_onload_js( backend, resultcontainerid, tag_id, widget_id), size="lg", disabled=inputelement_attrs.get("disabled", False), widgetattributes={"id": hg.format("search__{}", widget_id)}, ), help_text, errors, **hg.merge_html_attrs(attributes, {"_class": "bx--text-input-wrapper"}), )
def _close_button(resultcontainerid, widgetattributes): kwargs = { "_class": hg.BaseElement( "bx--search-close", hg.If(widgetattributes.get("value"), None, " bx--search-close--hidden"), ), "title": _("Clear search input"), "aria_label": _("Clear search input"), "type": "button", } if resultcontainerid is not None: kwargs["onclick"] = hg.format( "document.getElementById('{}').innerHTML = '';", resultcontainerid ) return hg.BUTTON(Icon("close", size=20, _class="bx--search-clear"), **kwargs)
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 asoverflowbutton(context): link = context["link"] return hg.A( hg.DIV( hg.If( link.iconname, Icon(link.iconname, size=16), ), link.label, _class="bx--overflow-menu-options__option-content", ), _class="bx--overflow-menu-options__btn", role="menuitem", title=link.label, href=link.href, **link.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, )
def searchbar(search_urlparameter: str): """ Creates a searchbar element for datatables to submit an entered search term via a GET url parameter """ searchinput = Search( widgetattributes={ "autofocus": True, "name": search_urlparameter, "value": hg.F(lambda c: c["request"].GET.get(search_urlparameter, "")), "onfocus": "this.setSelectionRange(this.value.length, this.value.length);", }) searchinput.close_button.attributes[ "onclick"] = "this.closest('form').querySelector('input').value = ''; this.closest('form').submit()" return hg.DIV( hg.FORM( searchinput, hg.Iterator( hg.C("request").GET.lists(), "urlparameter", hg.If( hg.F( lambda c: c["urlparameter"][0] != search_urlparameter), hg.Iterator( hg.C("urlparameter")[1], "urlvalue", hg.INPUT( type="hidden", name=hg.C("urlparameter")[0], value=hg.C("urlvalue"), ), ), ), ), method="GET", ), _class="bx--toolbar-search-container-persistent", )
def email(request): return tile_with_datatable( models.Email, hg.F(lambda c: c["object"].core_email_list.all()), [ DataTableColumn( layout.ObjectFieldLabel("type", models.Email), hg.SPAN( hg.C("row.type"), hg.If( hg.F(lambda c: c["row"] == c["row"].person. primary_email_address), hg.BaseElement(" (", _("primary"), ")"), "", ), ), ), "email", ], request, )
def __init__( self, *children, buttontype="primary", icon=None, notext=False, small=False, **attributes, ): attributes["type"] = attributes.get("type", "button") attributes["tabindex"] = attributes.get("tabindex", "0") attributes["_class"] = hg.BaseElement( attributes.get("_class", ""), f" bx--btn bx--btn--{buttontype}", hg.If( hg.F(lambda c: hg.resolve_lazy( self.attributes.get("disabled", False), c)), " bx--btn--disabled", ), ) if small: attributes["_class"] += " bx--btn--sm " if notext or not children: attributes["_class"] += " bx--btn--icon-only" if children: attributes["_class"] += ( " bx--btn--icon-only bx--tooltip__trigger bx--tooltip--a11y " "bx--tooltip--bottom bx--tooltip--align-center") children = (hg.SPAN(*children, _class="bx--assistive-text"), ) if icon is not None: if isinstance(icon, str): icon = Icon(icon) if isinstance(icon, Icon): icon.attributes["_class"] = ( icon.attributes.get("_class", "") + " bx--btn__icon") children += (icon, ) super().__init__(*children, **attributes)