From 079dbdd019da4c6abd2a7b2940eccd206db8181b Mon Sep 17 00:00:00 2001 From: Dave Lockhart Date: Fri, 7 Jul 2023 16:58:55 -0400 Subject: [PATCH] improved bar for test settings --- src/server/report/app.js | 62 +++++------- src/server/report/common.js | 37 +++++++ src/server/report/icons.js | 14 +++ src/server/report/test-result.js | 23 +++-- src/server/report/test.js | 159 +++++++++++++++++++++++++++++++ 5 files changed, 245 insertions(+), 50 deletions(-) create mode 100644 src/server/report/common.js create mode 100644 src/server/report/icons.js create mode 100644 src/server/report/test.js diff --git a/src/server/report/app.js b/src/server/report/app.js index 6b7873c9..a7f5e71f 100644 --- a/src/server/report/app.js +++ b/src/server/report/app.js @@ -1,20 +1,17 @@ -import './test-result.js'; +import './test.js'; import { css, html, LitElement, nothing } from 'lit'; +import { FILTER_STATUS, FULL_MODE, LAYOUTS } from './common.js'; +import { classMap } from 'lit/directives/class-map.js'; import data from './data.js'; import page from 'page'; -const FILTER_STATUS = { - ALL: 'All', - PASSED: 'Passed', - FAILED: 'Failed' -}; - class App extends LitElement { static properties = { _files: { state: true }, _filterFile: { state: true }, _filterTest: { state: true }, - _mode: { state: true }, + _fullMode: { state: true }, + _layout: { state: true }, _overlay: { state: true } }; static styles = [css` @@ -26,7 +23,7 @@ class App extends LitElement { } aside { background-color: #fff; - border: 1px solid #e6e6e6; + border-right: 1px solid #e6e6e6; box-shadow: 0 0 6px rgba(0,0,0,.07); box-sizing: border-box; grid-area: sidebar; @@ -42,9 +39,6 @@ class App extends LitElement { background-color: #fafafa; grid-area: content; } - main > div { - padding: 20px; - } table { background-color: #ffffff; border-collapse: collapse; @@ -75,12 +69,16 @@ class App extends LitElement { fieldset > legend { font-weight: bold; } + .padding { + padding: 20px; + } `]; constructor() { super(); this._filterBrowsers = data.browsers.map(b => b.name); this._filterStatus = data.numFailed > 0 ? FILTER_STATUS.FAILED : FILTER_STATUS.ALL; - this._mode = 'sideBySide'; + this._fullMode = FULL_MODE.GOLDEN.value; + this._layout = LAYOUTS.SPLIT.value; this._overlay = true; this._updateFiles(); } @@ -104,7 +102,7 @@ class App extends LitElement { page(); } render() { - let view; + let hasPadding = true, view; if (this._filterFile !== undefined && this._filterTest !== undefined) { const fileData = data.files.find(f => f.name === this._filterFile); if (!fileData) { @@ -114,7 +112,13 @@ class App extends LitElement { if (!testData) { view = html`

Test not found: ${this._filterTest}.

`; } else { - view = this._renderTest(fileData, testData); + hasPadding = false; + view = html` + +
+ +
+ `; } } } else { @@ -132,7 +136,7 @@ class App extends LitElement { ${this._renderFilters()} -
${view}
+
${view}
`; } @@ -152,11 +156,8 @@ class App extends LitElement { this._filterStatus = e.target.value; this._updateFiles(); } - _handleModeChange(e) { - this._mode = e.target.options[e.target.selectedIndex].value; - } - _handleOverlayChange(e) { - this._overlay = e.target.checked; + _handleSettingChange(e) { + this[`_${e.detail.name}`] = e.detail.value; } _renderFile(file) { const renderBrowserCell = (b) => { @@ -218,25 +219,6 @@ class App extends LitElement { `; } - _renderTest(file, test) { - return html` -

${test.name} (${(test.results.length - test.numFailed)}/${test.results.length} passed)

-
- - -
- ${test.results.map(r => html``)} -
- -
- `; - } _renderTestResultRow(file, test) { const results = data.browsers.map(b => { if (!this._filterBrowsers.includes(b.name)) return nothing; diff --git a/src/server/report/common.js b/src/server/report/common.js new file mode 100644 index 00000000..2d49fa0a --- /dev/null +++ b/src/server/report/common.js @@ -0,0 +1,37 @@ +import { ICON_FULL, ICON_SPLIT } from './icons.js'; + +export const FILTER_STATUS = { + ALL: 'All', + PASSED: 'Passed', + FAILED: 'Failed' +}; + +export const FULL_MODE = { + GOLDEN: { + label: 'Golden', + value: 'golden' + }, + NEW: { + label: 'New', + value: 'new' + } +}; + +export const LAYOUTS = { + FULL: { + label: 'Full', + icon: ICON_FULL, + value: 'full' + }, + SPLIT: { + label: 'Split', + icon: ICON_SPLIT, + value: 'split' + } +}; + +let id = 0; +export function getId() { + id++; + return `id-${id}`; +} diff --git a/src/server/report/icons.js b/src/server/report/icons.js new file mode 100644 index 00000000..56cb0b2e --- /dev/null +++ b/src/server/report/icons.js @@ -0,0 +1,14 @@ +import { svg } from 'lit'; + +export const ICON_FULL = svg` + + + +`; + +export const ICON_SPLIT = svg` + + + + +`; diff --git a/src/server/report/test-result.js b/src/server/report/test-result.js index 6f6f098b..045ae85b 100644 --- a/src/server/report/test-result.js +++ b/src/server/report/test-result.js @@ -1,31 +1,33 @@ import { css, html, LitElement, nothing } from 'lit'; +import { FULL_MODE, LAYOUTS } from './common.js'; import data from './data.js'; class TestResult extends LitElement { static properties = { browser: { type: String }, - mode: { type: String }, + fullMode: { attribute: 'full-mode', type: String }, + layout: { type: String }, file: { type: String }, showOverlay: { attribute: 'show-overlay', type: Boolean }, test: { type: String }, }; static styles = [css` - .side-by-side { + .split { flex-direction: row; flex-wrap: nowrap; display: flex; gap: 10px; } - .side-by-side > div { + .split > div { flex: 0 1 auto; } img { max-width: 100%; } .diff-container { - background: repeating-conic-gradient(#cccccc 0% 25%, #ffffff 0% 50%) 50% / 20px 20px; + background: repeating-conic-gradient(#cdd5dc 0% 25%, #ffffff 0% 50%) 50% / 20px 20px; background-position: 0 0; - border: 1px solid #cccccc; + border: 1px solid #cdd5dc; display: inline-block; line-height: 0; } @@ -37,9 +39,10 @@ class TestResult extends LitElement { position: absolute; top: 0; left: 0; + z-index: 1; } .no-changes { - border: 1px solid #cccccc; + border: 1px solid #cdd5dc; padding: 20px; } `]; @@ -87,18 +90,18 @@ class TestResult extends LitElement { const overlay = (this.showOverlay && !resultData.passed) ? html`
` : nothing; - if (this.mode === 'sideBySide') { + if (this.layout === LAYOUTS.SPLIT.value) { const g = html`
${goldenImage}
`; return html` -
+
${ resultData.passed ? noChanges : g }
${newImage}${overlay}
`; - } else { + } else if (this.layout === LAYOUTS.FULL.value) { return html`
- ${(this.mode === 'oneUpOriginal') ? goldenImage : newImage} + ${(this.fullMode === FULL_MODE.GOLDEN.value) ? goldenImage : newImage} ${overlay}
`; diff --git a/src/server/report/test.js b/src/server/report/test.js new file mode 100644 index 00000000..da1ffca5 --- /dev/null +++ b/src/server/report/test.js @@ -0,0 +1,159 @@ +import './test-result.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { FULL_MODE, getId, LAYOUTS } from './common.js'; +import data from './data.js'; + +class Test extends LitElement { + static properties = { + file: { type: String }, + fullMode: { attribute: 'full-mode', type: String }, + layout: { type: String }, + showOverlay: { attribute: 'show-overlay', type: Boolean }, + test: { type: String }, + }; + static styles = [css` + .header { + background-color: #f0f0f0; + border-bottom: 1px solid #e6e6e6; + box-shadow: 0 0 6px rgba(0,0,0,.07); + position: sticky; + top: 0; + z-index: 2; + } + .title h2 { + margin: 0; + } + .settings { + align-items: center; + display: flex; + padding-top: 20px; + gap: 20px; + } + .settings-box { + background-color: #ffffff; + border: 1px solid #cdd5dc; + border-radius: 5px; + line-height: 24px; + padding: 10px; + user-select: none; + } + .header, .results { + padding: 20px; + } + .pill-box { + border-radius: 5px; + display: flex; + flex-wrap: nowrap; + } + .pill input[type="radio"] { + position: absolute; + opacity: 0; + pointer-events: none; + } + .pill label { + align-items: center; + background-color: #ffffff; + border-block-end-style: solid; + border-block-start-style: solid; + border-inline-start-style: solid; + border-color: #cdd5dc; + border-width: 1px; + cursor: pointer; + display: flex; + gap: 5px; + line-height: 24px; + padding: 10px; + position: relative; + user-select: none; + } + .pill:first-child label { + border-start-start-radius: 5px; + border-end-start-radius: 5px; + } + .pill:last-child label { + border-end-end-radius: 5px; + border-inline-end-style: solid; + border-start-end-radius: 5px; + } + .pill input[type="radio"]:checked + label { + background-color: #007bff; + color: white; + } + .pill input[type="radio"]:focus-visible + label { + z-index: 1; + border-color: #007bff; + box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #007bff; + } + `]; + render() { + + const { fileData, testData } = this._fetchData(); + if (!fileData || !testData) return nothing; + + let fullMode = nothing; + if (this.layout === LAYOUTS.FULL.value) { + fullMode = this._renderPillbox('fullMode', this.fullMode, [FULL_MODE.GOLDEN, FULL_MODE.NEW]); + } + + return html` +
+
+

${testData.name}

+
${fileData.name}
+
+
+ ${this._renderPillbox('layout', this.layout, [LAYOUTS.FULL, LAYOUTS.SPLIT])} + + ${fullMode} +
+
+
+ ${testData.results.map(r => html``)} +
+ `; + + } + _fetchData() { + + const fileData = data.files.find(f => f.name === this.file); + if (!fileData) return {}; + + const testData = fileData.tests.find(t => t.name === this.test); + if (!testData) return {}; + + return { fileData, testData }; + + } + _handleOverlayChange(e) { + this._triggerChange('overlay', e.target.checked); + } + _handlePillboxChange(e) { + this._triggerChange(e.target.name, e.target.value); + } + _renderPillbox(name, selectedValue, items) { + const renderItem = (i) => { + const id = getId(); + return html` +
+ + +
+ `; + }; + return html`
${items.map(i => renderItem(i))}
`; + } + _triggerChange(name, value) { + this.dispatchEvent(new CustomEvent( + 'setting-change', { + bubbles: false, + composed: false, + detail: { + name: name, + value: value + } + } + )); + } +} + +customElements.define('d2l-vdiff-report-test', Test);