The main page¶
This page explains how to customize the elements of the main page of a Lino application.
Vocabulary¶
- dashboard item¶
An individual item of the dashboard, rendered directly (inline) into the main page because it is considered an important entry point.
This is a tested document. The following instructions are used for initialization:
Code snippets in this document are tested using the
lino_book.projects.noi1e
demo project.
>>> import lino
>>> lino.startup('lino_book.projects.noi1e.settings.demo')
>>> from lino.api.doctest import *
Quick links¶
As the application developer you define quick links by overriding the
setup_quicklinks
methods of your
Site
class.
For example the lino.modlib.about
plugin says:
class Plugin(Plugin):
def get_quicklinks(site):
yield 'about.SiteSearch'
Or the lino_noi.lib.noi.settings
module says:
class Site(Site):
...
def setup_quicklinks(self, user, tb):
super().setup_quicklinks(user, tb)
tb.add_action(self.models.tickets.RefTickets)
...
tb.add_action(
self.models.tickets.AllTickets.insert_action,
label=_("Submit a ticket"))
...
a = self.models.users.MySettings.default_action
tb.add_instance_action(user, action=a, label=_("My settings"))
>>> pprint(settings.SITE.quicklinks.items)
...
[<lino.core.actions.WrappedAction users_Me_my_settings ('My settings')>,
<lino.core.actions.WrappedAction calview_WeeklyView_detail ('Calendar')>,
<lino.core.actions.WrappedAction tickets_RefTickets_grid>,
<lino.core.actions.WrappedAction tickets_ActiveTickets_grid>,
<lino.core.actions.WrappedAction tickets_AllTickets_grid>,
<lino.core.actions.WrappedAction tickets_AllTickets_insert ('Submit new ticket')>,
<lino.core.actions.WrappedAction subscriptions_RefSubscriptions_grid>,
<lino.core.actions.WrappedAction search_SiteSearch_grid>]
The admin_main.html
template calls
lino.core.Site.get_quicklink_items()
to retrieve and then render this
information.
>>> ar = rt.login("robin")
>>> user = ar.get_user()
>>> for ql in settings.SITE.get_quicklink_items(user.user_type):
... print(tostring(ar.menu_item_button(ql)))
...
<a style="text-decoration:none" href="My settings">My settings</a>
<a style="text-decoration:none" title="Open a detail window on records of calview." href="Detail">Calendar</a>
<a style="text-decoration:none" href="Reference Tickets">Reference Tickets</a>
<a style="text-decoration:none" href="Active tickets">Active tickets</a>
<a style="text-decoration:none" href="All tickets">All tickets</a>
<a style="text-decoration:none" title="Open a dialog window to insert a new Ticket." href="New">Submit new ticket</a>
<a style="text-decoration:none" href="Subscriptions">Subscriptions</a>
<a style="text-decoration:none" href="Search">Search</a>
Welcome messages¶
As the application developer you have several methods to define welcome messages:
Set
welcome_message_when_count
of some table to some value (usually0
).For example the
lino_xl.lib.tickets.TicketsToTriage
plugin uses this to define the "You have X items in Tickets to triage" message.Define a custom welcome message by overwriting
add_welcome_handler
in theSite
class of your application.For example the "You are busy with..." message in Lino Noi is
lino_xl.lib.working
. Orlino_xl.lib.stars
defines the "Your stars are" message.
The admin_main.html
calls get_welcome_messages
. This code inserts the "welcome
messages" for this user on this site. get_welcome_messages
returns an etree element (see
etgen.html
).
>>> ar = rt.login("robin")
>>> print(tostring(settings.SITE.get_welcome_messages(ar)))
...
<p><span><a href="Detail">Jean</a> is working on: <a title="'NoneType' object
has no attribute 'isocode'" href="Detail">#97 ('NoneType' object has no
attribute 'isocode')</a>, <a title="Cannot delete foo" href="Detail">#109
(Cannot delete foo)</a>.</span><br/><span><a href="Detail">Luc</a> is working
on: <a title="Irritating message when bar" href="Detail">#111 (Irritating
message when bar)</a>, <a title="Foo never matches Bar" href="Detail">#9 (Foo
never matches Bar)</a>.</span><br/><span><a href="Detail">Mathieu</a> is working
on: <a title="Cannot delete foo" href="Detail">#73 (Cannot delete foo)</a>, <a
title="How can I see where bar?" href="Detail">#85 (How can I see where
bar?)</a>, <a title="'NoneType' object has no attribute 'isocode'"
href="Detail">#97 ('NoneType' object has no attribute 'isocode')</a>, <a
title="Cannot delete foo" href="Detail">#109 (Cannot delete
foo)</a>.</span></p><span>You have <b>15 items in Tickets to triage</b>.</span>
The dashboard¶
As the application developer you define which actors are available as dashboard item for your application. You can do this in two different ways:
override the
get_dashboard_items
of yourPlugin
classes.override the
get_dashboard_items
of yourSite
class.
This list is hard-coded per application and applies to all users. But Lino respects view permissions, i.e. an item will appear only if the user has permission to see it. For each dashboard item you can specify certain options to influence how Lino renders them. For example they usually don't appear if the table contains no data.
Independently of how you define the dashboard items for your application, you
can additionally opt to install the lino.modlib.dashboard
plugin.
List of available dashboard items¶
The list of available dashboard items exists also without this plugin.
>>> ar = rt.login("robin")
>>> user = ar.get_user()
>>> pprint(list(settings.SITE.get_dashboard_items(user)))
...
[lino_xl.lib.cal.ui.MyTasks,
lino.core.dashboard.ActorItem(cal.MyEntries,header_level=2,min_count=None),
lino_xl.lib.cal.ui.MyOverdueAppointments,
lino_xl.lib.cal.ui.MyUnconfirmedAppointments,
lino_xl.lib.cal.ui.MyPresences,
lino_xl.lib.cal.ui.PublicEntries,
lino_xl.lib.calview.ui.DailyPlanner,
lino.modlib.comments.ui.RecentComments,
lino_xl.lib.tickets.ui.MyTickets,
lino_xl.lib.tickets.ui.MySites,
lino_xl.lib.tickets.ui.TicketsToTriage,
lino_xl.lib.tickets.ui.MyTicketsToWork,
lino_xl.lib.tickets.ui.TicketsNeedingMyFeedback,
lino_xl.lib.tickets.ui.MyTicketsNeedingFeedback,
lino_xl.lib.working.ui.WorkedHours,
lino.modlib.notify.models.MyMessages,
lino_xl.lib.groups.models.MyGroups,
lino_xl.lib.ledger.ui.MyMovements,
lino_xl.lib.ledger.ui.JournalsOverview]
Note that in practice you would probably prefer to not use above list directly, but rather its "processed" form, stored in the user's preferences:
>>> pprint(user.get_preferences().dashboard_items)
...
[lino.core.dashboard.ActorItem(cal.MyTasks,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(cal.MyEntries,header_level=2,min_count=None),
lino.core.dashboard.ActorItem(cal.MyOverdueAppointments,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(cal.MyUnconfirmedAppointments,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(cal.MyPresences,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(calview.DailyPlanner,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(comments.RecentComments,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(tickets.MyTickets,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(tickets.MySites,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(tickets.TicketsToTriage,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(tickets.MyTicketsToWork,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(tickets.TicketsNeedingMyFeedback,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(tickets.MyTicketsNeedingFeedback,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(working.WorkedHours,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(notify.MyMessages,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(groups.MyGroups,header_level=2,min_count=1),
lino.core.dashboard.ActorItem(ledger.JournalsOverview,header_level=2,min_count=1)]
Behind the scenes¶
The content of the main page is generated from the admin_main.html
template.
- admin_main_base.html¶
- admin_main.html¶
This is the template used to generate the content of the main page. It is split into two files admin_main.html and admin_main_base.html.
For illustration compare the content of the latter template with its
result in the following screenshots (taken from the noi1e
demo project which runs Lino Noi).

Main page for AnonymousUser.¶

Main page for user robin
.¶
Customizing the main page¶
You may define a custom admin_main.html
template, as we did
in The Lino Polls tutorial. But this was rather an exercise for pedagogical
reasons than something we would recommend to do for application developers.
You may even go further and override the get_main_html
method of your Site
class to return your own html.