From eb4463c8ab318e8093e93c1ecaac139cf6dbb74d Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:16:44 -0700 Subject: [PATCH] perf: improve slot UI + device search speedup Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com> --- www/src/ts/virtual_machine/base_device.ts | 5 +- www/src/ts/virtual_machine/device/card.ts | 21 +-- .../ts/virtual_machine/device/device_list.ts | 135 +++++++++++++----- www/src/ts/virtual_machine/device/slot.ts | 61 +++++--- www/src/ts/virtual_machine/device/template.ts | 6 +- 5 files changed, 158 insertions(+), 70 deletions(-) diff --git a/www/src/ts/virtual_machine/base_device.ts b/www/src/ts/virtual_machine/base_device.ts index 3676589..9b4861c 100644 --- a/www/src/ts/virtual_machine/base_device.ts +++ b/www/src/ts/virtual_machine/base_device.ts @@ -183,10 +183,6 @@ export const VMDeviceMixin = >( } } - update(changedProperties: PropertyValueMap | Map): void { - super.update(changedProperties); - this.updateDevice(); - } } return VMDeviceMixinClass as Constructor & T; }; @@ -239,6 +235,7 @@ export const VMDeviceDBMixin = >(superClass: T "vm-device-db-loaded", this._handleDeviceDBLoad.bind(this), ); + this.deviceDB = window.VM.vm.db!; return root; } diff --git a/www/src/ts/virtual_machine/device/card.ts b/www/src/ts/virtual_machine/device/card.ts index b4bd9ef..a936675 100644 --- a/www/src/ts/virtual_machine/device/card.ts +++ b/www/src/ts/virtual_machine/device/card.ts @@ -92,7 +92,7 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { padding: var(--sl-spacing-small) var(--sl-spacing-medium); } sl-tab-group::part(base) { - max-height: 20rem; + max-height: 30rem; overflow-y: auto; } sl-icon-button.remove-button::part(base) { @@ -116,6 +116,11 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { `, ]; + _handleDeviceDBLoad(e: CustomEvent): void { + super._handleDeviceDBLoad(e); + this.updateDevice(); + } + onImageErr(e: Event) { this.image_err = true; console.log("Image load error", e); @@ -137,21 +142,21 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { }, this); return html` -
- Id - + - Name - Hash @@ -192,12 +197,12 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { renderSlots(): HTMLTemplateResult { return html` -
+
${this.slots.map((_slot, index, _slots) => html` ` )} diff --git a/www/src/ts/virtual_machine/device/device_list.ts b/www/src/ts/virtual_machine/device/device_list.ts index ca197f6..a837faf 100644 --- a/www/src/ts/virtual_machine/device/device_list.ts +++ b/www/src/ts/virtual_machine/device/device_list.ts @@ -1,18 +1,17 @@ - import { html, css, HTMLTemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import { BaseElement, defaultCss } from "components"; import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js"; -import { - structuralEqual, -} from "../../utils"; +import { structuralEqual } from "../../utils"; import SlDrawer from "@shoelace-style/shoelace/dist/components/drawer/drawer.js"; import type { DeviceDB, DeviceDBEntry } from "virtual_machine/device_db"; import { repeat } from "lit/directives/repeat.js"; import { cache } from "lit/directives/cache.js"; import { default as uFuzzy } from "@leeoniya/ufuzzy"; +import { when } from "lit/directives/when.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; @customElement("vm-device-list") export class VMDeviceList extends BaseElement { @@ -169,13 +168,7 @@ export class VMAddDeviceButton extends BaseElement { ...defaultCss, css` .add-device-drawer { - --size: 32rem; - } - - .search-results { - display: flex; - flex-direction: row; - overflow-x: auto; + --size: 36rem; } .card { @@ -238,7 +231,11 @@ export class VMAddDeviceButton extends BaseElement { this.performSearch(); } - private _searchResults: DeviceDBEntry[]; + private _searchResults: { + entry: DeviceDBEntry; + haystackEntry: string; + ranges: number[]; + }[]; private filterTimeout: number | undefined; @@ -252,18 +249,30 @@ export class VMAddDeviceButton extends BaseElement { 1e3, ); - const filtered = order?.map( - (infoIdx) => this._datapoints[info.idx[infoIdx]], - ); - const names = - filtered - ?.map((data) => data[1]) - ?.filter((val, index, arr) => arr.indexOf(val) === index) ?? []; + const filtered = order?.map((infoIdx) => ({ + name: this._datapoints[info.idx[infoIdx]][1], + haystackEntry: this._haystack[info.idx[infoIdx]], + ranges: info.ranges[infoIdx], + })); - this._searchResults = names.map((name) => this._strutures.get(name)!); + const unique = [...new Set(filtered.map((obj) => obj.name))].map( + (result) => { + return filtered.find((obj) => obj.name === result); + }, + ); + + this._searchResults = unique.map(({ name, haystackEntry, ranges }) => ({ + entry: this._strutures.get(name)!, + haystackEntry, + ranges, + })); } else { - // clear our results and prefilter if the filter is empty - this._searchResults = []; + // return everything + this._searchResults = [...this._strutures.values()].map((st) => ({ + entry: st, + haystackEntry: st.title, + ranges: [], + })); } } @@ -283,15 +292,55 @@ export class VMAddDeviceButton extends BaseElement { } renderSearchResults() { - return repeat( - this._searchResults ?? [], - (result) => result.name, - (result) => cache(html` - - - `) + return when( + typeof this._searchResults !== "undefined" && this._searchResults.length < 20, + () => + repeat( + this._searchResults ?? [], + (result) => result.entry.name, + (result) => + cache(html` + + + `), + ), + () => html` +
+

+ + results, filter more to get cards +

+
+ ${[ + ...this._searchResults.slice(0, 50), + { entry: { title: "", name: "" }, haystackEntry: "...", ranges: [] }, + ].map((result) => { + const hay = result.haystackEntry.slice(0, 15); + const ranges = result.ranges.filter((pos) => pos < 20); + const key = result.entry.name; + return html`
+ ${result.entry.title} ( + ${unsafeHTML(uFuzzy.highlight(hay, ranges))} + ) +
`; + })} +
+
+ `, ); + } + _handleHaystackClick(e: Event) { + const div = e.currentTarget as HTMLDivElement; + const key = div.getAttribute("key"); + this.filter = key; + this.searchInput.value = key; } _handleDeviceAdd() { @@ -300,20 +349,33 @@ export class VMAddDeviceButton extends BaseElement { render() { return html` - + Add Device - + Search Structures -
${this.renderSearchResults()}
- { - this.drawer.hide(); +
${this.renderSearchResults()}
+ { + this.drawer.hide(); }} - > + > Close
@@ -336,4 +398,3 @@ export class VMAddDeviceButton extends BaseElement { (this.drawer.querySelector(".device-search-input") as SlInput).select(); } } - diff --git a/www/src/ts/virtual_machine/device/slot.ts b/www/src/ts/virtual_machine/device/slot.ts index 6da1394..3373cd6 100644 --- a/www/src/ts/virtual_machine/device/slot.ts +++ b/www/src/ts/virtual_machine/device/slot.ts @@ -2,7 +2,7 @@ import { html, css, HTMLTemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import { BaseElement, defaultCss } from "components"; import { VMDeviceDBMixin, VMDeviceMixin } from "virtual_machine/base_device"; -import type { DeviceDB } from "virtual_machine/device_db"; +import type { DeviceDB, DeviceDBEntry } from "virtual_machine/device_db"; import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js"; import { displayNumber, parseIntWithHexOrBinary, parseNumber } from "utils"; import { @@ -29,11 +29,17 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) { ...defaultCss, css` .slot-card { - --padding: var(--sl-spacing-small); + --padding: var(--sl-spacing-x-small); + } + .slot-card::part(header) { + padding: var(--sl-spacing-x-small); } .slot-card::part(base) { background-color: var(--sl-color-neutral-50); } + .quantity-input sl-input::part(input) { + width: 3rem; + } `, ]; @@ -59,16 +65,26 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) { } } + slotOcccupantTemplate(): { name: string, typ: SlotType} | undefined { + if (this.deviceDB) { + const entry = this.deviceDB.db[this.prefabName] + return entry?.slots[this.slotIndex]; + } else { + return undefined; + } + } + renderHeader() { const inputIdBase = `vmDeviceSlot${this.deviceID}Slot${this.slotIndex}Head`; const slot = this.slots[this.slotIndex]; const slotImg = this.slotOccupantImg(); - const img = html``; + const img = html``; + const template = this.slotOcccupantTemplate(); return html`
- ${slot.occupant.quantity} / ${slot.occupant.max_quantity} + ${slot.occupant.quantity}/${slot.occupant.max_quantity}
` )}
-
+
+
${when( typeof slot.occupant !== "undefined", () => html` - - ${slot.occupant.id} : ${this.slotOccupantPrefabName()} + + ${this.slotOccupantPrefabName()} `, () => html` - - ${slot.typ} + + ${template?.name} `, )} +
+
+
Type:${slot.typ}
+
-
- ${when( - typeof slot.occupant !== "undefined", - () => html` + ${when( + typeof slot.occupant !== "undefined", + () => html` +
- Max Quantity:${slot.occupant.max_quantity} + Max Quantity: ${slot.occupant.max_quantity}
- `, - () => html` - `, - )} -
+
+ `, + () => html` + `, + )}
`; } diff --git a/www/src/ts/virtual_machine/device/template.ts b/www/src/ts/virtual_machine/device/template.ts index ae9358e..d044143 100644 --- a/www/src/ts/virtual_machine/device/template.ts +++ b/www/src/ts/virtual_machine/device/template.ts @@ -47,6 +47,10 @@ export class VmDeviceTemplate extends VMDeviceDBMixin(BaseElement) { // height: 18rem; overflow-y: auto; } + sl-tab-group { + --indicator-color: var(--sl-color-purple-600); + --sl-color-primary-600: var(--sl-color-purple-600); + } sl-tab::part(base) { padding: var(--sl-spacing-small) var(--sl-spacing-medium); } @@ -222,7 +226,7 @@ export class VmDeviceTemplate extends VMDeviceDBMixin(BaseElement) {