diff --git a/cypress/fixtures/flows/dashboard-button-wrap.json b/cypress/fixtures/flows/dashboard-button-wrap.json new file mode 100644 index 000000000..8724bdb33 --- /dev/null +++ b/cypress/fixtures/flows/dashboard-button-wrap.json @@ -0,0 +1,151 @@ +[ + { + "id": "dashboard-bw-tab", + "type": "tab", + "label": "Button Wrap", + "disabled": false, + "info": "" + }, + { + "id": "dashboard-ui-base", + "type": "ui-base", + "name": "UI Name", + "path": "/dashboard", + "includeClientData": true, + "acceptsClientConfig": [ + "ui-notification", + "ui-control" + ] + }, + { + "id": "dashboard-ui-theme", + "type": "ui-theme", + "name": "Theme", + "colors": { + "surface": "#ffffff", + "primary": "#0094ce", + "bgPage": "#eeeeee", + "groupBg": "#ffffff", + "groupOutline": "#cccccc" + } + }, + { + "id": "dashboard-ui-theme-compact", + "type": "ui-theme", + "name": "Theme Compact", + "colors": { + "surface": "#ffffff", + "primary": "#0094ce", + "bgPage": "#eeeeee", + "groupBg": "#ffffff", + "groupOutline": "#cccccc" + }, + "sizes": { + "pagePadding": "12px", + "groupGap": "12px", + "groupBorderRadius": "4px", + "widgetGap": "12px", + "density": "compact" + } + }, + { + "id": "dashboard-ui-page-1", + "type": "ui-page", + "name": "Page 1", + "ui": "dashboard-ui-base", + "path": "/page1", + "icon": "home", + "layout": "grid", + "theme": "dashboard-ui-theme", + "order": 1, + "className": "", + "visible": "true", + "disabled": false + }, + { + "id": "dashboard-ui-page-2", + "type": "ui-page", + "name": "Page 2", + "ui": "dashboard-ui-base", + "path": "/page2", + "icon": "home", + "layout": "grid", + "theme": "dashboard-ui-theme-compact", + "order": 2, + "className": "", + "visible": "true", + "disabled": false + }, + { + "id": "dashboard-ui-group", + "type": "ui-group", + "name": "G", + "page": "dashboard-ui-page-1", + "width": "2", + "height": "1", + "order": 1, + "showTitle": true, + "className": "", + "visible": "true", + "disabled": "false" + }, + { + "id": "dashboard-ui-group-2", + "type": "ui-group", + "name": "G2", + "page": "dashboard-ui-page-2", + "width": "2", + "height": "1", + "order": 1, + "showTitle": true, + "className": "", + "visible": "true", + "disabled": "false" + }, + { + "id": "dashboard-btn-long", + "type": "ui-button", + "z": "dashboard-bw-tab", + "group": "dashboard-ui-group", + "name": "", + "label": "Acknowledge compressor fault", + "order": 1, + "width": 1, + "height": 1, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 300, + "y": 80, + "wires": [[]] + }, + { + "id": "dashboard-btn-long-compact", + "type": "ui-button", + "z": "dashboard-bw-tab", + "group": "dashboard-ui-group-2", + "name": "", + "label": "Acknowledge compressor fault", + "order": 1, + "width": 1, + "height": 1, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 300, + "y": 160, + "wires": [[]] + } +] diff --git a/cypress/tests/widgets/button-wrap.spec.js b/cypress/tests/widgets/button-wrap.spec.js new file mode 100644 index 000000000..4ac7ec346 --- /dev/null +++ b/cypress/tests/widgets/button-wrap.spec.js @@ -0,0 +1,39 @@ +describe('Node-RED Dashboard 2.0 - Button label wrapping (#151, #551)', () => { + beforeEach(() => { + cy.deployFixture('dashboard-button-wrap') + cy.visit('/dashboard/page1') + }) + + it('wraps a long label instead of clipping it at each end', () => { + const content = '#nrdb-ui-widget-dashboard-btn-long .v-btn__content' + cy.get(content).should('have.css', 'white-space', 'normal') + // eslint-disable-next-line promise/always-return, promise/catch-or-return + cy.get(`${content} span`).then(($span) => { + const range = $span[0].ownerDocument.createRange() + range.selectNodeContents($span[0]) + expect(range.getClientRects().length, 'label lays out on multiple lines (wrapped, not clipped on one)').to.be.greaterThan(1) + }) + }) + + it('clamps the label so the button never overflows its cell', () => { + const widget = '#nrdb-ui-widget-dashboard-btn-long' + // eslint-disable-next-line promise/always-return, promise/catch-or-return + cy.get(widget).then(($w) => { + const cell = $w[0].getBoundingClientRect() + const btn = $w[0].querySelector('.v-btn').getBoundingClientRect() + expect(btn.bottom, 'button stays within its cell (no overflow past the card)').to.be.at.most(cell.bottom + 1) + }) + }) + + it('stays within its cell on the compact (32px row) theme too', () => { + cy.visit('/dashboard/page2') + cy.get('.nrdb-app').should('have.class', 'nrdb-view-density--compact') + const widget = '#nrdb-ui-widget-dashboard-btn-long-compact' + // eslint-disable-next-line promise/always-return, promise/catch-or-return + cy.get(widget).then(($w) => { + const cell = $w[0].getBoundingClientRect() + const btn = $w[0].querySelector('.v-btn').getBoundingClientRect() + expect(btn.bottom, 'compact button stays within its cell').to.be.at.most(cell.bottom + 1) + }) + }) +}) diff --git a/ui/src/widgets/ui-button/UIButton.vue b/ui/src/widgets/ui-button/UIButton.vue index ad16e3b5a..ce83794a2 100644 --- a/ui/src/widgets/ui-button/UIButton.vue +++ b/ui/src/widgets/ui-button/UIButton.vue @@ -147,6 +147,15 @@ export default {