Skip to content

Commit

Permalink
feat: support elements in dashboard items (#7761)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivirkki authored Sep 5, 2024
1 parent b5bc352 commit a590b1b
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 8 deletions.
26 changes: 19 additions & 7 deletions packages/dashboard/src/vaadin-dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab
if (cell.firstElementChild && cell.firstElementChild.localName === 'vaadin-dashboard-section') {
return;
}
if (renderer) {
if (cell.__item.component instanceof HTMLElement) {
if (cell.__item.component.parentElement !== cell) {
cell.textContent = '';
cell.appendChild(cell.__item.component);
}
} else if (renderer) {
renderer(cell, this, { item: cell.__item });
} else {
cell.innerHTML = '';
Expand All @@ -137,13 +142,20 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab
`.trim();

if (item.items) {
const itemHasComponent = item.component instanceof HTMLElement;
if (itemHasComponent) {
render(this.__renderItemCells(item.items), item.component);
}

return html`<vaadin-dashboard-widget-wrapper .__item="${item}" style="${style}">
<vaadin-dashboard-section
.sectionTitle="${item.title}"
?highlight="${this.__widgetReorderController.draggedItem}"
>
${this.__renderItemCells(item.items)}
</vaadin-dashboard-section>
${itemHasComponent
? item.component
: html` <vaadin-dashboard-section
.sectionTitle="${item.title}"
?highlight="${this.__widgetReorderController.draggedItem}"
>
${this.__renderItemCells(item.items)}
</vaadin-dashboard-section>`}
</vaadin-dashboard-widget-wrapper>`;
}

Expand Down
62 changes: 61 additions & 1 deletion packages/dashboard/test/dashboard.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { expect } from '@vaadin/chai-plugins';
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import '../vaadin-dashboard.js';
import type { CustomElementType } from '@vaadin/component-base/src/define.js';
import type { Dashboard, DashboardItem } from '../vaadin-dashboard.js';
import { getDraggable, getElementFromCell, setGap, setMaximumColumnWidth, setMinimumColumnWidth } from './helpers.js';

type TestDashboardItem = DashboardItem & { id: string };
type TestDashboardItem = DashboardItem & { id: string; component?: Element | string };

describe('dashboard', () => {
let dashboard: Dashboard<TestDashboardItem>;
Expand Down Expand Up @@ -160,4 +161,63 @@ describe('dashboard', () => {
expect(draggable.getBoundingClientRect().height).to.be.above(0);
});
});

describe('item components', () => {
it('should use the item component as widget', async () => {
const widget = fixtureSync('<vaadin-dashboard-widget widget-title="Component 0"></vaadin-dashboard-widget>');
dashboard.items = [{ id: 'Item 0', component: widget }];
await nextFrame();

expect(getElementFromCell(dashboard, 0, 0)).to.equal(widget);
});

it('should render default widgets if component is not an element', async () => {
dashboard.items = [{ id: 'Item 0', component: 'not-an-element' }];
await nextFrame();

const widget = getElementFromCell(dashboard, 0, 0);
expect(widget).to.be.ok;
expect(widget?.localName).to.equal('vaadin-dashboard-widget');
expect(widget).to.have.property('widgetTitle', 'Item 0 title');
});

it('should not call renderer for item components', async () => {
const renderer = sinon.spy();
dashboard.renderer = renderer;
const widget = fixtureSync('<vaadin-dashboard-widget widget-title="Component 0"></vaadin-dashboard-widget>');
dashboard.items = [{ id: 'Item 0', component: widget }];
await nextFrame();

expect(renderer).to.not.be.called;
});

it('should use the item component as section', async () => {
const section = fixtureSync(`<vaadin-dashboard-section section-title="Section"></vaadin-dashboard-section>`);
const widget = fixtureSync('<vaadin-dashboard-widget widget-title="Component 0"></vaadin-dashboard-widget>');
(dashboard as any).items = [
{
component: section,
items: [{ id: 'Item 0', component: widget }],
},
];
await nextFrame();

expect(getElementFromCell(dashboard, 0, 0)).to.equal(widget);
expect(section.contains(widget)).to.be.true;
});

it('should render default section if component is not an element', async () => {
(dashboard as any).items = [{ component: 'not-an-element', title: 'Section', items: [{ id: 'Item 0' }] }];
await nextFrame();

const widget = getElementFromCell(dashboard, 0, 0);
expect(widget).to.be.ok;
expect(widget?.localName).to.equal('vaadin-dashboard-widget');
expect(widget).to.have.property('widgetTitle', 'Item 0 title');

const section = widget?.closest('vaadin-dashboard-section');
expect(section).to.be.ok;
expect(section?.sectionTitle).to.equal('Section');
});
});
});

0 comments on commit a590b1b

Please sign in to comment.