Panel Controls
Panel controls provides a unified interface for controlling lists inside of a panel.
Tabs + Search
No Pagination
Text here
Pagination
Pagination with Bulk actions
Sample Custom Toolbar
Kitchen Sink
Name | Email Marketing | Join Date | Last Activity | |||
---|---|---|---|---|---|---|
|
Albert Flores | [email protected] | Never Subcribed | 8/2/19 | 8/2/19 | |
|
Eleanor Pena | [email protected] | Unsubscribed | 7/11/19 | 7/11/19 | |
|
Arlene McCoy | [email protected] | Unsubscribed | 6/21/19 | 6/21/19 | |
|
Kathryn Murphy | [email protected] | Subscribed | 4/4/18 | 4/4/18 |
List properties
This component is set up to pair with a target table.
The following data-
properties can be set on the table
in order for the two to sync up well:
Property | Value | Notes |
---|---|---|
data-js-list-items-total |
Number | Total number of items that are available, even beyond this current page. |
data-js-list-items-shown |
Number | Total number of items possible in this view. Consider this the "page size" or maximum number of items the view will show at any one time. |
data-js-list-page |
Number | Current page being shown |
data-js-list-noun |
String | The noun used to describe the items in the table. A plural and singular value can be provided separated by a comma. |
Events
This component is set up to pair with a table of items. As a result, these controls can sort, navigate between pages, and apply bulk actions when the actions exposed here are paired with corresponding responders in context.
- All these custom events are mapped to the
sage.panelControls.change
event type. The
detail
property of this custom event always contains the following along with additional properties outlined in detail below:type
: the more specific type of event in the context of the Panel ControlstargetListId
: the id of the list to be targetted by the action
Pagination events type: "pagination:[next|prev]"
As the user clicks on the "next" or "previous" buttons, they will fire the corresponding event type. It is up the the responder to interpret and adjust the list accordingly.
Expand/Collapse events type: "list:[collapse|expand]"
As the user clicks on the "expand" or "collapse" buttons, they will fire the corresponding event type. It is up the the responder to interpret and adjust the list accordingly.
Selection events type: "list:[selectAll|selectNone|selectSome]"
As the user toggles the "select all" checkbox the corresponding event type is issued. It is up the the responder to interpret and adjust the list accordingly.
When pairing with a target table, clicking on items' checkboxes should affect
what the bulk actions/item count label should display.
So the Sage.panelControls
also exposes a handleItemSelection()
method as an aid for this.
Call this method in sync with click events on such checkboxes and the pass the following object:
{
target: <Object: the event target>,
total: <Number: the total number of items selected>,
}
This dispatches the list:selectSome
event detail type with the target
and total
values
passed along for the panel controls to recieve and interpret.
Sorting events type: "list:sort"
Items provided to the sort_items
should set the data-js-list-sort-by
attribute
with the name of the field to be sorted by the responder.
This value is passed to the detail
of the custom event
through the sortBy
property.
Bulk action events type: "list:action"
Items provided to the bulk_action_items
should set the data-js-action
attribute
with the name of an action to be exposed to the responder.
This value is passed to the detail
of the custom event
through the action
property.
Any additional properties may be provided as data attributes
and accessible on the custom event's target.dataset
property.
Sage Component
SagePanelControls
<%
tabs = sage_component(SageTabs, {
items: [
{
text: "Test 1",
attributes: { href: "#test-1" },
active: true
},
{
text: "Test 2",
attributes: { href: "#test-2" },
},
{
text: "Test 3",
attributes: { href: "#test-3" },
}
]
})
search = sage_component(SageSearch, { placeholder: "Find...", contained: true, })
dropdown = sage_component(SageDropdown, {
search: true,
trigger_type: "select",
align: "right",
items: [
{
value: "-- None --"
}, {
value: "Option 1",
}, {
value: "Option 2",
}, {
value: "Option 3",
}
],
content: %(
#{sage_component(SageButton, {
style: "secondary",
value: "",
css_classes: "sage-dropdown__trigger-selected-value",
icon: { style: "right", name: "caret-down" },
})}
<label class="sage-dropdown__trigger-label">Select an option...</label>
).html_safe
})
search_filter_toolbar = %(
<div class="sage-panel-controls__toolbar-btn-group">
#{search}
#{
sage_component(SageButton, {
value: "Saved filters",
style: "secondary",
icon: { name: "favorite", style: "left" },
})
}
#{
sage_component(SageButton, {
value: "Filters",
style: "secondary",
icon: { name: "filters", style: "left" },
})
}
#{
sage_component(SageButton, {
value: "Clear filters",
style: "secondary",
icon: { name: "remove", style: "left" },
})
}
</div>
).html_safe
sort_items = [
{
value: "Name",
attributes: {
"href": "#",
"data-js-list-sort-by": "name"
},
},
{
value: "Email",
attributes: {
"href": "#",
"data-js-list-sort-by": "email"
},
},
{
value: "Join date",
attributes: {
"href": "#",
"data-js-list-sort-by": "join_date"
},
}
]
actions_items = [
{
value: "Delete",
attributes: {
"href": "#",
"data-js-list-action": "delete_selected",
},
},
{
value: "Set marketing",
attributes: {
"href": "#",
"data-js-list-action": "set_marketing_unsubscribed",
},
}
]
%>
<h3 class="t-sage-heading-6">Tabs + Search</h3>
<%= sage_component SagePanel, {} do %>
<%= sage_component SagePanelControls, {} do %>
<% content_for :sage_panel_controls_tabs do %>
<%= tabs %>
<% end %>
<% content_for :sage_panel_controls_toolbar do %>
<%= search %>
<% end %>
<% end %>
<% end %>
<h3 class="t-sage-heading-6">No Pagination</h3>
<%= sage_component SagePanel, {} do %>
<%= sage_component SagePanelControls, {
item_count_label: "Text here",
show_bulk_actions: false,
show_expand_collapse: true,
show_pagination: false,
show_sort: true,
bulk_action_items: actions_items,
} do %>
<% content_for :sage_panel_controls_sort do %>
<%= sage_component SageDropdown, {
trigger_type: "select",
align: "right",
customized: true,
contained: true,
css_classes: "sage-dropdown--sort sage-panel-controls__sorts",
items: sort_items
} do %>
<%= sage_component SageButton, {
style: "secondary",
value: "",
css_classes: "sage-dropdown__trigger-selected-value",
icon: { style: "right", name: "caret-down" },
} %>
<label class="sage-dropdown__trigger-label">Sort</label>
<% end %>
<% end %>
<% end %>
<% end %>
<h3 class="t-sage-heading-6">Pagination</h3>
<%= sage_component SagePanel, {} do %>
<%= sage_component SagePanelControls, {
show_bulk_actions: false,
show_expand_collapse: true,
show_pagination: true,
show_sort: true,
bulk_action_items: actions_items,
} do %>
<% content_for :sage_panel_controls_pagination do %>
<%= sage_component SagePagination, {
items: Kaminari.paginate_array(Array.new(30, 1)).page(1).per(10),
collection_name: "Items",
page_count_prefix: "Displaying",
page_count_suffix: "in the last <strong>30 days</strong>".html_safe,
window: 2,
hide_pages: true,
} %>
<% end %>
<% end %>
<% end %>
<h3 class="t-sage-heading-6">Pagination with Bulk actions</h3>
<%= sage_component SagePanel, {} do %>
<%= sage_component SagePanelControls, {
show_bulk_actions: true,
show_expand_collapse: true,
show_pagination: true,
show_sort: true,
bulk_action_items: actions_items,
} do %>
<% content_for :sage_panel_controls_pagination do %>
<%= sage_component SagePagination, {
items: Kaminari.paginate_array(Array.new(30, 1)).page(1).per(10),
collection_name: "Some name here",
window: 2,
hide_pages: true,
} %>
<% end %>
<% content_for :sage_panel_controls_sort do %>
<%= sage_component SageDropdown, {
trigger_type: "select",
align: "right",
customized: true,
contained: true,
css_classes: "sage-dropdown--sort sage-panel-controls__sorts",
items: sort_items
} do %>
<%= sage_component SageButton, {
style: "secondary",
value: "",
css_classes: "sage-dropdown__trigger-selected-value",
icon: { style: "right", name: "caret-down" },
} %>
<label class="sage-dropdown__trigger-label">Sort</label>
<% end %>
<% end %>
<% end %>
<% end %>
<h3 class="t-sage-heading-6">Sample Custom Toolbar</h3>
<%= sage_component SagePanel, {} do %>
<%= sage_component SagePanelControls, {} do %>
<% content_for :sage_panel_controls_toolbar do %>
<%= search_filter_toolbar %>
<%= dropdown %>
<% end %>
<% end %>
<% end %>
<h3 class="t-sage-heading-6">Kitchen Sink</h3>
<%= sage_component SagePanel, {} do %>
<%= sage_component SagePanelControls, {
show_bulk_actions: true,
show_expand_collapse: true,
show_pagination: true,
show_sort: true,
bulk_action_items: actions_items,
target: "demo-table",
} do %>
<% content_for :sage_panel_controls_tabs do %>
<%= tabs %>
<% end %>
<% content_for :sage_panel_controls_toolbar do %>
<%= search_filter_toolbar %>
<%= dropdown %>
<% end %>
<% content_for :sage_panel_controls_pagination do %>
<%= sage_component SagePagination, {
items: Kaminari.paginate_array(Array.new(30, 1)).page(1).per(10),
collection_name: "Some name here",
window: 2,
hide_pages: true,
} %>
<% end %>
<% content_for :sage_panel_controls_sort do %>
<%= sage_component SageDropdown, {
trigger_type: "select",
align: "right",
customized: true,
contained: true,
css_classes: "sage-dropdown--sort sage-panel-controls__sorts",
items: sort_items
} do %>
<%= sage_component SageButton, {
style: "secondary",
value: "",
css_classes: "sage-dropdown__trigger-selected-value",
icon: { style: "right", name: "caret-down" },
} %>
<label class="sage-dropdown__trigger-label">Sort</label>
<% end %>
<% end %>
<% end %>
<%= sage_component SageTable, {
html_attributes: {
id: "demo-table",
"data-js-list-items-total": "4",
"data-js-list-items-shown": "25",
"data-js-list-page": "1",
"data-js-list-noun": "People,Person",
},
reset_above: true,
headers: [
{
value: "",
data_type: "checkbox",
},
{
value: "",
data_type: "avatar",
},
"Name",
"Email",
"Email Marketing",
"Join Date",
"Last Activity",
],
rows: [
{
selected: sage_component(SageCheckbox, { value: "", standalone: true, checked: true }),
avatar: sage_component(SageAvatar, { initials: "AF", color: "purple" }),
name: "Albert Flores",
email: "[email protected]",
marking: "Never Subcribed",
joinDate: "8/2/19",
lastActivity: "8/2/19",
},
{
selected: sage_component(SageCheckbox, { value: "", standalone: true, checked: true }),
avatar: sage_component(SageAvatar, { initials: "EP", color: "orange" }),
name: "Eleanor Pena",
email: "[email protected]",
marking: "Unsubscribed",
joinDate: "7/11/19",
lastActivity: "7/11/19",
},
{
selected: sage_component(SageCheckbox, { value: "", standalone: true }),
avatar: sage_component(SageAvatar, { initials: "AM", color: "sage" }),
name: "Arlene McCoy",
email: "[email protected]",
marking: "Unsubscribed",
joinDate: "6/21/19",
lastActivity: "6/21/19",
},
{
selected: sage_component(SageCheckbox, { value: "", standalone: true }),
avatar: sage_component(SageAvatar, { initials: "KM" }),
name: "Kathryn Murphy",
email: "[email protected]",
marking: "Subscribed",
joinDate: "4/4/18",
lastActivity: "4/4/18",
}
]
}
%>
<% end %>
<%= md(%(
#### List properties
This component is set up to pair with a target table.
The following `data-` properties can be set on the table
in order for the two to sync up well:
| Property | Value | Notes |
| --- | --- | --- |
| `data-js-list-items-total` | Number | Total number of items that are available, even beyond this current page. |
| `data-js-list-items-shown` | Number | Total number of items possible in this view. Consider this the "page size" or maximum number of items the view will show at any one time. |
| `data-js-list-page` | Number | Current page being shown |
| `data-js-list-noun` | String | The noun used to describe the items in the table. A plural and singular value can be provided separated by a comma. |
#### Events
This component is set up to pair with a table of items.
As a result, these controls can sort, navigate between pages,
and apply bulk actions when the actions exposed here
are paired with corresponding responders in context.
- All these custom events are mapped to the `sage.panelControls.change` event type.</li>
- The `detail` property of this custom event always contains the following
along with additional properties outlined in detail below:
- `type`: the more specific type of event in the context of the Panel Controls
- `targetListId`: the id of the list to be targetted by the action
##### Pagination events `type: "pagination:[next|prev]"`
As the user clicks on the "next" or "previous" buttons,
they will fire the corresponding event type.
It is up the the responder to interpret and adjust the list accordingly.
##### Expand/Collapse events `type: "list:[collapse|expand]"`
As the user clicks on the "expand" or "collapse" buttons,
they will fire the corresponding event type.
It is up the the responder to interpret and adjust the list accordingly.
##### Selection events `type: "list:[selectAll|selectNone|selectSome]"`
As the user toggles the "select all" checkbox the corresponding event type is issued.
It is up the the responder to interpret and adjust the list accordingly.
When pairing with a target table, clicking on items' checkboxes should affect
what the bulk actions/item count label should display.
So the `Sage.panelControls` also exposes a `handleItemSelection()` method as an aid for this.
Call this method in sync with click events on such checkboxes and the pass the following object:
```
{
target: <Object: the event target>,
total: <Number: the total number of items selected>,
}
```
This dispatches the `list:selectSome` event detail type with the `target` and `total` values
passed along for the panel controls to recieve and interpret.
##### Sorting events `type: "list:sort"`
Items provided to the `sort_items`
should set the `data-js-list-sort-by` attribute
with the name of the field to be sorted by the responder.
This value is passed to the `detail` of the custom event
through the `sortBy` property.
##### Bulk action events `type: "list:action"`
Items provided to the `bulk_action_items`
should set the `data-js-action` attribute
with the name of an action to be exposed to the responder.
This value is passed to the `detail` of the custom event
through the `action` property.
Any additional properties may be provided as data attributes
and accessible on the custom event's `target.dataset` property.
), use_sage_type: true) %>
<script>
// Target table
let table = null;
// Table items
let items = null;
// Count selected elements
let selectedItems = null;
let selectedItemsCount = null;
// Panel Controls object
let panelControls = null;
// Functions
const setupPanelControls = () => {
table = document.getElementById('demo-table');
// Ensure matching table exists
if (!table) {
return;
}
items = table.querySelectorAll('tr');
selectedItems = table.querySelectorAll(':checked');
selectedItemsCount = selectedItems ? selectedItems.length : null;
// Set up event handlers
table.addEventListener('click', (ev) => {
const target = ev.target;
if (target.classList.contains('sage-checkbox')) {
handleClickCheckbox(target);
}
});
document.addEventListener('sage.panelControls.change', (ev) => {
switch (ev.detail.type) {
case 'list:selectAll':
items.forEach(tr => {
const cb = tr.querySelector('td .sage-checkbox--standalone');
if (cb) {
cb.checked = true;
}
});
selectedItems = table.querySelectorAll(':checked');
selectedItemsCount = selectedItems.length;
break;
case 'list:selectNone':
items.forEach(tr => {
const cb = tr.querySelector('td .sage-checkbox--standalone');
if (cb) {
cb.checked = false;
}
});
selectedItems = null;
selectedItemsCount = 0;
break;
default:
break;
}
});
};
const handleClickCheckbox = (target) => {
if (target.checked) {
selectedItemsCount++;
} else {
selectedItemsCount--;
}
Sage.panelControls.handleItemSelection({ target, total: selectedItemsCount });
};
const ready = (callback) => {
if (document.readyState != "loading") callback();
else document.addEventListener("DOMContentLoaded", callback);
}
ready(() => {
if (Sage.panelControls) setupPanelControls();
});
</script>
Property | Description | Type | Default |
---|---|---|---|
|
The list of items to populate in the bulk actions dropdown. |
|
|
|
The list of items to populate in the bulk actions dropdown. |
Array: See structure for Dropdown items |
|
|
Maps records to create page link items |
Object |
|
|
A caption for the bulk actions checkbox. |
String |
Select all |
|
Whether or not to render the bulk actions checkmark and dropdown.
If set to |
Boolean |
|
|
When enabled, shows the checkbox and allows for selection of the adjacent list. |
Boolean |
|
|
Whether or not to show the "expand"/"collapse" button toggle.
If set to |
Boolean |
|
|
The list of items to populate in the sort dropdown. |
|
|
|
TBD |
Boolean |
|
|
Whether or not to render the sorting dropdown.
If set to |
Boolean |
|
|
Whether or not the controls should start as expanded or collapsed. This merely affects which of the two buttons appears by default and should be syncronized with the actual target list. |
Boolean |
|
|
The HTML ID for the list this panel controls will target with any events. |
String |
|
Sections |
|
||
|
This area holds the pagination for the component. |
|
|
|
This area holds the buttons that will navigate to subpages. |
|
|
|
This area holds the tabs linking to sub pages. |
|
|
|
This area holds the dropdown that navigates between Products. This resides next to the tabs at the top of the component. |
|
|
|
This area holds the sort dropdown. |
|