Reland "[logging] Migrate LogHeader component to lit"
This is a reland of commit 02444cf705ae0783b322cd92ca673815509910ad
Original change's description:
> [logging] Migrate LogHeader component to lit
>
> Change-Id: I3f115afcf2a0954848d646608ae88967b86f6927
> Reviewed-on: https://fuchsia-review.googlesource.com/c/vscode-plugins/+/756083
> Reviewed-by: Miguel Flores <miguelfrde@google.com>
> Kokoro: Kokoro <noreply+kokoro@google.com>
Change-Id: Idc0243ec47c97ac991fabc351f15ca77826c8629
Reviewed-on: https://fuchsia-review.googlesource.com/c/vscode-plugins/+/772342
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Miguel Flores <miguelfrde@google.com>
diff --git a/media/webview-logging.css b/media/webview-logging.css
index 6dd643f..d32bca2 100644
--- a/media/webview-logging.css
+++ b/media/webview-logging.css
@@ -12,7 +12,7 @@
flex-direction: column;
}
-#logs-table-header>div {
+log-header>div {
background-color: var(--vscode-editor-background);
border-bottom: 2px solid var(--vscode-panel-border);
padding-bottom: 5px;
@@ -20,7 +20,7 @@
top: 0;
}
-#logs-table-header,
+log-header,
log-view-row {
display: table-row-group;
}
@@ -34,7 +34,7 @@
}
.log-list-cell,
-#logs-table-header>div {
+log-header>div {
overflow: clip;
text-align: left;
text-overflow: ellipsis;
diff --git a/webviews/logging/components/log_header.ts b/webviews/logging/components/log_header.ts
index df7e9ff..9e66fc3 100644
--- a/webviews/logging/components/log_header.ts
+++ b/webviews/logging/components/log_header.ts
@@ -4,57 +4,69 @@
import * as constant from '../src/constants';
import { State } from '../src/state';
+import {html, LitElement} from 'lit';
+import {customElement} from 'lit/decorators.js';
import { LogField } from '../src/fields';
-export class LogHeader {
- private tableHeader: Element;
+@customElement('log-header')
+export class LogHeader extends LitElement {
private maxWidths = {} as Record<string, number>;
+ private headerKeys: LogField[];
constructor(private state: State) {
+ super();
const fields = this.state.currentFields;
- const keys = Object.keys(fields);
- this.tableHeader = this.initTableHeader();
+ const keys = Object.keys(fields).map(field => field as LogField);
+ this.headerKeys = keys;
for (let i = 0; i < keys.length; i++) {
const header = keys[i] as LogField;
- const headerCell = document.createElement('div');
this.maxWidths[header] = 0;
- headerCell.id = header;
- headerCell.style.width = fields[header].width;
- headerCell.innerText = fields[header].displayName;
- headerCell.ariaLabel = fields[header].displayName;
- headerCell.ariaColIndex = `${i + 1}`;
- this.tableHeader.appendChild(headerCell);
- if (i === keys.length - 1) {
- break;
- }
- const headerDiv = document.createElement('div');
- headerDiv.classList.add('column-resize');
- headerCell.appendChild(headerDiv);
- createResizableColumn(this.state, this.maxWidths, headerCell, headerDiv);
}
}
- /**
- * Returns the core element.
- */
- get element() {
- return this.tableHeader;
+ render() {
+ const fields = this.state.currentFields;
+ return html`
+
+ ${this.headerKeys.map((field, i) => {
+ return html`
+ <div
+ id="${field}"
+ aria-label="${fields[field].displayName}"
+ aria-colindex="${i + 1}"
+ style="width: ${fields[field].width}">
+ ${fields[field].displayName}
+ ${(i !== this.headerKeys.length - 1) ? (html`
+ <div
+ class="column-resize"
+ ></div>
+ `) : ''}
+ </div>
+ `;
+ })}
+ `;
}
- /**
- * Initializes the header element.
- *
- * @return the header element.
- */
- private initTableHeader(): HTMLDivElement {
- const tableHeader = document.createElement('div');
- tableHeader.id = 'logs-table-header';
- return tableHeader;
+ protected createRenderRoot() {
+ return this;
}
public setMaxCellWidth(id: LogField, maxWidth: number): void {
this.maxWidths[id] = maxWidth;
};
+
+ firstUpdated(changedProperties: any) {
+ super.firstUpdated(changedProperties);
+ const resizers = this.querySelectorAll('.column-resize');
+ for (const index in Array.from(resizers)) {
+ const curResizer = resizers[index];
+ createResizableColumn(
+ this.state,
+ this.maxWidths,
+ curResizer.parentElement!,
+ curResizer as HTMLElement);
+ }
+ }
}
/**
diff --git a/webviews/logging/components/log_list.ts b/webviews/logging/components/log_list.ts
index d1712ed..cd2cb89 100644
--- a/webviews/logging/components/log_list.ts
+++ b/webviews/logging/components/log_list.ts
@@ -74,7 +74,7 @@
*/
public reset() {
this.logList.innerHTML = '';
- this.logList.appendChild(this.logHeader.element);
+ this.logList.appendChild(this.logHeader);
this.hasPreviousLog = false;
this.filterResultsCount = 0;
}
@@ -99,7 +99,7 @@
*/
private initLogList(): HTMLDivElement {
let logList = document.createElement('div');
- logList.appendChild(this.logHeader.element);
+ logList.appendChild(this.logHeader);
logList.id = 'log-list';
return logList;
}
@@ -121,7 +121,11 @@
element.setAttribute('hidden', '');
}
this.logList.appendChild(element);
- this.setMaxCellWidth(element);
+ element.updateComplete
+ .then(() => {
+ this.setMaxCellWidth(element.children[0]);
+ })
+ .catch(e => { });
}
private setMaxCellWidth(row: Element) {
diff --git a/webviews/logging/test/log_header.test.ts b/webviews/logging/test/log_header.test.ts
index 80cfe6b..aaf390d 100644
--- a/webviews/logging/test/log_header.test.ts
+++ b/webviews/logging/test/log_header.test.ts
@@ -6,23 +6,27 @@
import * as constant from '../src/constants';
import { State } from '../src/state';
import { LogHeader } from '../components/log_header';
-import { FakeWebviewAPi } from './util';
+import {FakeWebviewAPi} from './util';
+import {LogList} from '../components/log_list';
before(() => {
chai.should();
});
-// TODO(fxbug.dev/110279): re-enable
-describe.skip('LogHeader', () => {
+describe('LogHeader', () => {
let state: State;
let logHeader: LogHeader;
+ let logList: LogList;
let root: HTMLElement;
- beforeEach(() => {
+ beforeEach(async () => {
root = document.createElement('div');
+ document.body.appendChild(root);
state = new State(new FakeWebviewAPi());
- logHeader = new LogHeader(state);
- document.body.appendChild(logHeader.element);
+ logList = new LogList(state);
+ root.appendChild(logList.element);
+ logHeader = logList.element.children[0] as LogHeader;
+ await logHeader.updateComplete;
});
afterEach(() => {
@@ -32,56 +36,54 @@
describe('#constructor', () => {
it('creates header cells for table with resize div', () => {
const headers = Object.keys(constant.LOGS_HEADERS);
- const el = logHeader.element as HTMLElement;
- el.children.length.should.equal(7);
- for (let i = 0; i < el.children.length; i++) {
- el.children[i].id.should.equal(headers[i]);
- if (i === el.children.length - 1) {
- el.children[i].innerHTML.should.equal('');
+ logHeader.children.length.should.equal(7);
+ for (let i = 0; i < logHeader.children.length; i++) {
+ logHeader.children[i].id.should.equal(headers[i]);
+ if (i === logHeader.children.length - 1) {
+ logHeader.children[i].children.length.should.equal(0);
} else {
- el.children[i].innerHTML.should.equal('<div class="column-resize"></div>');
+ logHeader.children[i].children[0].outerHTML.should.equal('<div class="column-resize"></div>');
}
// Check aria label and index.
- el.children[i].should.have.attr('ariaLabel');
- el.children[i].should.have.attr('ariaColIndex');
- el.children[i].ariaColIndex?.should.equal(i + 1);
+ logHeader.children[i].should.have.attr('aria-label');
+ logHeader.children[i].should.have.attr('aria-colindex');
+ logHeader.children[i].ariaColIndex?.should.equal(`${i + 1}`);
}
});
});
describe('on mouse drag', () => {
it('has the resizing class', () => {
- const monikerEl = logHeader.element.children[3] as HTMLElement;
+ const monikerEl = logHeader.children[3] as HTMLElement;
const monikerWidth = state.currentFields['moniker'].width;
-
- window.getComputedStyle(monikerEl).width.should.equal(monikerWidth);
+ monikerEl.style.width.should.equal(monikerWidth);
monikerEl.children[0].classList.contains('resizing').should.equal(false);
monikerEl.children[0].dispatchEvent(new MouseEvent('mousedown'));
monikerEl.children[0].classList.contains('resizing').should.equal(true);
});
it('resizes based on mouse move', () => {
- const monikerEl = logHeader.element.children[3] as HTMLElement;
+ const monikerEl = logHeader.children[3] as HTMLElement;
const monikerWidth = state.currentFields['moniker'].width;
+ const monikerWidthOnPage = monikerEl.clientWidth;
- window.getComputedStyle(monikerEl).width.should.equal(monikerWidth);
+ monikerEl.style.width.should.equal(monikerWidth);
monikerEl.children[0].dispatchEvent(new MouseEvent('mousedown', { clientX: 0 }));
document.dispatchEvent(new MouseEvent('mousemove', { clientX: 20 }));
- window.getComputedStyle(monikerEl).width.should.equal('20px');
+ window.getComputedStyle(monikerEl).width.should.equal(`${monikerWidthOnPage + 20}px`);
});
});
describe('on mouse double click', () => {
it('resizes column to stored size', () => {
- const monikerEl = logHeader.element.children[3] as HTMLElement;
+ const monikerEl = logHeader.children[3] as HTMLElement;
const monikerWidth = state.currentFields['moniker'].width;
const testWidth = 200;
- window.getComputedStyle(monikerEl).width.should.equal(monikerWidth);
+ monikerEl.style.width.should.equal(monikerWidth);
logHeader.setMaxCellWidth('moniker', testWidth);
monikerEl.children[0].dispatchEvent(new MouseEvent('dblclick'));
window.getComputedStyle(monikerEl).width.should.equal(`${testWidth}px`);
});
});
});
-
diff --git a/webviews/logging/test/log_list.test.ts b/webviews/logging/test/log_list.test.ts
index 33f135c..8f439bf 100644
--- a/webviews/logging/test/log_list.test.ts
+++ b/webviews/logging/test/log_list.test.ts
@@ -32,10 +32,12 @@
});
describe('#constructor', () => {
- it('crates a new empty view', () => {
+ it('crates a new empty view', async () => {
const logsList = new LogList(state);
+ root.appendChild(logsList.element);
logsList.element.children.length.should.equal(1);
- logsList.element.children[0].id.should.equal('logs-table-header');
+ await (logsList.element.children[0] as LitElement).updateComplete;
+ logsList.element.children[0].nodeName.should.equal('LOG-HEADER');
logsList.element.should.have.attr('aria-colcount');
const expectedColumns = Object.keys(state.currentFields).length;
logsList.element.getAttribute('aria-colcount')?.should.equal(`${expectedColumns}`);
@@ -59,7 +61,8 @@
document.body.appendChild(logsList);
logsList.children.length.should.equal(1);
- logsList.children[0].id.should.equal('logs-table-header');
+ await (logsList.children[0] as LitElement).updateComplete;
+ logsList.children[0].nodeName.should.equal('LOG-HEADER');
view.addLog(logDataForTest('core/foo'));
logsList.children.length.should.equal(2);
@@ -108,7 +111,8 @@
const logsList = view.element;
document.body.appendChild(logsList);
logsList.children.length.should.equal(2);
- logsList.children[0].id.should.equal('logs-table-header');
+ await (logsList.children[0] as LitElement).updateComplete;
+ logsList.children[0].nodeName.should.equal('LOG-HEADER');
const logLine = logsList.children[1] as LitElement;
await logLine.updateComplete;
@@ -133,7 +137,8 @@
const logsList = view.element;
document.body.appendChild(logsList);
logsList.children.length.should.equal(2);
- logsList.children[0].id.should.equal('logs-table-header');
+ await (logsList.children[0] as LitElement).updateComplete;
+ logsList.children[0].nodeName.should.equal('LOG-HEADER');
const logLine = logsList.children[1] as LitElement;
await logLine.updateComplete;