more performant search

This commit is contained in:
Rachel Powers
2024-04-17 00:19:01 -07:00
parent 07ff3a167b
commit 7e2ea652c3

View File

@@ -34,7 +34,11 @@ import "@shoelace-style/shoelace/dist/components/drawer/drawer.js";
import "@shoelace-style/shoelace/dist/components/icon/icon.js"; import "@shoelace-style/shoelace/dist/components/icon/icon.js";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js"; import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";
import { parseIntWithHexOrBinary, parseNumber, structuralEqual } from "../utils"; import {
parseIntWithHexOrBinary,
parseNumber,
structuralEqual,
} from "../utils";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.js"; import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.js";
import SlDrawer from "@shoelace-style/shoelace/dist/components/drawer/drawer.js"; import SlDrawer from "@shoelace-style/shoelace/dist/components/drawer/drawer.js";
import { DeviceDB, DeviceDBEntry } from "./device_db"; import { DeviceDB, DeviceDBEntry } from "./device_db";
@@ -78,7 +82,7 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
} }
.device-card{ .device-card {
--padding: var(--sl-spacing-small); --padding: var(--sl-spacing-small);
} }
.device-name::part(input) { .device-name::part(input) {
@@ -134,56 +138,30 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
} }
activeIc?.pins?.forEach((id, index) => { activeIc?.pins?.forEach((id, index) => {
if (this.deviceID == id) { if (this.deviceID == id) {
badges.push(html`<sl-badge variant="success" pill>d${index}</sl-badge>`); badges.push(
html`<sl-badge variant="success" pill>d${index}</sl-badge>`,
);
} }
}, this); }, this);
return html` return html`
<sl-tooltip content="${this.prefabName}"> <sl-tooltip content="${this.prefabName}">
<img <img class="image" src="img/stationpedia/${this.prefabName}.png" @onerr=${this.onImageErr} />
class="image"
src="img/stationpedia/${this.prefabName}.png"
@onerr=${this.onImageErr}
/>
</sl-tooltip> </sl-tooltip>
<div class="header-name"> <div class="header-name">
<sl-input <sl-input id="vmDeviceCard${this.deviceID}Id" class="device-id" size="small" pill value=${this.deviceID}
id="vmDeviceCard${this.deviceID}Id" @sl-change=${this._handleChangeID}>
class="device-id"
size="small"
pill
value=${this.deviceID}
@sl-change=${this._handleChangeID}
>
<span slot="prefix">Id</span> <span slot="prefix">Id</span>
<sl-copy-button slot="suffix" value=${this.deviceID}></sl-copy-button> <sl-copy-button slot="suffix" value=${this.deviceID}></sl-copy-button>
</sl-input> </sl-input>
<sl-input <sl-input id="vmDeviceCard${this.deviceID}Name" class="device-name" size="small" pill placeholder="${this.prefabName}"
id="vmDeviceCard${this.deviceID}Name" @sl-change=${this._handleChangeName}>
class="device-name"
size="small"
pill
placeholder="${this.prefabName}"
@sl-change=${this._handleChangeName}
>
<span slot="prefix">Name</span> <span slot="prefix">Name</span>
<sl-copy-button <sl-copy-button slot="suffix" from="vmDeviceCard${this.deviceID}Name.value"></sl-copy-button>
slot="suffix"
from="vmDeviceCard${this.deviceID}Name.value"
></sl-copy-button>
</sl-input> </sl-input>
<sl-input <sl-input id="vmDeviceCard${this.deviceID}NameHash" size="small" pill class="device-name-hash"
id="vmDeviceCard${this.deviceID}NameHash" value="${this.nameHash}" disabled>
size="small"
pill
class="device-name-hash"
value="${this.nameHash}"
disabled
>
<span slot="prefix">Hash</span> <span slot="prefix">Hash</span>
<sl-copy-button <sl-copy-button slot="suffix" from="vmDeviceCard${this.deviceID}NameHash.value"></sl-copy-button>
slot="suffix"
from="vmDeviceCard${this.deviceID}NameHash.value"
></sl-copy-button>
</sl-input> </sl-input>
${badges.map((badge) => badge)} ${badges.map((badge) => badge)}
</div> </div>
@@ -195,20 +173,12 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
const inputIdBase = `vmDeviceCard${this.deviceID}Field`; const inputIdBase = `vmDeviceCard${this.deviceID}Field`;
return html` return html`
${fields.map(([name, field], _index, _fields) => { ${fields.map(([name, field], _index, _fields) => {
return html` <sl-input return html` <sl-input id="${inputIdBase}${name}" key="${name}" value="${field.value}"
id="${inputIdBase}${name}" ?disabled=${field.field_type==="Read" } @sl-change=${this._handleChangeField}>
key="${name}" <span slot="prefix">${name}</span>
value="${field.value}" <sl-copy-button slot="suffix" from="${inputIdBase}${name}.value"></sl-copy-button>
?disabled=${field.field_type === "Read"} <span slot="suffix">${field.field_type}</span>
@sl-change=${this._handleChangeField} </sl-input>`;
>
<span slot="prefix">${name}</span>
<sl-copy-button
slot="suffix"
from="${inputIdBase}${name}.value"
></sl-copy-button>
<span slot="suffix">${field.field_type}</span>
</sl-input>`;
})} })}
`; `;
} }
@@ -219,28 +189,17 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
const inputIdBase = `vmDeviceCard${this.deviceID}Slot${slotIndex}Field`; const inputIdBase = `vmDeviceCard${this.deviceID}Slot${slotIndex}Field`;
return html` return html`
<sl-card class="slot-card"> <sl-card class="slot-card">
<span slot="header" class="slot-header" <span slot="header" class="slot-header">${slotIndex} : ${slot.typ}</span>
>${slotIndex} : ${slot.typ}</span
>
<div class="slot-fields"> <div class="slot-fields">
${fields.map( ${fields.map(
([name, field], _index, _fields) => html` ([name, field], _index, _fields) => html`
<sl-input <sl-input id="${inputIdBase}${name}" slotIndex=${slotIndex} key="${name}" value="${field.value}"
id="${inputIdBase}${name}" ?disabled=${field.field_type==="Read" } @sl-change=${this._handleChangeSlotField}>
slotIndex=${slotIndex} <span slot="prefix">${name}</span>
key="${name}" <sl-copy-button slot="suffix" from="${inputIdBase}${name}.value"></sl-copy-button>
value="${field.value}" <span slot="suffix">${field.field_type}</span>
?disabled=${field.field_type === "Read"} </sl-input>
@sl-change=${this._handleChangeSlotField} `,
>
<span slot="prefix">${name}</span>
<sl-copy-button
slot="suffix"
from="${inputIdBase}${name}.value"
></sl-copy-button>
<span slot="suffix">${field.field_type}</span>
</sl-input>
`,
)} )}
</div> </div>
</sl-card> </sl-card>
@@ -264,26 +223,19 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
return html` return html`
<div class="networks"> <div class="networks">
${this.connections.map((connection, index, _conns) => { ${this.connections.map((connection, index, _conns) => {
const conn = const conn =
typeof connection === "object" ? connection.CableNetwork : null; typeof connection === "object" ? connection.CableNetwork : null;
return html` return html`
<sl-select <sl-select hoist placement="top" clearable key=${index} value=${conn?.net} ?disabled=${conn===null}
hoist @sl-change=${this._handleChangeConnection}>
placement="top" <span slot="prefix">Connection:${index} </span>
clearable ${vmNetworks.map(
key=${index} (net) =>
value=${conn?.net} html`<sl-option value=${net}>Network ${net}</sl-option>`,
?disabled=${conn === null} )}
@sl-change=${this._handleChangeConnection} <span slot="prefix"> ${conn?.typ} </span>
> </sl-select>
<span slot="prefix">Connection:${index} </span> `;
${vmNetworks.map(
(net) =>
html`<sl-option value=${net}>Network ${net}</sl-option>`,
)}
<span slot="prefix"> ${conn?.typ} </span>
</sl-select>
`;
})} })}
</div> </div>
`; `;
@@ -294,23 +246,16 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
return html` return html`
<div class="pins"> <div class="pins">
${pins?.map( ${pins?.map(
(pin, index) => (pin, index) =>
html`<sl-select html`<sl-select hoist placement="top" clearable key=${index} value=${pin} @sl-change=${this._handleChangePin}>
hoist <span slot="prefix">d${index}</span>
placement="top" ${visibleDevices.map(
clearable (device, _index) =>
key=${index} html`<sl-option value=${device.id}>
value=${pin} Device ${device.id} : ${device.name ?? device.prefabName}
@sl-change=${this._handleChangePin} </sl-option>`,
> )}
<span slot="prefix">d${index}</span> </sl-select>`,
${visibleDevices.map(
(device, _index) =>
html`<sl-option value=${device.id}>
Device ${device.id} : ${device.name ?? device.prefabName}
</sl-option>`,
)}
</sl-select>`,
)} )}
</div> </div>
`; `;
@@ -440,10 +385,7 @@ export class VMDeviceList extends BaseElement {
protected render(): HTMLTemplateResult { protected render(): HTMLTemplateResult {
const deviceCards: HTMLTemplateResult[] = this.devices.map( const deviceCards: HTMLTemplateResult[] = this.devices.map(
(id, _index, _ids) => (id, _index, _ids) =>
html`<vm-device-card html`<vm-device-card .deviceID=${id} class="device-list-card"></vm-device-card>`,
.deviceID=${id}
class="device-list-card"
></vm-device-card>`,
); );
const result = html` const result = html`
<div class="header"> <div class="header">
@@ -489,8 +431,9 @@ export class VMAddDeviceButton extends BaseElement {
@query(".device-search-input") accessor searchInput: SlInput; @query(".device-search-input") accessor searchInput: SlInput;
private _deviceDB: DeviceDB; private _deviceDB: DeviceDB;
private _strutures: Map<string, DeviceDBEntry>; private _strutures: Map<string, DeviceDBEntry> = new Map();
private _datapoints: [string, string][] = [];
private _haystack: string[] = [];
get deviceDB() { get deviceDB() {
return this._deviceDB; return this._deviceDB;
} }
@@ -507,6 +450,18 @@ export class VMAddDeviceButton extends BaseElement {
) )
.map((entry) => [entry.name, entry]), .map((entry) => [entry.name, entry]),
); );
const datapoints: [string, string][] = [];
for (const entry of this._strutures.values()) {
datapoints.push(
[entry.name, entry.name],
[entry.title, entry.name],
[entry.desc, entry.name],
);
}
const haystack: string[] = datapoints.map((data) => data[0]);
this._datapoints = datapoints;
this._haystack = haystack;
this.performSearch(); this.performSearch();
} }
@@ -528,19 +483,17 @@ export class VMAddDeviceButton extends BaseElement {
performSearch() { performSearch() {
if (this.filter) { if (this.filter) {
const datapoints: [string, string][] = [];
for (const entry of this._strutures.values()) {
datapoints.push(
[entry.name, entry.name],
[entry.title, entry.name],
[entry.desc, entry.name],
);
}
const haystack: string[] = datapoints.map((data) => data[0]);
const uf = new uFuzzy({}); const uf = new uFuzzy({});
const [_idxs, info, order] = uf.search(haystack, this._filter, 0, 1e3); const [_idxs, info, order] = uf.search(
this._haystack,
this._filter,
0,
1e3,
);
const filtered = order?.map((infoIdx) => datapoints[info.idx[infoIdx]]); const filtered = order?.map(
(infoIdx) => this._datapoints[info.idx[infoIdx]],
);
const names = const names =
filtered filtered
?.map((data) => data[1]) ?.map((data) => data[1])
@@ -548,8 +501,7 @@ export class VMAddDeviceButton extends BaseElement {
this._searchResults = names.map((name) => this._strutures.get(name)!); this._searchResults = names.map((name) => this._strutures.get(name)!);
} else { } else {
// this._searchResults = // clear our results and prefilter if the filter is empty
// [] ?? this._strutures ? [...this._strutures.values()] : [];
this._searchResults = []; this._searchResults = [];
} }
} }
@@ -569,12 +521,10 @@ export class VMAddDeviceButton extends BaseElement {
renderSearchResults(): HTMLTemplateResult { renderSearchResults(): HTMLTemplateResult {
const renderedResults: HTMLTemplateResult[] = this._searchResults?.map( const renderedResults: HTMLTemplateResult[] = this._searchResults?.map(
(result) => (result) => html`
html`<vm-device-template <vm-device-template prefab_name=${result.name} class="card" @add-device-template=${this._handleDeviceAdd}>
prefab_name=${result.name} </vm-device-template>
class="card" `,
@add-device-template=${this._handleDeviceAdd}
></vm-device-template>`,
); );
return html`${renderedResults}`; return html`${renderedResults}`;
} }
@@ -585,33 +535,20 @@ export class VMAddDeviceButton extends BaseElement {
render() { render() {
return html` return html`
<sl-button <sl-button variant="neutral" outline pill @click=${this._handleAddButtonClick}>
variant="neutral"
outline
p ill
@click=${this._handleAddButtonClick}
>
Add Device Add Device
</sl-button> </sl-button>
<sl-drawer class="add-device-drawer" placement="bottom" no-header> <sl-drawer class="add-device-drawer" placement="bottom" no-header>
<sl-input <sl-input class="device-search-input" autofocus placeholder="Search For Device" clearable
class="device-search-input" @sl-input=${this._handleSearchInput}>
autofocus
placeholder="Search For Device"
clearable
@sl-input=${this._handleSearchInput}
>
<span slot="prefix">Search Structures</span> <span slot="prefix">Search Structures</span>
<sl-icon slot="suffix" name="search"></sl-icon>" <sl-icon slot="suffix" name="search"></sl-icon>"
</sl-input> </sl-input>
<div class="search-results">${this.renderSearchResults()}</div> <div class="search-results">${this.renderSearchResults()}</div>
<sl-button <sl-button slot="footer" variant="primary" @click=${()=> {
slot="footer" this.drawer.hide();
variant="primary"
@click=${() => {
this.drawer.hide();
}} }}
> >
Close Close
</sl-button> </sl-button>
</sl-drawer> </sl-drawer>
@@ -771,17 +708,12 @@ export class VmDeviceTemplate extends BaseElement {
const fields = Object.entries(this.fields); const fields = Object.entries(this.fields);
return html` return html`
${fields.map(([name, field], _index, _fields) => { ${fields.map(([name, field], _index, _fields) => {
return html` return html`
<sl-input <sl-input key="${name}" value="${field.value}" @sl-change=${this._handleChangeField} ?disabled=${name==="PrefabHash" }>
key="${name}" <span slot="prefix">${name}</span>
value="${field.value}" <span slot="suffix">${field.field_type}</span>
@sl-change=${this._handleChangeField} </sl-input>
?disabled=${name === "PrefabHash"} `;
>
<span slot="prefix">${name}</span>
<span slot="suffix">${field.field_type}</span>
</sl-input>
`;
})} })}
`; `;
} }
@@ -815,26 +747,19 @@ export class VmDeviceTemplate extends BaseElement {
return html` return html`
<div class="networks"> <div class="networks">
${connections.map((connection, index, _conns) => { ${connections.map((connection, index, _conns) => {
const conn = const conn =
typeof connection === "object" ? connection.CableNetwork : null; typeof connection === "object" ? connection.CableNetwork : null;
return html` return html`
<sl-select <sl-select hoist placement="top" clearable key=${index} value=${conn?.net} ?disabled=${conn===null}
hoist @sl-change=${this._handleChangeConnection}>
placement="top" <span slot="prefix">Connection:${index} </span>
clearable ${vmNetworks.map(
key=${index} (net) =>
value=${conn?.net} html`<sl-option value=${net}>Network ${net}</sl-option>`,
?disabled=${conn === null} )}
@sl-change=${this._handleChangeConnection} <span slot="prefix"> ${conn?.typ} </span>
> </sl-select>
<span slot="prefix">Connection:${index} </span> `;
${vmNetworks.map(
(net) =>
html`<sl-option value=${net}>Network ${net}</sl-option>`,
)}
<span slot="prefix"> ${conn?.typ} </span>
</sl-select>
`;
})} })}
</div> </div>
`; `;
@@ -859,22 +784,14 @@ export class VmDeviceTemplate extends BaseElement {
<sl-card class="template-card"> <sl-card class="template-card">
<div class="header" slot="header"> <div class="header" slot="header">
<sl-tooltip content="${device?.name}"> <sl-tooltip content="${device?.name}">
<img <img class="image" src="img/stationpedia/${device?.name}.png" @onerr=${this.onImageErr} />
class="image"
src="img/stationpedia/${device?.name}.png"
@onerr=${this.onImageErr}
/>
</sl-tooltip> </sl-tooltip>
<div class="vstack"> <div class="vstack">
<span class="prefab-name">${device?.name}</span> <span class="prefab-name">${device?.name}</span>
<span class="prefab-hash">${device?.hash}</span> <span class="prefab-hash">${device?.hash}</span>
</div> </div>
<sl-button <sl-button class="ms-auto" pill variant="success" @click=${this._handleAddButtonClick}>Add <sl-icon slot="prefix"
class="ms-auto" name="plus-lg"></sl-icon>
pill
variant="success"
@click=${this._handleAddButtonClick}
>Add <sl-icon slot="prefix" name="plus-lg"></sl-icon>
</sl-button> </sl-button>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -887,12 +804,8 @@ export class VmDeviceTemplate extends BaseElement {
<sl-tab-panel name="fields">${this.renderFields()}</sl-tab-panel> <sl-tab-panel name="fields">${this.renderFields()}</sl-tab-panel>
<sl-tab-panel name="slots">${this.renderSlots()}</sl-tab-panel> <sl-tab-panel name="slots">${this.renderSlots()}</sl-tab-panel>
<sl-tab-panel name="reagents" <sl-tab-panel name="reagents">${this.renderReagents()}</sl-tab-panel>
>${this.renderReagents()}</sl-tab-panel <sl-tab-panel name="networks">${this.renderNetworks()}</sl-tab-panel>
>
<sl-tab-panel name="networks"
>${this.renderNetworks()}</sl-tab-panel
>
<sl-tab-panel name="pins">${this.renderPins()}</sl-tab-panel> <sl-tab-panel name="pins">${this.renderPins()}</sl-tab-panel>
</sl-tab-group> </sl-tab-group>
</div> </div>