Exemple #1
0
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 __init__(
        self,
        links,
        menuiconname="overflow-menu--vertical",
        menuname=None,
        direction="bottom",
        flip=False,
        item_attributes={},
        **attributes,
    ):
        attributes["data-overflow-menu"] = True
        attributes["_class"] = attributes.get("_class",
                                              "") + " bx--overflow-menu"
        item_attributes["_class"] = (item_attributes.get("_class", "") +
                                     " bx--overflow-menu-options__option")

        menuid = hg.F(lambda c: OverflowMenu.MENUID_TEMPLATE % hg.html_id(
            c.get("row", self)))
        triggerid = hg.F(lambda c: (OverflowMenu.MENUID_TEMPLATE % hg.html_id(
            c.get("row", self))) + "-trigger")

        super().__init__(
            hg.BUTTON(
                Icon(menuiconname, size=16),
                _class="bx--overflow-menu__trigger" +
                (" bx--tooltip__trigger bx--tooltip--a11y bx--tooltip--right bx--tooltip--align-start"
                 if menuname is not None else ""),
                aria_haspopup="true",
                aria_expanded="false",
                aria_controls=menuid,
                type="button",
                id=triggerid,
            ),
            hg.DIV(
                hg.UL(
                    hg.Iterator(
                        links,
                        "link",
                        hg.LI(
                            hg.F(asoverflowbutton),
                            **item_attributes,
                        ),
                    ),
                    _class="bx--overflow-menu-options__content",
                ),
                _class="bx--overflow-menu-options" +
                (" bx--overflow-menu--flip" if flip else ""),
                tabindex="-1",
                role="menu",
                aria_labelledby=triggerid,
                data_floating_menu_direction=direction,
                id=menuid,
            ),
            **attributes,
        )
        if menuname is not None:
            self[0].insert(0, hg.SPAN(menuname, _class="bx--assistive-text"))
Exemple #3
0
 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",
         ),
     )
Exemple #4
0
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 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 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 __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,
     )
Exemple #8
0
 def __init__(
     self,
     columns,
     row_iterator,
     valueproviderclass=hg.ValueProvider,
     spacing="default",
     zebra=False,
 ):
     """columns: tuple(header_expression, row_expression)
     if the header_expression/row_expression has an attribute td_attributes it will be used as attributes for the TH/TD elements (necessary because sometimes the content requires additional classes on the parent element)
     spacing: one of "default", "compact", "short", "tall"
     valueproviderclass: A class which implements ValueProvider which will be passed to the Iterator
     """
     assert spacing in ["default", "compact", "short", "tall"]
     classes = ["bx--data-table"]
     if spacing != "default":
         classes.append(f"bx--data-table--{spacing}")
     if zebra:
         classes.append("bx--data-table--zebra")
     super().__init__(
         hg.TABLE(
             hg.THEAD(
                 hg.TR(*[
                     hg.TH(
                         hg.SPAN(
                             column[0],
                             _class="bx--table-header-label",
                         ),
                         **getattr(column[1], "td_attributes", {}),
                     ) for column in columns
                 ])),
             hg.TBODY(
                 hg.Iterator(
                     row_iterator,
                     hg.TR(*[
                         hg.TD(column[1],
                               **getattr(column[1], "td_attributes", {}))
                         for column in columns
                     ]),
                     valueproviderclass,
                 )),
             _class=" ".join(classes),
         ))
 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.Iterator(
                 boundfield.subwidgets,
                 "checkbox",
                 Checkbox(
                     label=Label(hg.C("checkbox").data["label"]),
                     inputelement_attrs=_combine_lazy_dict(
                         _combine_lazy_dict(
                             inputelement_attrs,
                             {
                                 "name": hg.C("checkbox").data["name"],
                                 "value": hg.C("checkbox").data["value"],
                                 "checked":
                                 hg.C("checkbox").data["selected"],
                             },
                         ),
                         hg.C("checkbox").data["attrs"],
                     ),
                 ),
             ),
             data_invalid=hg.If(getattr(errors, "condition", False), True),
         ),
         help_text,
         errors,
         **attributes,
     )
Exemple #10
0
    def __init__(
        self,
        columns: List["DataTableColumn"],
        row_iterator: Union[hg.Lazy, Iterable, hg.Iterator],
        orderingurlparameter: str = "ordering",
        rowvariable: str = "row",
        spacing: str = "default",
        zebra: bool = False,
        sticky: bool = False,
        **kwargs: Any,
    ):
        """A carbon DataTable element

        :param columns: Column definitions
        :param row_iterator: Iterator which yields row objects. If this is a hg.Iterator instance
                             it will be used for the table body, otherwise a default iterator will
                             be used to render the column cells. This can also be htmlgenerator.Lazy
                             object which returns a Python iterator when beeing evaluated.
        :param rowvariable: Name of the current object passed to childrens context
        :param orderingurlparameter: The name of the GET query parameter which is used to set the
                                     table ordering.
        :param spacing: One of "default", "compact", "short", "tall", according to the carbon styles
        :param zebra: If True alternate row colors
        :param kwargs: HTML element attributes
        """

        self.head = DataTable.headrow(columns, orderingurlparameter)
        if isinstance(row_iterator, hg.Iterator):
            self.iterator = row_iterator
        else:
            self.iterator = hg.Iterator(row_iterator, rowvariable,
                                        DataTable.row(columns))
        kwargs["_class"] = kwargs.get("_class", "") + " ".join(
            DataTable.tableclasses(spacing, zebra, sticky))
        super().__init__(hg.THEAD(self.head), hg.TBODY(self.iterator),
                         **kwargs)
Exemple #11
0
    def from_queryset(
        queryset,
        # column behaviour
        columns: Iterable[Union[str, "DataTableColumn"]] = (),
        prevent_automatic_sortingnames=False,
        # row behaviour
        rowvariable="row",
        rowactions: Iterable[Link] = (),
        rowactions_dropdown=False,
        rowclickaction=None,
        # bulkaction behaviour
        bulkactions: Iterable[Link] = (),
        checkbox_for_bulkaction_name="_selected",
        # toolbar configuration
        title=None,
        primary_button: Optional[Button] = None,
        settingspanel: Any = None,
        pagination_config: Optional[PaginationConfig] = None,
        search_urlparameter: Optional[str] = None,
        model=None,  # required if queryset is Lazy
        **kwargs,
    ):
        """TODO: Write Docs!!!!
        Yeah yeah, on it already...

        :param settingspanel: A panel which will be opened when clicking on the
                              "Settings" button of the datatable, usefull e.g.
                              for showing filter options. Currently only one
                              button and one panel are supported. More buttons
                              and panels could be interesting but may to over-
                              engineered because it is a rare case and it is not
                              difficutl to add another button by modifying the
                              datatable after creation.
        """
        if not isinstance(queryset, hg.Lazy):
            model = queryset.model
        if model is None:
            raise ValueError(
                "Argument for 'model' must be given if 'queryset' is of type hg.Lazy"
            )

        columns = columns or filter_fieldlist(model, ["__all__"])

        title = title or pretty_modelname(model, plural=True)

        if primary_button is None:
            primary_button = Button.from_link(
                Link(
                    href=ModelHref(model, "add"),
                    label=_("Add %s") % pretty_modelname(model),
                    permissions=[
                        f"{model._meta.app_label}.add_{model._meta.model_name}"
                    ],
                ),
                icon=Icon("add", size=20),
            )

        if rowactions_dropdown:
            objectactions_menu: hg.HTMLElement = OverflowMenu(
                rowactions,
                flip=True,
                item_attributes={"_class": "bx--table-row--menu-option"},
            )
        else:
            objectactions_menu = hg.DIV(
                hg.Iterator(
                    rowactions,
                    "link",
                    hg.F(lambda c: Button.from_link(
                        c["link"],
                        notext=True,
                        small=True,
                        buttontype="ghost",
                        _class="bx--overflow-menu",
                    ) if isinstance(c["link"], Link) else c["link"]),
                ),
                style="display: flex; justify-content: flex-end;",
            )

        column_definitions: List[DataTableColumn] = []
        for col in columns:
            if not (isinstance(col, DataTableColumn) or isinstance(col, str)):
                raise ValueError(
                    f"Argument 'columns' needs to be of a List[str] or a List[DataTableColumn], but found {col}"
                )
            td_attributes: Optional[dict] = None
            if rowclickaction and getattr(col, "enable_row_click", True):
                assert isinstance(rowclickaction,
                                  Link), "rowclickaction must be of type Link"
                td_attributes = {
                    **aslink_attributes(rowclickaction.href),
                    **(rowclickaction.attributes or {}),
                }
            # convert simple string (modelfield) to column definition
            if isinstance(col, str):

                col = DataTableColumn.from_modelfield(
                    col,
                    model,
                    prevent_automatic_sortingnames,
                    rowvariable,
                    td_attributes=td_attributes,
                )
            else:
                if td_attributes:
                    col = col._replace(
                        td_attributes=td_attributes)  # type: ignore

            column_definitions.append(col)

        return DataTable(
            column_definitions + ([
                DataTableColumn(
                    "",
                    objectactions_menu,
                    td_attributes=hg.F(
                        lambda c: {
                            "_class":
                            "bx--table-column-menu"
                            if rowactions_dropdown else ""
                        }),
                    th_attributes=hg.F(
                        lambda c: {"_class": "bx--table-column-menu"}),
                )
            ] if rowactions else []),
            # querysets are cached, the call to all will make sure a new query is used in every request
            hg.F(lambda c: queryset),
            **kwargs,
        ).with_toolbar(
            title,
            helper_text=hg.format(
                "{} {}",
                hg.F(lambda c: len(hg.resolve_lazy(queryset, c))
                     if pagination_config is None else pagination_config.
                     paginator.count),
                model._meta.verbose_name_plural,
            ),
            primary_button=primary_button,
            bulkactions=bulkactions,
            pagination_config=pagination_config,
            checkbox_for_bulkaction_name=checkbox_for_bulkaction_name,
            search_urlparameter=search_urlparameter,
            settingspanel=settingspanel,
        )
Exemple #12
0
def as_list(iterable):
    return hg.UL(hg.Iterator(iterable, "item", hg.LI(hg.C("item"))))
Exemple #13
0
def postals():
    return tile_with_icon(
        Icon("map"),
        hg.H4(_("Address(es)")),
        R(
            C(
                hg.Iterator(
                    hg.F(lambda c: getattr(c["object"], "core_postal_list").
                         order_by(
                             django.db.models.F("valid_until").desc(
                                 nulls_first=True)).all()
                         if hasattr(c["object"], "core_postal_list") else []),
                    "i",
                    display_postal(),
                ))),
        R(
            C(
                layout.button.Button(
                    _("Hide inactive postals"),
                    onclick="hideInactivePostals();",
                    id="hideInactivePostalsButton",
                    style="display: none;",
                    icon="view--off",
                    buttontype="ghost",
                ),
                layout.button.Button(
                    _("Show inactive postals"),
                    onclick="showInactivePostals();",
                    id="showInactivePostalsButton",
                    icon="view",
                    buttontype="ghost",
                ),
            ),
            style="margin-top: 1.5rem;",
        ),
        R(
            C(
                modal_with_trigger(
                    modal_add_postal(),
                    layout.button.Button,
                    _("Add"),
                    buttontype="ghost",
                    icon="add",
                ), ), ),
        hg.SCRIPT(
            mark_safe("""
                function hideInactivePostals() {
                    for(i of $$('.inactive_postal')) {
                        $(i)._.style({display: "none"});
                    }
                    $$('#hideInactivePostalsButton')._.style({display: "none"})
                    $$('#showInactivePostalsButton')._.style({display: "block"})
                }
                function showInactivePostals() {
                    for(i of $$('.inactive_postal')) {
                        $(i)._.style({display: "block"});
                    }
                    $$('#hideInactivePostalsButton')._.style({display: "block"})
                    $$('#showInactivePostalsButton')._.style({display: "none"})
                }
                """)),
    )
    def __init__(
            self,
            label=None,
            help_text=None,
            errors=None,
            inputelement_attrs=None,
            boundfield=None,  # for django-form select elements use this
            choices=None,  # for non-django-form select elements use this
            **attributes,  # for non-django-form select elements use this
    ):
        inputelement_attrs = inputelement_attrs or {}
        optgroups = (_optgroups_from_choices(
            choices,
            name=inputelement_attrs.get("name"),
            value=inputelement_attrs.get("value"),
        ) if choices else _gen_optgroup(boundfield))

        def countselected(context):
            options = [
                o for og in hg.resolve_lazy(optgroups, context) for o in og[1]
            ]
            return len([o for o in options if o and o["selected"]])

        searchfieldid = hg.html_id(self)
        super().__init__(
            label,
            hg.If(
                inputelement_attrs.get("disabled"),
                hg.DIV(
                    hg.Iterator(
                        optgroups,
                        "optiongroup",
                        hg.Iterator(
                            hg.C("optiongroup.1"),
                            "option",
                            hg.If(hg.C("option.selected"),
                                  Tag(hg.C("option.label"))),
                        ),
                    )),
                hg.DIV(
                    hg.DIV(
                        hg.DIV(
                            hg.F(countselected),
                            Icon(
                                "close",
                                focusable="false",
                                size=15,
                                role="img",
                                onclick=
                                "clearMultiselect(this.parentElement.parentElement.parentElement)",
                            ),
                            role="button",
                            _class=
                            "bx--list-box__selection bx--list-box__selection--multi bx--tag--filter",
                            tabindex="0",
                            title="Clear all selected items",
                        ),
                        hg.INPUT(
                            id=searchfieldid,
                            _class="bx--text-input",
                            placeholder="Filter...",
                            onclick=
                            "this.parentElement.nextElementSibling.style.display = 'block'",
                            onkeyup=
                            "filterOptions(this.parentElement.parentElement)",
                        ),
                        hg.DIV(
                            Icon("chevron--down",
                                 size=16,
                                 role="img",
                                 focusable="false"),
                            _class="bx--list-box__menu-icon",
                            onclick=
                            "this.parentElement.nextElementSibling.style.display = this.parentElement.nextElementSibling.style.display == 'none' ? 'block' : 'none';",
                        ),
                        role="button",
                        _class="bx--list-box__field",
                        tabindex="0",
                        onload=
                        "window.addEventListener('click', (e) => {this.nextElementSibling.style.display = 'none'})",
                    ),
                    hg.FIELDSET(
                        hg.Iterator(
                            optgroups,
                            "optgroup",
                            hg.Iterator(
                                hg.C("optgroup.1"),
                                "option",
                                hg.DIV(
                                    hg.DIV(
                                        hg.DIV(
                                            hg.LABEL(
                                                hg.INPUT(
                                                    type="checkbox",
                                                    readonly=True,
                                                    _class="bx--checkbox",
                                                    value=hg.C("option.value"),
                                                    lazy_attributes=hg.C(
                                                        "option.attrs"),
                                                    onchange=
                                                    "updateMultiselect(this.closest('.bx--multi-select'))",
                                                    checked=hg.C(
                                                        "option.selected"),
                                                    name=hg.C("option.name"),
                                                ),
                                                hg.SPAN(
                                                    _class=
                                                    "bx--checkbox-appearance"),
                                                hg.SPAN(
                                                    hg.C("option.label"),
                                                    _class=
                                                    "bx--checkbox-label-text",
                                                ),
                                                title=hg.C("option.label"),
                                                _class="bx--checkbox-label",
                                            ),
                                            _class=
                                            "bx--form-item bx--checkbox-wrapper",
                                        ),
                                        _class=
                                        "bx--list-box__menu-item__option",
                                    ),
                                    _class="bx--list-box__menu-item",
                                ),
                            ),
                        ),
                        _class="bx--list-box__menu",
                        role="listbox",
                        style="display: none",
                    ),
                    _class=hg.BaseElement(
                        "bx--multi-select bx--list-box bx--multi-select--selected bx--combo-box bx--multi-select--filterable",
                        hg.If(
                            inputelement_attrs.get("disabled"),
                            " bx--list-box--disabled",
                        ),
                    ),
                    data_invalid=hg.If(getattr(errors, "condition", None),
                                       True),
                ),
            ),
            help_text,
            errors,
            **hg.merge_html_attrs(
                attributes,
                {
                    "onclick": "event.stopPropagation()",
                    "_class": "bx--list-box__wrapper",
                },
            ),
        )
 def __init__(
     self,
     label=None,
     help_text=None,
     errors=None,
     inputelement_attrs=None,
     boundfield=None,
     inline=False,
     choices=None,  # for non-django-form select elements use this
     **attributes,
 ):
     inputelement_attrs = inputelement_attrs or {}
     select_wrapper = hg.DIV(
         hg.SELECT(
             hg.Iterator(
                 _optgroups_from_choices(
                     choices,
                     name=inputelement_attrs.get("name"),
                     value=inputelement_attrs.get("value"),
                 ) if choices else _gen_optgroup(boundfield),
                 "optgroup",
                 hg.If(
                     hg.C("optgroup.0"),
                     hg.OPTGROUP(
                         hg.Iterator(
                             hg.C("optgroup.1"),
                             "option",
                             hg.OPTION(
                                 hg.C("option.label"),
                                 _class="bx--select-option",
                                 value=hg.C("option.value"),
                                 lazy_attributes=hg.C("option.attrs"),
                             ),
                         ),
                         _class="bx--select-optgroup",
                         label=hg.C("optgroup.0"),
                     ),
                     hg.Iterator(
                         hg.C("optgroup.1"),
                         "option",
                         hg.OPTION(
                             hg.C("option.label"),
                             _class="bx--select-option",
                             value=hg.C("option.value"),
                             lazy_attributes=hg.C("option.attrs"),
                         ),
                     ),
                 ),
             ),
             lazy_attributes=_append_classes(
                 inputelement_attrs,
                 self.carbon_input_class,
                 hg.If(
                     getattr(errors, "condition", None),
                     self.carbon_input_error_class,
                 ),
             ),
         ),
         Icon(
             "chevron--down",
             size=16,
             _class="bx--select__arrow",
             aria_hidden="true",
         ),
         hg.If(
             getattr(errors, "condition", None),
             Icon(
                 "warning--filled",
                 size=16,
                 _class="bx--select__invalid-icon",
             ),
         ),
         _class="bx--select-input__wrapper",
         data_invalid=hg.If(getattr(errors, "condition", None), True),
     )
     super().__init__(
         label,
         hg.If(
             inline,
             hg.DIV(
                 select_wrapper,
                 errors,
                 _class="bx--select-input--inline__wrapper",
             ),
             select_wrapper,
         ),
         help_text,
         hg.If(inline, None, errors),  # not displayed if this is inline
         **hg.merge_html_attrs(
             attributes,
             {
                 "_class":
                 hg.BaseElement(
                     "bx--select",
                     hg.If(inline, " bx--select--inline"),
                     hg.If(getattr(errors, "condition", None),
                           " bx--select--invalid"),
                     hg.If(
                         inputelement_attrs.get("disabled"),
                         " bx--select--disabled",
                     ),
                 ),
             },
         ),
     )
 def __init__(self, menu: "bread.menu.Menu", **kwargs):
     kwargs["_class"] = hg.BaseElement(
         kwargs.get("_class", ""),
         " bx--side-nav bx--side-nav--rail",
         hg.If(
             HasBreadCookieValue("sidenav-hidden", "true"),
             "",
             " bx--side-nav--expanded",
         ),
     )
     kwargs["data_side_nav"] = True
     super().__init__(
         hg.NAV(
             hg.UL(
                 hg.Iterator(
                     hg.F(lambda c: (i for i in sorted(
                         hg.resolve_lazy(menu, c)._registry.values())
                                     if i.has_permission(c["request"]))),
                     "menugroup",
                     hg.LI(
                         hg.If(
                             hg.F(lambda c: len(c["menugroup"].items) > 1 or
                                  c["menugroup"].force_show),
                             hg.BaseElement(
                                 hg.BUTTON(
                                     hg.DIV(
                                         Icon(hg.C("menugroup.iconname"),
                                              size=16),
                                         _class="bx--side-nav__icon",
                                     ),
                                     hg.SPAN(
                                         hg.C("menugroup.label"),
                                         _class=
                                         "bx--side-nav__submenu-title",
                                     ),
                                     hg.DIV(
                                         Icon("chevron--down", size=16),
                                         _class=
                                         "bx--side-nav__icon bx--side-nav__submenu-chevron",
                                     ),
                                     _class="bx--side-nav__submenu",
                                     type="button",
                                     aria_haspopup="true",
                                     aria_expanded=hg.If(
                                         isactive("menugroup"), "true"),
                                 ),
                                 hg.UL(
                                     hg.Iterator(
                                         hg.F(lambda c: (i for i in sorted(
                                             c["menugroup"].items) if i.
                                                         has_permission(c[
                                                             "request"]))),
                                         "menuitem",
                                         hg.LI(
                                             hg.A(
                                                 hg.SPAN(
                                                     hg.
                                                     C("menuitem.link.label"
                                                       ),
                                                     _class=
                                                     "bx--side-nav__link-text",
                                                 ),
                                                 _class=hg.BaseElement(
                                                     "bx--side-nav__link",
                                                     hg.If(
                                                         isactive(
                                                             "menuitem"),
                                                         " bx--side-nav__link--current",
                                                     ),
                                                 ),
                                                 href=hg.C(
                                                     "menuitem.link.href"),
                                             ),
                                             _class=hg.BaseElement(
                                                 "bx--side-nav__menu-item",
                                                 hg.If(
                                                     isactive("menuitem"),
                                                     " bx--side-nav__menu-item--current",
                                                 ),
                                             ),
                                         ),
                                     ),
                                     _class="bx--side-nav__menu",
                                 ),
                             ),
                             hg.A(
                                 hg.DIV(
                                     Icon(
                                         hg.
                                         C("menugroup.items.0.link.iconname"
                                           ),
                                         size=16,
                                     ),
                                     _class="bx--side-nav__icon",
                                 ),
                                 hg.SPAN(
                                     hg.C("menugroup.items.0.link.label"),
                                     _class="bx--side-nav__link-text",
                                 ),
                                 _class=hg.BaseElement(
                                     "bx--side-nav__link",
                                     hg.If(
                                         isactive("menugroup"),
                                         " bx--side-nav__link--current",
                                     ),
                                 ),
                                 href=hg.C("menugroup.items.0.link.href"),
                             ),
                         ),
                         _class=hg.BaseElement(
                             "bx--side-nav__item",
                             hg.If(isactive("menugroup"),
                                   " bx--side-nav__item--active"),
                         ),
                     ),
                 ),
                 _class="bx--side-nav__items",
             ),
             hg.FOOTER(
                 hg.BUTTON(
                     hg.DIV(
                         Icon(
                             "close",
                             size=20,
                             _class=
                             "bx--side-nav__icon--collapse bx--side-nav-collapse-icon",
                             aria_hidden="true",
                         ),
                         Icon(
                             "chevron--right",
                             size=20,
                             _class=
                             "bx--side-nav__icon--expand bx--side-nav-expand-icon",
                             aria_hidden="true",
                         ),
                         _class="bx--side-nav__icon",
                     ),
                     hg.SPAN(
                         "Toggle the expansion state of the navigation",
                         _class="bx--assistive-text",
                     ),
                     _class="bx--side-nav__toggle",
                     onclick=
                     "setBreadCookie('sidenav-hidden', getBreadCookie('sidenav-hidden', 'false') != 'true');",
                 ),
                 _class="bx--side-nav__footer",
             ),
             _class="bx--side-nav__navigation",
         ),
         **kwargs,
     )
Exemple #17
0
class PersonBrowseView(BrowseView):
    columns = [
        DataTableColumn(
            layout.ObjectFieldLabel("personnumber", models.Person),
            hg.DIV(
                hg.C("row.personnumber"),
                style=hg.If(hg.C("row.deleted"),
                            "text-decoration:line-through"),
            ),
            "personnumber__int",
        ),
        DataTableColumn(
            hg.DIV(
                layout.tooltip.IconTooltip(
                    hg.UL(
                        hg.LI(hg.SPAN("●", style="color: green"), " ",
                              _("Active")),
                        hg.LI(hg.SPAN("●", style="color: red"), " ",
                              _("Inactive")),
                    ),
                    position="top",
                )),
            hg.DIV(
                "●",
                style=hg.format("color: {}",
                                hg.If(hg.C("row.active"), "green", "red")),
            ),
            "active",
        ),
        DataTableColumn(layout.ObjectFieldLabel("_type", models.Person),
                        hg.C("row._type"), "_type"),
        DataTableColumn(
            _("Name"),
            hg.DIV(
                hg.If(
                    hg.F(lambda context: type(context["row"]) == models.
                         NaturalPerson),
                    hg.C("row.last_name"),
                    hg.C("row.name"),
                ),
                style=hg.If(hg.C("row.deleted"),
                            "text-decoration:line-through"),
            ),
            "default_sorting_name",
        ),
        DataTableColumn(
            layout.ObjectFieldLabel("first_name", models.NaturalPerson),
            hg.DIV(
                hg.If(
                    hg.F(lambda context: type(context["row"]) == models.
                         NaturalPerson),
                    hg.C("row.first_name"),
                    "",
                ),
                style=hg.If(hg.C("row.deleted"),
                            "text-decoration:line-through"),
            ),
            "naturalperson__first_name",
        ),
        "primary_postal_address.address",
        "primary_postal_address.postcode",
        "primary_postal_address.city",
        "primary_postal_address.country",
        DataTableColumn(
            _("Email"),
            hg.C("row.primary_email_address.asbutton", ),
            "primary_email_address__email",
            False,
        ),
        DataTableColumn(
            layout.ObjectFieldLabel("tags", models.Person),
            hg.UL(
                hg.Iterator(hg.C("row.tags.all"), "tag",
                            layout.tag.Tag(hg.C("tag")))),
        ),
    ]
    bulkactions = (
        BulkAction(
            "add-tag",
            label=_("Add tag"),
            iconname="add",
            action=bulkaddtag,
        ),
        BulkAction(
            "remove-tag",
            label=_("Remove tag"),
            iconname="subtract",
            action=bulkremovetag,
        ),
        BulkAction(
            "delete",
            label=_("Delete"),
            iconname="trash-can",
            action=bulkdelete,
        ),
        BulkAction(
            "restore",
            label=_("Restore"),
            iconname="restart",
            action=bulkrestore,
        ),
        BulkAction(
            "excel",
            label=_("Excel"),
            iconname="download",
            action=export,
        ),
    )
    search_backend = layout.search.SearchBackendConfig(url=reverse(
        "basxconnect.core.views.person.search_person_view.searchperson"))
    rowclickaction = BrowseView.gen_rowclickaction("read")
    viewstate_sessionkey = "personbrowseview"

    class FilterForm(forms.Form):
        naturalperson = forms.BooleanField(required=False,
                                           label=_("Natural Person"))
        legalperson = forms.BooleanField(required=False,
                                         label=_("Legal Person"))
        personassociation = forms.BooleanField(required=False,
                                               label=_("Person Association"))
        naturalperson_subtypes = forms.ModelMultipleChoiceField(
            queryset=models.Term.objects.filter(
                vocabulary__slug="naturaltype"),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label="",
        )
        legalperson_subtypes = forms.ModelMultipleChoiceField(
            queryset=models.Term.objects.filter(vocabulary__slug="legaltype"),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label="",
        )
        personassociation_subtypes = forms.ModelMultipleChoiceField(
            queryset=models.Term.objects.filter(
                vocabulary__slug="associationtype"),
            widget=forms.CheckboxSelectMultiple,
            required=False,
            label="",
        )
        tags = forms.ModelMultipleChoiceField(
            queryset=models.Term.objects.filter(vocabulary__slug="tag"),
            widget=forms.CheckboxSelectMultiple,
            required=False,
        )
        preferred_language = forms.MultipleChoiceField(
            choices=settings.PREFERRED_LANGUAGES,
            widget=forms.CheckboxSelectMultiple,
            required=False,
        )
        status = forms.MultipleChoiceField(
            choices=[("active", _("Active")), ("inactive", _("Inactive"))],
            widget=forms.CheckboxSelectMultiple,
            required=False,
        )
        trash = forms.BooleanField(required=False, label=_("Trash"))

    def get_layout(self):
        self.checkboxcounterid = hg.html_id(self, "checkbox-counter")
        ret = super().get_layout()
        toolbar = list(
            ret.filter(lambda e, a: getattr(e, "attributes", {}).get(
                "_class", "") == "bx--toolbar-content"))[0]
        nfilters = self._checkbox_count()
        toolbar.insert(
            -2,
            hg.DIV(
                hg.SPAN(nfilters, id=self.checkboxcounterid),
                layout.icon.Icon(
                    "close",
                    focusable="false",
                    size=15,
                    role="img",
                    onclick=
                    f"document.location = '{self.request.path}?reset=1'",
                ),
                role="button",
                _class=
                "bx--list-box__selection bx--list-box__selection--multi bx--tag--filter",
                style="margin: auto 0.5rem;" +
                (" display: none;" if nfilters == 0 else ""),
                tabindex="0",
                title=("Reset"),
            ),
        )
        return ret

    def _filterform(self):
        return self.FilterForm({"status": ["active"], **self.request.GET})

    def _checkbox_count(self):
        counter = 0
        form = self._filterform()
        if form.is_valid():
            counter += 1 if form.cleaned_data["naturalperson"] else 0
            counter += 1 if form.cleaned_data["legalperson"] else 0
            counter += 1 if form.cleaned_data["personassociation"] else 0
            counter += form.cleaned_data["naturalperson_subtypes"].count()
            counter += form.cleaned_data["legalperson_subtypes"].count()
            counter += form.cleaned_data["personassociation_subtypes"].count()
            counter += form.cleaned_data["tags"].count()
            counter += len(form.cleaned_data["preferred_language"])
            counter += (
                1 if "inactive" in form.cleaned_data["status"] else 0
            )  # don't count the "active" checkbox, it is a permanent default
            counter += 1 if form.cleaned_data["trash"] else 0
        return counter

    def get_queryset(self):
        form = self._filterform()
        qs = super().get_queryset()
        if form.is_valid():
            ret = ((qs.filter(
                deleted=form.cleaned_data.get("trash", False))).select_related(
                    "primary_email_address", "primary_postal_address",
                    "_type").prefetch_related("tags"))
            if any([
                    form.cleaned_data[i] for i in (
                        "naturalperson",
                        "legalperson",
                        "personassociation",
                        "naturalperson_subtypes",
                        "legalperson_subtypes",
                        "personassociation_subtypes",
                    )
            ]):
                q = Q()
                for i in ("naturalperson", "legalperson", "personassociation"):
                    # setup some logic descriptors
                    maintype_selected = bool(form.cleaned_data[i])
                    subtype_selected = bool(form.cleaned_data[f"{i}_subtypes"])
                    all_subtypes_selected = bool(
                        form.cleaned_data[f"{i}_subtypes"].count() ==
                        form.fields[f"{i}_subtypes"].queryset.count())

                    # the semantics for this filter are not 100% clear
                    # there are also cases where a subtype has the wrong maintype
                    # This code tries to make the selection consistent to what a user
                    # would expect, but these expectations can still vary...
                    if maintype_selected:
                        typeq = Q(_maintype=i)
                        if subtype_selected:
                            if not all_subtypes_selected:
                                typeq &= Q(_type__in=form.
                                           cleaned_data[f"{i}_subtypes"])
                        else:
                            typeq &= ~Q(_type__in=form.fields[f"{i}_subtypes"].
                                        queryset)
                        q |= typeq
                    else:
                        q |= Q(_type__in=form.cleaned_data[f"{i}_subtypes"])
                ret = ret.filter(q)
            if form.cleaned_data.get("tags"):
                ret = ret.filter(tags__in=form.cleaned_data["tags"])
            if form.cleaned_data.get("preferred_language"):
                ret = ret.filter(preferred_language__in=form.
                                 cleaned_data["preferred_language"])
            if len(form.cleaned_data.get("status")
                   ) == 1 and not form.cleaned_data.get("trash", False):
                ret = ret.filter(
                    active=form.cleaned_data.get("status")[0] == "active")

            return ret
        return qs

    def get_settingspanel(self):
        return hg.DIV(
            layout.forms.Form(
                self._filterform(),
                hg.DIV(
                    hg.DIV(
                        hg.DIV(layout.helpers.Label(_("Person Type"))),
                        hg.DIV(
                            hg.DIV(
                                hg.DIV(
                                    layout.forms.FormField(
                                        "naturalperson",
                                        onclick=
                                        "updateCheckboxGroupItems(this.parentElement.parentElement)",
                                    ),
                                    hg.DIV(
                                        layout.forms.FormField(
                                            "naturalperson_subtypes",
                                            style="padding-left: 1rem",
                                        ),
                                        style="margin-top: -2rem",
                                    ),
                                ),
                                layout.forms.FormField(
                                    "personassociation",
                                    onclick=
                                    "updateCheckboxGroupItems(this.parentElement.parentElement)",
                                ),
                                hg.DIV(
                                    layout.forms.FormField(
                                        "personassociation_subtypes",
                                        style="padding-left: 1rem",
                                    ),
                                    style="margin-top: -2rem",
                                ),
                                style="margin-right: 16px",
                            ),
                            hg.DIV(
                                layout.forms.FormField(
                                    "legalperson",
                                    onclick=
                                    "updateCheckboxGroupItems(this.parentElement.parentElement)",
                                ),
                                hg.DIV(
                                    layout.forms.FormField(
                                        "legalperson_subtypes",
                                        style="padding-left: 1rem",
                                    ),
                                    style="margin-top: -2rem",
                                ),
                                style="margin-right: 16px",
                            ),
                            style="display: flex",
                        ),
                        style=
                        "border-right: #ccc solid 1px; margin: 0 16px 0 0",
                    ),
                    hg.DIV(
                        hg.DIV(
                            layout.forms.FormField("tags"),
                            style="margin-right: 16px",
                        ),
                        style=
                        "border-right: #ccc solid 1px; margin: 0 16px 0 0; overflow-y: scroll",
                    ),
                    hg.DIV(
                        hg.DIV(
                            layout.forms.FormField("preferred_language"),
                            style="margin-right: 16px",
                        ),
                        style=
                        "border-right: #ccc solid 1px; margin: 0 16px 0 0",
                    ),
                    hg.DIV(
                        hg.DIV(layout.forms.FormField("status"),
                               style="flex-grow: 0"),
                        hg.DIV(style="flex-grow: 1"),
                        hg.DIV(
                            layout.forms.FormField("trash"),
                            style="max-height: 2rem",
                        ),
                        style="display: flex; flex-direction: column",
                    ),
                    style=
                    "display: flex; max-height: 50vh; padding: 24px 32px 0 32px",
                ),
                hg.DIV(
                    layout.button.Button(
                        _("Cancel"),
                        buttontype="ghost",
                        onclick=
                        "this.parentElement.parentElement.parentElement.parentElement.parentElement.style.display = 'none'",
                    ),
                    layout.button.Button.from_link(
                        Link(
                            label=_("Reset"),
                            href=self.request.path + "?reset=1",
                            iconname=None,
                        ),
                        buttontype="secondary",
                    ),
                    layout.button.Button(
                        pgettext_lazy("apply filter", "Filter"),
                        type="submit",
                    ),
                    style=
                    "display: flex; justify-content: flex-end; margin-top: 24px",
                    _class="bx--modal-footer",
                ),
                method="GET",
            ),
            hg.SCRIPT(
                mark_safe("""
                    function updateCheckboxGroupItems(group) {
                        var items = $$('input[type=checkbox]', group);
                        var value = items[0].getAttribute('aria-checked');
                        value = value == 'true' ? 'true' : 'false';
                        for(var i = 1; i < items.length; ++i) {
                            new CarbonComponents.Checkbox(items[i]).setState(value);
                        }
                    }
                    function updateCheckboxCounter(group) {
                        var items = $$('input[type=checkbox]', group);
                        var count = 0;
                        for(item of items) {
                            if(!(item.name === 'status' && item.value === 'active'))
                                count += item.getAttribute('aria-checked') == 'true' ? 1 : 0
                        }
                        $('#%s').innerHTML = count;
                        $('#%s').closest('div[role=button]').style.display = count === 0 ? "none" : "flex";
                    }
                    """ % (self.checkboxcounterid, self.checkboxcounterid))),
            style="background-color: #fff",
            onclick="updateCheckboxCounter(this)",
        )
Exemple #18
0
def default_page_layout(menu, *content):
    return hg.HTML(
        hg.HEAD(
            hg.TITLE(
                hg.F(lambda c: strip_tags(
                    hg.render(
                        hg.BaseElement(
                            c.get("pagetitle", c.get("PLATFORMNAME"))), c)) +
                     " | " + strip_tags(c.get("PLATFORMNAME")))),
            hg.LINK(rel="shortcut icon", href=_static("logo.png")),
            hg.LINK(
                rel="stylesheet",
                type="text/css",
                href=hg.If(
                    settings.DEBUG,
                    _static("css/bread-main.css"),  # generate with "make css"
                    _static(
                        "css/bread-main.min.css"),  # generate with "make css"
                ),
                media="all",
            ),
        ),
        hg.BODY(
            ShellHeader(
                hg.C("PLATFORMNAME"),
                hg.C("COMPANYNAME"),
                searchbar=hg.If(
                    hg.C("request.user.is_authenticated"),
                    hg.C("SEARCHBAR"),
                    "",
                ),
            ),
            hg.If(
                hg.C("request.user.is_authenticated"),
                SideNav(menu),
            ),
            hg.DIV(
                hg.Iterator(
                    hg.C("messages"),
                    "message",
                    ToastNotification(
                        message=hg.F(
                            lambda c: _(c["message"].tags.capitalize())),
                        details=hg.C("message.message"),
                        kind=hg.C("message.level_tag"),
                        hidetimestamp=True,
                        autoremove=5.0,
                    ),
                ),
                style="position: fixed; right: 0; z-index: 999",
            ),
            hg.DIV(*content, _class="bx--content"),
            hg.If(
                settings.DEBUG,
                hg.BaseElement(
                    hg.SCRIPT(src=_static("js/bliss.js")),
                    hg.SCRIPT(src=_static("js/htmx.js")),
                    hg.SCRIPT(src=_static("js/main.js")),
                    hg.SCRIPT(src=_static(
                        "design/carbon_design/js/carbon-components.js")),
                ),
                hg.SCRIPT(
                    src=_static("js/bread.min.js")),  # generate with "make js"
            ),
            hg.SCRIPT("CarbonComponents.watch(document);"),
        ),
        doctype=True,
        _class="no-js",
        lang=get_language(),
    )
def get_attribute_description_modal(obj):
    from . import datatable, modal

    columns = []
    fields = {f.name: f for f in obj._meta.get_fields()}
    for i in set(dir(obj) + list(vars(obj))):
        try:
            desc = _get_attribute_description(obj, i, fields)
            if desc is not None and desc[3]:
                f = desc[3]._meta.get_fields()
                additional_attrs = list(
                    filter(
                        None,
                        (
                            _get_attribute_description(desc[3], a, f)
                            for a in set(dir(desc[3]) + list(vars(desc[3])))
                        ),
                    )
                )
                desc = (
                    desc[0],
                    desc[1],
                    desc[2],
                    hg.BaseElement(
                        hg.UL(
                            hg.Iterator(
                                additional_attrs,
                                "attr",
                                hg.LI(
                                    hg.format("{}.{}", i, hg.C("attr.0")),
                                    style="font-weight: 700",
                                ),
                            )
                        ),
                    ),
                )
            if desc is not None:
                columns.append(desc)
        except Exception as e:
            columns.append((i, _("Unknown"), e))
    return modal.Modal(
        _("Available columns"),
        hg.DIV(
            hg.DIV(_("Bold text marks valid column names")),
            datatable.DataTable(
                columns=[
                    datatable.DataTableColumn(
                        _("Column name"),
                        hg.SPAN(hg.C("row.0"), style="font-weight: 700"),
                    ),
                    datatable.DataTableColumn(
                        _("Description"), hg.F(lambda c: c["row"][2])
                    ),
                    datatable.DataTableColumn(_("Type"), hg.F(lambda c: c["row"][1])),
                    datatable.DataTableColumn(_("Extended columns"), hg.C("row.3")),
                ],
                row_iterator=sorted(columns),
            ),
        ),
        size="lg",
    )
    def __init__(self,
                 form,
                 *children,
                 use_csrf=True,
                 standalone=True,
                 **kwargs):
        """
        form: lazy evaluated value which should resolve to the form object
        children: any child elements, can be formfields or other
        use_csrf: add a CSRF input, but only for POST submission and standalone forms
        standalone: if true, will add a CSRF token and will render enclosing FORM-element
        """
        self.standalone = standalone
        attributes = {"method": "POST", "autocomplete": "off"}
        attributes.update(kwargs)
        if (attributes["method"].upper() == "POST" and use_csrf is not False
                and standalone is True):
            children = (CsrfToken(), ) + children

        if self.standalone and "enctype" not in attributes:
            # note: We will always use "multipart/form-data" instead of the
            # default "application/x-www-form-urlencoded" inside bread. We do
            # this because forms with file uploads require multipart/form-data.
            # Not distinguishing between two encoding types can save us some issues,
            # especially when handling files.
            # The only draw back with this is a slightly larger payload because
            # multipart-encoding takes a little bit more space
            attributes["enctype"] = "multipart/form-data"

        super().__init__(
            hg.WithContext(
                # generic errors
                hg.If(
                    form.non_field_errors(),
                    hg.Iterator(
                        form.non_field_errors(),
                        "formerror",
                        InlineNotification(_("Form error"),
                                           hg.C("formerror"),
                                           kind="error"),
                    ),
                ),
                # errors from hidden fields
                hg.If(
                    form.hidden_fields(),
                    hg.Iterator(
                        form.hidden_fields(),
                        "hiddenfield",
                        hg.Iterator(
                            hg.C("hiddenfield").errors,
                            "hiddenfield_error",
                            InlineNotification(
                                _("Hidden field error: "),
                                hg.format(
                                    "{}: {}",
                                    hg.C("hiddenfield").name,
                                    hg.C("hiddenfield_error"),
                                ),
                                kind="error",
                            ),
                        ),
                    ),
                ),
                *children,
                **{DEFAULT_FORM_CONTEXTNAME: form},
            ),
            **attributes,
        )