Skip to content

Commit

Permalink
edits to Dashboard component page
Browse files Browse the repository at this point in the history
  • Loading branch information
jouni committed Dec 18, 2024
1 parent e6af6d1 commit 73e9c10
Showing 1 changed file with 87 additions and 63 deletions.
150 changes: 87 additions & 63 deletions articles/components/dashboard/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ version: since:com.vaadin:[email protected]


= Dashboard
:experimental:
:toclevels: 2

// tag::description[]
A component for building static dashboard layouts and dynamic, user-configurable dashboards.
Expand All @@ -25,7 +25,7 @@ include::{articles}/_commercial-banner.adoc[opts=optional]
:feature-flag: com.vaadin.experimental.dashboardComponent
include::{articles}/_preview-banner.adoc[opts=optional]

[.example]
[.example.tall]
--
ifdef::flow[]
[source,java]
Expand All @@ -49,29 +49,40 @@ include::{root}/frontend/demo/component/dashboard/dashboard-basic.ts[render,tags
endif::[]
--

Widgets are placed in columns and rows automatically, in the order supplied, based on the Dashboard's width and the column configuration. As the Dashboard's width changes, the number of columns is automatically adjusted based on their configured minimum and maximum width, and the widget positions are adjusted accordingly. Widgets can not be explicitly placed in a particular column or row.

The Dashboard provides built-in vertical scrolling, provided that its height has been specified.
== Key Features

The Dashboard component can be used in two ways:
[.term-width-auto]
*Static & Dynamic Dashboards*::
+
*<<#static-dashboards,Static>>*:
You define a dashboard and its widgets declaratively or imperatively. The React and Web Components for this are `<DashboardLayout>` & `<DashboardWidget>` and `<vaadin-dashboard-layout>` & `<vaadin-dashboard-widget>` respectively.
+
*<<#dynamic-dashboards,Dynamic>>*:
You define the data and Dashboard generates widgets using a renderer. Dynamic dashboards support edit mode that allows the end user to move, resize, and remove widgets. The React and Web Components for this are `<Dashboard>` and `<vaadin-dashboard>`, respectively.
+
In Flow, the `Dashboard` and `DashboardWidget` classes are used for both approaches.

* <<#static-dashboards,Static>>: declaratively / imperatively defining the widgets. The React and Web Components for this are `<DashboardLayout>` and `<vaadin-dashboard-layout>` respectively.
* <<#dynamic-dashboards,Dynamic>>: widgets generated from data using a renderer; supports edit mode that allows the end user to move, resize and remove widgets. The React and Web Components for this are `<Dashboard>` and `<vaadin-dashboard>`, respectively.
*Widgets, Columns & Rows*::
Widgets are placed in columns and rows automatically, in the order supplied, based on the dashboard's width and the <<columns-and-rows,column configuration>>. As the dashboard's width changes, the number of columns is automatically adjusted based on their configured minimum and maximum width, and the widget positions are adjusted so.
+
You can't place a widget in a specific column or row.

In Flow, the same `Dashboard` class is used for both approaches.
*Scrolling*::
Dashboard scrolls vertically if the contents overflow its defined height. Individual widgets don't scroll (see <<widget-content-sizing>>).


== Configuration

The following configuration options are available for the dashboard:
The following configuration options are available for the Dashboard component.

=== Columns and Rows
[[columns-and-rows]]
=== Columns & Rows

Column width can vary between a minimum and maximum size. The default maximum width is `1fr`, which allows the columns to expand to fill any available space. If a fixed length value is provided, empty space is left at the end of rows once the columns reach their maximum width.
Column width can vary between a minimum and maximum size. The default maximum width is `1fr`, which allows the columns to expand to fill any available space. If a fixed length value is provided, empty space is reserved at the end of rows once the columns reach their maximum width.

By default there is no limit on the number of columns, but one can be provided if needed.

The height of each dashboard row is determined by the tallest widget currently in that row (whose height in turn is determined by its contents). A minimum row height determines the height of empty rows, such as when a widget's row span is stretched into a previously unoccupied row. The minimum height can be configured.
The height of each dashboard row is determined by the tallest widget in that row, whose height in turn is determined by its contents. A minimum row height determines the height of empty rows, such as when a widget's row span is stretched into an unoccupied row. The minimum height can be configured.

[.example]
--
Expand Down Expand Up @@ -152,7 +163,7 @@ endif::[]
--

=== Dense Layout
This mode uses the dense packing algorithm in the CSS grid layout model, which attempts to fill in empty slots in the layout by placing smaller widgets in them, potentially affecting the order of the widgets. It should be used with caution in user-configurable dashboards, as the automatic reordering of widgets may be confusing during editing.
This mode uses the dense packing algorithm in the CSS grid layout model. It attempts to fill in empty slots in the layout by placing smaller widgets in them. This can affect the order of the widgets. It should be used with caution in user-configurable dashboards, as the automatic reordering of widgets may be confusing during editing.

[.example]
--
Expand Down Expand Up @@ -195,9 +206,9 @@ include::{root}/frontend/demo/component/dashboard/dashboard-dense-layout.ts[rend

== Widgets

Widgets consist of a content area and a header containing the widget's title and a slot for additional elements.
Widgets consist of a content area and a header containing the widget's title and a slot for more elements.

[.example]
[.example.short]
--
ifdef::flow[]
[source,java]
Expand All @@ -221,24 +232,25 @@ include::{root}/frontend/demo/component/dashboard/dashboard-widget-contents.ts[r
endif::[]
--

The column span and row span can be set to make the widget take up more than one column or row in the dashboard's layout. The actual number of columns a widget spans is limited by the number of columns currently in the dashboard, however.
You can set the column span and row span to make a widget take up more than one column or row in the dashboard's layout. The actual number of columns a widget spans is limited by the current number of columns in the dashboard, however.


=== Widget Content Sizing

The height of a widget's contents determine its default height, which can be expanded by row span and/or other widgets on the same dashboard row. The widget does not scroll, so the contents may need to incorporate a scrollable area of its own (e.g. by way of a <<../scroller#,Scroller>>) to accommodate a height smaller than its contents.
The height of a widget's contents define its default height. The height can grow because of row span or other taller widgets on the same dashboard row. If the height of the widget is constrained (e.g., by an explicitly set height), the contents of the card can overflow. You may need to incorporate a scrollable area (e.g., with <<../scroller#,Scroller>>) to accommodate a height smaller than the contents you place in a widget.

The widget's width, on the other hand, is determined by the current column width and the widget's column span.
The width of a widget is determined by the current column width and the widget's column span.

Contents that should cover the entire widget area should therefore be configured with 100% width and height, as well as a minimum height corresponding to its desired default height.


[#static-dashboards]
== Static Dashboards

Static dashboards are populated declaratively (in React and Lit) / imperatively (in Flow), like normal layouts. They're a good choice for hard-coded dashboards.
Static dashboards are populated declaratively (in React and Lit) / imperatively (in Flow), like normal layouts. They are a good choice for hard-coded dashboards.

[cols="1,1m"]
[.small]
[cols="1s,2m",frame=none,grid=rows]
|===

|Flow
Expand All @@ -252,7 +264,7 @@ Static dashboards are populated declaratively (in React and Lit) / imperatively

|===

[.example]
[.example.tall]
--
ifdef::flow[]
[source,java]
Expand Down Expand Up @@ -280,9 +292,10 @@ endif::[]
[#dynamic-dashboards]
== Dynamic, Editable Dashboards

Dynamic dashboards provide end user editability out of the box. They're populated through a data binding API coupled with a widget renderer function, so that their contents can be easily persisted to and loaded from storage, such as a database.
Dynamic dashboards offer end users the possibility to edit the layout. Dynamic dashboards are populated through a data-binding API coupled with a widget renderer function. This makes the layout configuration easy to persist and load from storage, such as a database.

[cols="1,1m"]
[.small]
[cols="1s,2m",frame=none,grid=rows]
|===

|Flow
Expand All @@ -296,7 +309,7 @@ Dynamic dashboards provide end user editability out of the box. They're populate

|===

[.example]
[.example.tall]
--
ifdef::flow[]
[source,java]
Expand Down Expand Up @@ -347,15 +360,13 @@ endif::[]

=== Editing

Dynamic dashboards can be made user editable by toggling on editing mode, as seen in the sample above.
You can make dynamic dashboards editable by turning on editing mode, as seen in the sample above.

.Editing mode should be temporary
.Editing mode should be temporary.
[NOTE]
====
Editing mode is intended as a temporary state that is engaged when the end user wants to edit the dashboard's contents, and disengaged when they're done editing, at which point the widget configuration is typically persisted to storage.
====
The end user turns on editing mode when they want to edit the dashboard's contents and turns it off when they finish editing. When turned off, you typically want to persist the dashboard configuration to a storage.

The following operations are available in editing mode:
The following operations are available in editing mode.

==== Widget Selection by Keyboard

Expand All @@ -365,35 +376,35 @@ Widget selection is not required for editing by pointer device.

==== Moving Widgets

In editing mode, widgets can be moved around by
In editing mode, widgets can be moved around by:

* Drag & drop
* Arrow keys, once the widget has been selected
* An accessible move-mode engaged by clicking the drag-handle in the widget's top left corner. Move-mode is disengaged by clicking the apply-button in the widget's center, or by pressing kbd:[Esc].
* drag & drop;
* arrow keys, once the widget has been selected;
* an accessible move-mode engaged by clicking the drag-handle in the widget's top left corner. Move-mode is disengaged by clicking the apply-button in the widget's center, or by pressing kbd:[Esc].

(Currently widgets can only be moved backwards and forwards; moving a widget past the start or end of a row moves it to the preceding or following row.)
Widgets can only be moved backwards and forwards. Moving a widget past the start or end of a row moves it to the preceding or following row.

==== Resizing Widgets

In editing mode, widgets can be resized by increasing and decreasing their column span and row span by
In editing mode, widgets can be resized by increasing and decreasing their column span and row span by:

* Dragging from the drag-handle in the widget's bottom right corner
* kbd:[Shift] + arrow keys, once the widget has been selected
* An accessible resize-mode engaged by clicking the resize-handle. Resize-mode is disengaged by clicking the apply-button in the widget's center, or by pressing kbd:[Esc].
* dragging from the drag-handle in the widget's bottom right corner;
* kbd:[Shift] + arrow keys, once the widget has been selected;
* an accessible resize-mode engaged by clicking the resize-handle. Resize-mode is disengaged by clicking the apply-button in the widget's center, or by pressing kbd:[Esc].

==== Removing Widgets

In editing mode, widgets can be removed by clicking the remove-button in the widget's top right corner.
In editing mode, widgets can be removed by clicking the [guilabel]*Remove* button in the widget's top right corner.

==== Adding Widgets

Dashboard has no built-in mechanism for adding new widgets, but this can easily be implemented using an external widget selector, such as a <<../select#,Select>> drop-down, that adds the corresponding item to the dashboard.
Dashboard has no built-in mechanism for adding new widgets. You can implement this using an external widget selector, such as a <<../select#,Select>> drop-down, that adds the corresponding item to the dashboard.

==== Screen Reader Announcements

Although widget selection is announced via the widget's title, and the various buttons all have accessible names, the component does not provide announcements of changes to the widget's position and size out of the box. These can be provided by listening to related events emitted by the component and updating custom live regions with appropriate announcements.
Although widget selection is announced via a widget's title, and the various buttons all have accessible names, the component doesn't announce changes to a widget's position and size out of the box. These can be provided by listening to related events emitted by the component and updating custom live regions with appropriate announcements.

[.example]
[.example.tall]
--
ifdef::flow[]
[source,java]
Expand Down Expand Up @@ -430,7 +441,7 @@ endif::[]

Dynamic dashboards, with their user-editable capabilities, often require the ability to persist and load customized widget configurations to and from storage, such as a database.

The most straightforward way to persist widget configurations is by defining a custom widget/item type. This type can include additional custom metadata relevant to the widget content, in addition to the built-in widget/item properties.
The most straightforward way to persist widget configurations is by defining a custom widget/item type. This type can include custom metadata relevant to the widget content, in addition to the built-in widget/item properties.

Once you've defined your custom type, you can establish a mapping between your data model and the widget configuration. This involves:

Expand All @@ -439,14 +450,14 @@ Once you've defined your custom type, you can establish a mapping between your d

This approach allows for flexible persistence of dashboard configurations, enabling users to save and load their customized layouts across sessions.

For a simple example of how to implement this persistence approach, refer to the <<#dynamic-dashboards>> section above. While the example doesnt explicitly demonstrate data persistence, it illustrates the concept of defining a custom type for the dashboard widgets. The specific implementation details depend on your chosen storage mechanism and data model.
For a simple example of how to implement this persistence approach, see the <<#dynamic-dashboards>> section above. While the example doesn't explicitly show how to persist the data, it illustrates the concept of defining a custom type for the dashboard widgets. The specific implementation details depend on your chosen storage mechanism and data model.


== Dashboard Sections

Complex dashboards can benefit from being divided into titled sections. Dashboard Sections always span the full width of the dashboard, and follow the same column and row configuration as the dashboard itself. They support the same moving and removal operations in editing mode as widgets.
Complex dashboards can benefit from being divided into titled sections. Dashboard sections always span the full width of the dashboard, and follow the same column and row configuration as the dashboard itself. They support the same moving and removal operations in editing mode as widgets.

[.example]
[.example.tall]
--
ifdef::flow[]
[source,java]
Expand Down Expand Up @@ -480,49 +491,49 @@ The following texts in the dashboard can be localized through the internationali
| Property | Description

|selectWidget
|Widget selection trigger
|Widget selection trigger.

|deselectWidget
|Widget deselection trigger
|Widget deselection trigger.

|selectSection
|Section selection trigger
|Section selection trigger.

|deselectSection
|Section deselection trigger
|Section deselection trigger.

|move
|Button that engages move-mode
|Button that engages move-mode.

|moveForward
|Move forward button (in move-mode)
|Move forward button in move-mode.

|moveBackward
|Move backward button (in move-mode)
|Move backward button in move-mode.

|moveApply
|Button that disengages move-mode
|Button that disengages move-mode.

|resize
|Button that engages resize-mode
|Button that engages resize-mode.

|resizeGrowWidth
|Grow width button (in resize-mode)
|Grow width button in resize-mode.

|resizeShrinkWidth
|Shrink width button (in resize-mode)
|Shrink width button in resize-mode.

|resizeGrowHeight
|Grow height button (in resize-mode)
|Grow height button in resize-mode.

|resizeShrinkHeight
|Shrink height button (in resize-mode)
|Shrink height button in resize-mode.

|resizeApply
|Button that disengages resize-mode
|Button that disengages resize-mode.

|remove
|Remove button
|Remove button.

|===

Expand Down Expand Up @@ -564,3 +575,16 @@ UNCOMMENT ONCE CARD PAGE EXISTS
////

[discussion-id]`d59db2ee-c3dd-446d-bd0d-40224b1f141e`

++++
<style>
/* Limit the amount of layout shifting when examples are rendered */
.code-example:not(.short) .render {
min-height: 450px !important;
}
.code-example.tall .render {
min-height: 700px !important;
}
</style>
++++

0 comments on commit 73e9c10

Please sign in to comment.